feat: Implement AST macros and templates
This commit introduces support for AST macros and templates, enabling users to define and use custom, reusable components within the visual DSL. Key changes include: - A new `MacroRegistry` to manage macro definitions. - A `MacroExpander` to process macro calls and expand templates. - A `MacroEvaluator` trait for evaluating expressions during expansion. - The `Expansion` node in `BoundKind` to preserve the original macro call and its expanded form for debugging. - Updates to the `Binder`, `Dumper`, and `UpvalueAnalyzer` to handle the new macro constructs. - New examples demonstrating various macro functionalities like `unless`, splicing, and nested macros.
This commit is contained in:
+47
-1
@@ -25,12 +25,14 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
pub fn parse_expression(&mut self) -> Result<Node<UntypedKind>, String> {
|
||||
let token_loc = self.current_token.location;
|
||||
let identity = Rc::new(NodeIdentity { location: token_loc });
|
||||
|
||||
match self.peek() {
|
||||
TokenKind::LeftParen => self.parse_list(),
|
||||
TokenKind::LeftBracket => self.parse_vector_literal(),
|
||||
TokenKind::LeftBrace => self.parse_map_literal(),
|
||||
TokenKind::Quote => {
|
||||
let identity = Rc::new(NodeIdentity { location: self.current_token.location });
|
||||
self.advance()?; // consume '
|
||||
let expr = self.parse_expression()?;
|
||||
Ok(Node {
|
||||
@@ -42,6 +44,34 @@ impl<'a> Parser<'a> {
|
||||
ty: (),
|
||||
})
|
||||
}
|
||||
TokenKind::Backtick => {
|
||||
self.advance()?; // consume `
|
||||
let expr = self.parse_expression()?;
|
||||
Ok(Node {
|
||||
identity,
|
||||
kind: UntypedKind::Template(Box::new(expr)),
|
||||
ty: (),
|
||||
})
|
||||
}
|
||||
TokenKind::Tilde => {
|
||||
self.advance()?; // consume ~
|
||||
if *self.peek() == TokenKind::At {
|
||||
self.advance()?; // consume @
|
||||
let expr = self.parse_expression()?;
|
||||
Ok(Node {
|
||||
identity,
|
||||
kind: UntypedKind::Splice(Box::new(expr)),
|
||||
ty: (),
|
||||
})
|
||||
} else {
|
||||
let expr = self.parse_expression()?;
|
||||
Ok(Node {
|
||||
identity,
|
||||
kind: UntypedKind::Placeholder(Box::new(expr)),
|
||||
ty: (),
|
||||
})
|
||||
}
|
||||
}
|
||||
_ => self.parse_atom(),
|
||||
}
|
||||
}
|
||||
@@ -91,6 +121,7 @@ impl<'a> Parser<'a> {
|
||||
"def" => self.parse_def(identity),
|
||||
"assign" => self.parse_assign(identity),
|
||||
"do" => self.parse_do(identity),
|
||||
"macro" => self.parse_macro_decl(identity),
|
||||
_ => self.parse_call(head, identity),
|
||||
}
|
||||
} else {
|
||||
@@ -171,6 +202,21 @@ impl<'a> Parser<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_macro_decl(&mut self, identity: Identity) -> Result<Node<UntypedKind>, String> {
|
||||
let name_node = self.parse_expression()?;
|
||||
let name = match name_node.kind {
|
||||
UntypedKind::Identifier(s) => s,
|
||||
_ => return Err("Expected identifier for macro name".to_string()),
|
||||
};
|
||||
let params = self.parse_param_vector()?;
|
||||
let body = self.parse_expression()?;
|
||||
Ok(Node {
|
||||
identity,
|
||||
kind: UntypedKind::MacroDecl { name, params, body: Box::new(body) },
|
||||
ty: (),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_param_vector(&mut self) -> Result<Vec<Rc<str>>, String> {
|
||||
if *self.peek() != TokenKind::LeftBracket {
|
||||
return Err(format!("Expected parameter vector [...] for fn, found {:?}", self.peek()));
|
||||
|
||||
Reference in New Issue
Block a user