diff options
Diffstat (limited to 'src/makefile')
-rw-r--r-- | src/makefile/functions.rs | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/src/makefile/functions.rs b/src/makefile/functions.rs index 05f6750..a6a2db1 100644 --- a/src/makefile/functions.rs +++ b/src/makefile/functions.rs @@ -109,6 +109,18 @@ pub fn expand_call( assert!(!args.is_empty()); conditional::and(stack, args.iter(), eval_context) } + "intcmp" => { + assert!(2 <= args.len() && args.len() <= 5); + conditional::intcmp( + stack, + &args[0], + &args[1], + args.get(2), + args.get(3), + args.get(4), + eval_context, + ) + } "foreach" => { assert_eq!(args.len(), 3); @@ -466,7 +478,11 @@ mod file_name { // Functions for Conditionals mod conditional { + use std::borrow::Cow; + use std::cmp::Ordering; + use super::*; + use eyre::eyre; pub fn r#if( stack: &MacroScopeStack, @@ -517,6 +533,51 @@ mod conditional { } Ok(last) } + + pub fn intcmp<'a>( + stack: &MacroScopeStack, + lhs: &TokenString, + rhs: &TokenString, + lt_part: Option<&TokenString>, + eq_part: Option<&TokenString>, + gt_part: Option<&TokenString>, + mut eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, + ) -> Result<String> { + let raw_lhs_value = stack.expand(lhs, eval_context.as_deref_mut())?; + let raw_rhs_value = stack.expand(rhs, eval_context.as_deref_mut())?; + let lhs_value: i64 = raw_lhs_value.parse()?; + let rhs_value: i64 = raw_rhs_value.parse()?; + let cmp = lhs_value.cmp(&rhs_value); + + // defaults are a bit of a mess + let mut lt_part = lt_part.map(Cow::Borrowed); + let mut eq_part = eq_part.map(Cow::Borrowed); + let mut gt_part = gt_part.map(Cow::Borrowed); + if lt_part.is_none() && eq_part.is_none() && gt_part.is_none() { + lt_part = Some(Cow::Owned(TokenString::empty())); + // not just reusing lhs param since expansion could have a side effect + eq_part = Some(Cow::Owned(TokenString::text(raw_lhs_value))); + gt_part = Some(Cow::Owned(TokenString::empty())); + } + if eq_part.is_none() { + eq_part = Some(Cow::Owned(TokenString::empty())); + } + if gt_part.is_none() { + gt_part = eq_part.clone(); + } + + let lt_part = lt_part.ok_or_else(|| eyre!("intcmp defaults failed"))?; + let eq_part = eq_part.ok_or_else(|| eyre!("intcmp defaults failed"))?; + let gt_part = gt_part.ok_or_else(|| eyre!("intcmp defaults failed"))?; + + let result = match cmp { + Ordering::Less => lt_part, + Ordering::Equal => eq_part, + Ordering::Greater => gt_part, + }; + + stack.expand(&result, eval_context.as_deref_mut()) + } } pub fn foreach( @@ -854,6 +915,148 @@ mod test { } #[test] + fn intcmp() -> R { + assert_eq!( + call( + "intcmp", + &[TokenString::text("1"), TokenString::text("2")], + &MacroSet::new() + )?, + "" + ); + assert_eq!( + call( + "intcmp", + &[TokenString::text("2"), TokenString::text("2")], + &MacroSet::new() + )?, + "2" + ); + + assert_eq!( + call( + "intcmp", + &[ + TokenString::text("1"), + TokenString::text("2"), + TokenString::text("a") + ], + &MacroSet::new() + )?, + "a" + ); + assert_eq!( + call( + "intcmp", + &[ + TokenString::text("2"), + TokenString::text("2"), + TokenString::text("a") + ], + &MacroSet::new() + )?, + "" + ); + assert_eq!( + call( + "intcmp", + &[ + TokenString::text("3"), + TokenString::text("2"), + TokenString::text("a") + ], + &MacroSet::new() + )?, + "" + ); + + assert_eq!( + call( + "intcmp", + &[ + TokenString::text("1"), + TokenString::text("2"), + TokenString::text("a"), + TokenString::text("b") + ], + &MacroSet::new() + )?, + "a" + ); + assert_eq!( + call( + "intcmp", + &[ + TokenString::text("2"), + TokenString::text("2"), + TokenString::text("a"), + TokenString::text("b") + ], + &MacroSet::new() + )?, + "b" + ); + assert_eq!( + call( + "intcmp", + &[ + TokenString::text("3"), + TokenString::text("2"), + TokenString::text("a"), + TokenString::text("b") + ], + &MacroSet::new() + )?, + "b" + ); + + assert_eq!( + call( + "intcmp", + &[ + TokenString::text("1"), + TokenString::text("2"), + TokenString::text("a"), + TokenString::text("b"), + TokenString::text("c") + ], + &MacroSet::new() + )?, + "a" + ); + assert_eq!( + call( + "intcmp", + &[ + TokenString::text("2"), + TokenString::text("2"), + TokenString::text("a"), + TokenString::text("b"), + TokenString::text("c") + ], + &MacroSet::new() + )?, + "b" + ); + assert_eq!( + call( + "intcmp", + &[ + TokenString::text("3"), + TokenString::text("2"), + TokenString::text("a"), + TokenString::text("b"), + TokenString::text("c") + ], + &MacroSet::new() + )?, + "c" + ); + + Ok(()) + } + + #[test] fn foreach() -> R { let mut macros = MacroSet::new(); macros.set( |