Add prelude and while macro
This commit introduces a new prelude file that defines the `while` macro and registers it during environment bootstrapping. The `again` macro has been updated to accept multiple arguments for its recursive call, and several examples have been adjusted to reflect this change. Additionally, the `MacroRegistry` in the compiler is now cloneable and can be moved out of the `MacroExpander`.
This commit is contained in:
+1
-1
@@ -5,6 +5,6 @@
|
||||
(def factorial (fn [n acc]
|
||||
(if (= n 0)
|
||||
acc
|
||||
(again [(- n 1) (* acc n)]))))
|
||||
(again (- n 1) (* acc n)))))
|
||||
|
||||
(factorial 5 1))
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
;; Benchmark: 1.7ms
|
||||
;; Benchmark-Repeat: 3
|
||||
;; Benchmark: TBD
|
||||
;; Tests the effect of record inlining and field lookup optimization
|
||||
;; Output: 10000
|
||||
(do
|
||||
(macro while [cond body]
|
||||
`(do
|
||||
(def _while_loop (fn []
|
||||
(if ~cond
|
||||
(do ~body (_while_loop))
|
||||
...)))
|
||||
(_while_loop)))
|
||||
|
||||
(def config {:start 0 :limit 10000 :step 2})
|
||||
(def x (.start config))
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ struct ExpansionState<'a> {
|
||||
type MacroMap = HashMap<Rc<str>, (Vec<Rc<str>>, Node<UntypedKind>)>;
|
||||
|
||||
/// A registry for macro declarations.
|
||||
#[derive(Clone)]
|
||||
pub struct MacroRegistry {
|
||||
scopes: Vec<MacroMap>,
|
||||
}
|
||||
@@ -78,6 +79,10 @@ impl<E: MacroEvaluator> MacroExpander<E> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_registry(self) -> MacroRegistry {
|
||||
self.registry
|
||||
}
|
||||
|
||||
pub fn expand(&mut self, node: Node<UntypedKind>) -> Result<Node<UntypedKind>, String> {
|
||||
self.expand_recursive(node)
|
||||
}
|
||||
|
||||
+12
-1
@@ -32,6 +32,7 @@ pub struct Environment {
|
||||
pub monomorph_cache: Rc<RefCell<MonoCache>>,
|
||||
pub debug_mode: bool,
|
||||
pub optimization: bool,
|
||||
pub macro_registry: Rc<RefCell<MacroRegistry>>,
|
||||
}
|
||||
|
||||
struct EnvFunctionRegistry {
|
||||
@@ -104,6 +105,7 @@ impl Environment {
|
||||
monomorph_cache: Rc::new(RefCell::new(HashMap::new())),
|
||||
debug_mode: false,
|
||||
optimization: true,
|
||||
macro_registry: Rc::new(RefCell::new(MacroRegistry::new())),
|
||||
};
|
||||
env.register_stdlib();
|
||||
env
|
||||
@@ -119,7 +121,15 @@ impl Environment {
|
||||
global_types: self.global_types.clone(),
|
||||
global_values: self.global_values.clone(),
|
||||
};
|
||||
MacroExpander::new(MacroRegistry::new(), evaluator)
|
||||
MacroExpander::new(self.macro_registry.borrow().clone(), evaluator)
|
||||
}
|
||||
|
||||
fn eval_prelude(&self, source: &str) {
|
||||
let mut parser = crate::ast::parser::Parser::new(source).expect("Failed to parse prelude");
|
||||
let untyped_ast = parser.parse_expression().expect("Failed to parse prelude expression");
|
||||
let mut expander = self.get_expander();
|
||||
let _ = expander.expand(untyped_ast).expect("Failed to expand prelude");
|
||||
*self.macro_registry.borrow_mut() = expander.into_registry();
|
||||
}
|
||||
|
||||
pub fn register_native(
|
||||
@@ -174,6 +184,7 @@ impl Environment {
|
||||
|
||||
fn register_stdlib(&self) {
|
||||
rtl::register(self);
|
||||
self.eval_prelude(include_str!("rtl/prelude.myc"));
|
||||
}
|
||||
|
||||
pub fn dump_ast(&self, source: &str) -> Result<String, String> {
|
||||
|
||||
+15
-2
@@ -153,10 +153,23 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
fn parse_again(&mut self, identity: Identity) -> Result<Node<UntypedKind>, String> {
|
||||
let args = Box::new(self.parse_expression()?);
|
||||
let mut elements = Vec::new();
|
||||
|
||||
while *self.peek() != TokenKind::RightParen && *self.peek() != TokenKind::EOF {
|
||||
elements.push(self.parse_expression()?);
|
||||
}
|
||||
|
||||
let args_node = Node {
|
||||
identity: identity.clone(),
|
||||
kind: UntypedKind::Tuple { elements },
|
||||
ty: (),
|
||||
};
|
||||
|
||||
Ok(Node {
|
||||
identity,
|
||||
kind: UntypedKind::Again { args },
|
||||
kind: UntypedKind::Again {
|
||||
args: Box::new(args_node),
|
||||
},
|
||||
ty: (),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
;; Myc Prelude
|
||||
;; This file is evaluated during Environment bootstrapping.
|
||||
;; It contains standard macros and functions.
|
||||
|
||||
(macro while [cond body]
|
||||
`((fn [] (if ~cond
|
||||
(do ~body (again))
|
||||
)))
|
||||
)
|
||||
@@ -267,7 +267,7 @@ mod tests {
|
||||
#[should_panic(expected = "'again' is only allowed in tail position to avoid dead code.")]
|
||||
fn test_again_non_tail_panic() {
|
||||
let env = Environment::new();
|
||||
let source = "(do (def f (fn [x] (do (again [(- x 1)]) x))) (f 5))";
|
||||
let source = "(do (def f (fn [x] (do (again (- x 1)) x))) (f 5))";
|
||||
// This will trigger the TCO pass which contains the validation logic
|
||||
let _ = env.run_script(source);
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
(while (< 1 2) (print 1))
|
||||
Reference in New Issue
Block a user