Add 'again' macro for recursive expansion
The 'again' macro is a new addition to the macro system, allowing for recursive macro expansion. This commit introduces the necessary AST nodes, macro expansion logic, and an integration test to ensure its functionality. The `soa_series.myc` example has also been updated to demonstrate its usage.
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
(do
|
||||
(repeat n 10 (print n)
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
;; Output: 26.7
|
||||
;; Output: 228
|
||||
;; Benchmark: 1.4us
|
||||
;; Benchmark-Repeat: 1406
|
||||
(do
|
||||
@@ -8,6 +8,8 @@
|
||||
(push my_ticks {:price 11.2 :volume 200 :msg "B"})
|
||||
(push my_ticks {:price 15.5 :volume 300 :msg "C"})
|
||||
|
||||
(repeat n 100 (push my_ticks {:price (+ n 15.5) :volume (ceil (/ n 300)) :msg "??"})
|
||||
)
|
||||
|
||||
(def prices (.price my_ticks))
|
||||
|
||||
|
||||
@@ -275,6 +275,17 @@ impl<E: MacroEvaluator> MacroExpander<E> {
|
||||
})
|
||||
}
|
||||
|
||||
UntypedKind::Again { args } => {
|
||||
let expanded_args = self.expand_recursive(*args)?;
|
||||
Ok(Node {
|
||||
identity: node.identity,
|
||||
kind: UntypedKind::Again {
|
||||
args: Box::new(expanded_args),
|
||||
},
|
||||
ty: (),
|
||||
})
|
||||
}
|
||||
|
||||
_ => Ok(node),
|
||||
}
|
||||
}
|
||||
@@ -536,6 +547,17 @@ impl<E: MacroEvaluator> MacroExpander<E> {
|
||||
})
|
||||
}
|
||||
|
||||
UntypedKind::Again { args } => {
|
||||
let expanded_args = self.expand_template(*args, state)?;
|
||||
Ok(Node {
|
||||
identity: node.identity,
|
||||
kind: UntypedKind::Again {
|
||||
args: Box::new(expanded_args),
|
||||
},
|
||||
ty: (),
|
||||
})
|
||||
}
|
||||
|
||||
_ => Ok(node),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -813,4 +813,20 @@ mod tests {
|
||||
let res = env.run_script(&source_fixed);
|
||||
assert!(res.is_ok(), "Inlining slot clash triggered: {:?}", res.err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_repro_placeholder_in_template_failure() {
|
||||
let env = Environment::new();
|
||||
let source = r#"
|
||||
(do
|
||||
(macro repeat [var limit body]
|
||||
`((fn [~var __limit]
|
||||
(if (< ~var __limit)
|
||||
(do ~body (again (+ ~var 1) __limit))))
|
||||
0 ~limit))
|
||||
(repeat n 10 42))
|
||||
"#;
|
||||
let res = env.run_script(source);
|
||||
assert!(res.is_ok(), "Expansion failed to strip placeholders: {:?}", res.err());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user