diff options
author | Melody Horn <melody@boringcactus.com> | 2024-12-16 22:16:20 -0700 |
---|---|---|
committer | Melody Horn <melody@boringcactus.com> | 2024-12-16 22:16:20 -0700 |
commit | 35ebe14f47d692f17ec04b7d94f4ac490b297e3e (patch) | |
tree | 0ff57084631d42a6b6d4bd2934d72321e3ae7374 | |
parent | 46cbd2994ac20b5ee02072cf2fe37f3c68ca934c (diff) | |
download | makers-35ebe14f47d692f17ec04b7d94f4ac490b297e3e.tar.gz makers-35ebe14f47d692f17ec04b7d94f4ac490b297e3e.zip |
add intcmp function
-rw-r--r-- | src/args.rs | 35 | ||||
-rw-r--r-- | src/makefile/functions.rs | 203 |
2 files changed, 220 insertions, 18 deletions
diff --git a/src/args.rs b/src/args.rs index 40f591f..57ac84c 100644 --- a/src/args.rs +++ b/src/args.rs @@ -540,24 +540,23 @@ mod test { #[cfg(feature = "full")] #[test] fn makeflags_no_print_directory() { - let args = - Args { - environment_overrides: false, - makefile: vec![], - ignore_errors: false, - keep_going: false, - dry_run: false, - print_everything: false, - question: false, - no_builtin_rules: false, - no_keep_going: false, - silent: false, - touch: false, - directory: None, - print_directory: false, - no_print_directory: true, - targets_or_macros: vec!["V=1".into()], - }; + let args = Args { + environment_overrides: false, + makefile: vec![], + ignore_errors: false, + keep_going: false, + dry_run: false, + print_everything: false, + question: false, + no_builtin_rules: false, + no_keep_going: false, + silent: false, + touch: false, + directory: None, + print_directory: false, + no_print_directory: true, + targets_or_macros: vec!["V=1".into()], + }; assert_eq!(args.makeflags(), "--no-print-directory V=1"); } } 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( |