aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2024-12-16 22:16:20 -0700
committerMelody Horn <melody@boringcactus.com>2024-12-16 22:16:20 -0700
commit35ebe14f47d692f17ec04b7d94f4ac490b297e3e (patch)
tree0ff57084631d42a6b6d4bd2934d72321e3ae7374
parent46cbd2994ac20b5ee02072cf2fe37f3c68ca934c (diff)
downloadmakers-35ebe14f47d692f17ec04b7d94f4ac490b297e3e.tar.gz
makers-35ebe14f47d692f17ec04b7d94f4ac490b297e3e.zip
add intcmp function
-rw-r--r--src/args.rs35
-rw-r--r--src/makefile/functions.rs203
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(