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:
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
;; Benchmark: 2.5us
|
;; Benchmark: 2.5us
|
||||||
;; Benchmark-Repeat: 804
|
;; Benchmark-Repeat: 804
|
||||||
;; Output: 120
|
;; Output: 120
|
||||||
(do
|
(do
|
||||||
(def factorial (fn [n acc]
|
(def factorial (fn [n acc]
|
||||||
(if (= n 0)
|
(if (= n 0)
|
||||||
acc
|
acc
|
||||||
(again [(- n 1) (* acc n)]))))
|
(again (- n 1) (* acc n)))))
|
||||||
|
|
||||||
(factorial 5 1))
|
(factorial 5 1))
|
||||||
|
|||||||
@@ -1,21 +1,12 @@
|
|||||||
;; Benchmark: 1.7ms
|
;; Benchmark: 1.7ms
|
||||||
;; Benchmark-Repeat: 3
|
;; Benchmark-Repeat: 3
|
||||||
;; Benchmark: TBD
|
;; Tests the effect of record inlining and field lookup optimization
|
||||||
;; Tests the effect of record inlining and field lookup optimization
|
;; Output: 10000
|
||||||
;; Output: 10000
|
(do
|
||||||
(do
|
(def config {:start 0 :limit 10000 :step 2})
|
||||||
(macro while [cond body]
|
(def x (.start config))
|
||||||
`(do
|
|
||||||
(def _while_loop (fn []
|
(while (< x (.limit config))
|
||||||
(if ~cond
|
(assign x (+ x (.step config))))
|
||||||
(do ~body (_while_loop))
|
x
|
||||||
...)))
|
)
|
||||||
(_while_loop)))
|
|
||||||
|
|
||||||
(def config {:start 0 :limit 10000 :step 2})
|
|
||||||
(def x (.start config))
|
|
||||||
|
|
||||||
(while (< x (.limit config))
|
|
||||||
(assign x (+ x (.step config))))
|
|
||||||
x
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ struct ExpansionState<'a> {
|
|||||||
type MacroMap = HashMap<Rc<str>, (Vec<Rc<str>>, Node<UntypedKind>)>;
|
type MacroMap = HashMap<Rc<str>, (Vec<Rc<str>>, Node<UntypedKind>)>;
|
||||||
|
|
||||||
/// A registry for macro declarations.
|
/// A registry for macro declarations.
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct MacroRegistry {
|
pub struct MacroRegistry {
|
||||||
scopes: Vec<MacroMap>,
|
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> {
|
pub fn expand(&mut self, node: Node<UntypedKind>) -> Result<Node<UntypedKind>, String> {
|
||||||
self.expand_recursive(node)
|
self.expand_recursive(node)
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-1
@@ -32,6 +32,7 @@ pub struct Environment {
|
|||||||
pub monomorph_cache: Rc<RefCell<MonoCache>>,
|
pub monomorph_cache: Rc<RefCell<MonoCache>>,
|
||||||
pub debug_mode: bool,
|
pub debug_mode: bool,
|
||||||
pub optimization: bool,
|
pub optimization: bool,
|
||||||
|
pub macro_registry: Rc<RefCell<MacroRegistry>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EnvFunctionRegistry {
|
struct EnvFunctionRegistry {
|
||||||
@@ -104,6 +105,7 @@ impl Environment {
|
|||||||
monomorph_cache: Rc::new(RefCell::new(HashMap::new())),
|
monomorph_cache: Rc::new(RefCell::new(HashMap::new())),
|
||||||
debug_mode: false,
|
debug_mode: false,
|
||||||
optimization: true,
|
optimization: true,
|
||||||
|
macro_registry: Rc::new(RefCell::new(MacroRegistry::new())),
|
||||||
};
|
};
|
||||||
env.register_stdlib();
|
env.register_stdlib();
|
||||||
env
|
env
|
||||||
@@ -119,7 +121,15 @@ impl Environment {
|
|||||||
global_types: self.global_types.clone(),
|
global_types: self.global_types.clone(),
|
||||||
global_values: self.global_values.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(
|
pub fn register_native(
|
||||||
@@ -174,6 +184,7 @@ impl Environment {
|
|||||||
|
|
||||||
fn register_stdlib(&self) {
|
fn register_stdlib(&self) {
|
||||||
rtl::register(self);
|
rtl::register(self);
|
||||||
|
self.eval_prelude(include_str!("rtl/prelude.myc"));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump_ast(&self, source: &str) -> Result<String, String> {
|
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> {
|
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 {
|
Ok(Node {
|
||||||
identity,
|
identity,
|
||||||
kind: UntypedKind::Again { args },
|
kind: UntypedKind::Again {
|
||||||
|
args: Box::new(args_node),
|
||||||
|
},
|
||||||
ty: (),
|
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.")]
|
#[should_panic(expected = "'again' is only allowed in tail position to avoid dead code.")]
|
||||||
fn test_again_non_tail_panic() {
|
fn test_again_non_tail_panic() {
|
||||||
let env = Environment::new();
|
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
|
// This will trigger the TCO pass which contains the validation logic
|
||||||
let _ = env.run_script(source);
|
let _ = env.run_script(source);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
(while (< 1 2) (print 1))
|
||||||
Reference in New Issue
Block a user