diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-01-27 15:05:18 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-01-27 15:05:18 +0100 |
| commit | 2036663ed25b5885a87eb3a80caec3fa2e258d77 (patch) | |
| tree | 110ca98e4d76dc887b41c91685bb202c49730236 /src/syntax | |
| parent | 2641c2d20ef5ddaf8e1dc91f4a69abfe2c170e4d (diff) | |
Capture variables in templates 🔍
Diffstat (limited to 'src/syntax')
| -rw-r--r-- | src/syntax/expr.rs | 7 | ||||
| -rw-r--r-- | src/syntax/mod.rs | 1 | ||||
| -rw-r--r-- | src/syntax/visit.rs | 185 |
3 files changed, 193 insertions, 0 deletions
diff --git a/src/syntax/expr.rs b/src/syntax/expr.rs index 15c53cc0..ca55bdd0 100644 --- a/src/syntax/expr.rs +++ b/src/syntax/expr.rs @@ -1,5 +1,6 @@ use super::*; use crate::color::RgbaColor; +use crate::eval::Value; use crate::geom::{AngularUnit, LengthUnit}; /// An expression. @@ -50,6 +51,11 @@ pub enum Expr { If(ExprIf), /// A for expression: `#for x #in y { z }`. For(ExprFor), + /// A captured value. + /// + /// This node is never created by parsing. It only results from an in-place + /// transformation of an identifier to a captured value. + CapturedValue(Value), } impl Pretty for Expr { @@ -86,6 +92,7 @@ impl Pretty for Expr { Self::Let(v) => v.pretty(p), Self::If(v) => v.pretty(p), Self::For(v) => v.pretty(p), + Self::CapturedValue(v) => v.pretty(p), } } } diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index 0b2ac06f..16e691a9 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -5,6 +5,7 @@ mod ident; mod node; mod span; mod token; +pub mod visit; pub use expr::*; pub use ident::*; diff --git a/src/syntax/visit.rs b/src/syntax/visit.rs new file mode 100644 index 00000000..e9e5dad7 --- /dev/null +++ b/src/syntax/visit.rs @@ -0,0 +1,185 @@ +//! Syntax tree traversal. + +use super::*; + +/// Visits syntax tree nodes in a depth-first manner. +pub trait Visitor<'a>: Sized { + /// Visit a variable definition. + fn visit_def(&mut self, _ident: &'a mut Ident) {} + + /// Visit the start of a scope. + fn visit_scope_pre(&mut self) {} + + /// Visit the end of a scope. + fn visit_scope_post(&mut self) {} + + fn visit_node(&mut self, node: &'a mut Node) { + walk_node(self, node) + } + fn visit_expr(&mut self, expr: &'a mut Expr) { + walk_expr(self, expr) + } + fn visit_array(&mut self, array: &'a mut ExprArray) { + walk_array(self, array) + } + fn visit_dict(&mut self, dict: &'a mut ExprDict) { + walk_dict(self, dict) + } + fn visit_template(&mut self, template: &'a mut ExprTemplate) { + walk_template(self, template) + } + fn visit_group(&mut self, group: &'a mut ExprGroup) { + walk_group(self, group) + } + fn visit_block(&mut self, block: &'a mut ExprBlock) { + walk_block(self, block) + } + fn visit_binary(&mut self, binary: &'a mut ExprBinary) { + walk_binary(self, binary) + } + fn visit_unary(&mut self, unary: &'a mut ExprUnary) { + walk_unary(self, unary) + } + fn visit_call(&mut self, call: &'a mut ExprCall) { + walk_call(self, call) + } + fn visit_arg(&mut self, arg: &'a mut Argument) { + walk_arg(self, arg) + } + fn visit_let(&mut self, expr_let: &'a mut ExprLet) { + walk_let(self, expr_let) + } + fn visit_if(&mut self, expr_if: &'a mut ExprIf) { + walk_if(self, expr_if) + } + fn visit_for(&mut self, expr_for: &'a mut ExprFor) { + walk_for(self, expr_for) + } +} + +pub fn walk_node<'a, V: Visitor<'a>>(v: &mut V, node: &'a mut Node) { + match node { + Node::Strong => {} + Node::Emph => {} + Node::Space => {} + Node::Linebreak => {} + Node::Parbreak => {} + Node::Text(_) => {} + Node::Heading(_) => {} + Node::Raw(_) => {} + Node::Expr(expr) => v.visit_expr(expr), + } +} + +pub fn walk_expr<'a, V: Visitor<'a>>(v: &mut V, expr: &'a mut Expr) { + match expr { + Expr::None => {} + Expr::Ident(_) => {} + Expr::Bool(_) => {} + Expr::Int(_) => {} + Expr::Float(_) => {} + Expr::Length(_, _) => {} + Expr::Angle(_, _) => {} + Expr::Percent(_) => {} + Expr::Color(_) => {} + Expr::Str(_) => {} + Expr::Array(e) => v.visit_array(e), + Expr::Dict(e) => v.visit_dict(e), + Expr::Template(e) => v.visit_template(e), + Expr::Group(e) => v.visit_group(e), + Expr::Block(e) => v.visit_block(e), + Expr::Unary(e) => v.visit_unary(e), + Expr::Binary(e) => v.visit_binary(e), + Expr::Call(e) => v.visit_call(e), + Expr::Let(e) => v.visit_let(e), + Expr::If(e) => v.visit_if(e), + Expr::For(e) => v.visit_for(e), + Expr::CapturedValue(_) => {} + } +} + +pub fn walk_array<'a, V: Visitor<'a>>(v: &mut V, array: &'a mut ExprArray) { + for expr in array { + v.visit_expr(&mut expr.v); + } +} + +pub fn walk_dict<'a, V: Visitor<'a>>(v: &mut V, dict: &'a mut ExprDict) { + for named in dict { + v.visit_expr(&mut named.expr.v); + } +} + +pub fn walk_template<'a, V: Visitor<'a>>(v: &mut V, template: &'a mut ExprTemplate) { + v.visit_scope_pre(); + for node in template { + v.visit_node(&mut node.v); + } + v.visit_scope_post(); +} + +pub fn walk_group<'a, V: Visitor<'a>>(v: &mut V, group: &'a mut ExprGroup) { + v.visit_expr(&mut group.v); +} + +pub fn walk_block<'a, V: Visitor<'a>>(v: &mut V, block: &'a mut ExprBlock) { + if block.scopes { + v.visit_scope_pre(); + } + for expr in &mut block.exprs { + v.visit_expr(&mut expr.v); + } + if block.scopes { + v.visit_scope_post(); + } +} + +pub fn walk_binary<'a, V: Visitor<'a>>(v: &mut V, binary: &'a mut ExprBinary) { + v.visit_expr(&mut binary.lhs.v); + v.visit_expr(&mut binary.rhs.v); +} + +pub fn walk_unary<'a, V: Visitor<'a>>(v: &mut V, unary: &'a mut ExprUnary) { + v.visit_expr(&mut unary.expr.v); +} + +pub fn walk_call<'a, V: Visitor<'a>>(v: &mut V, call: &'a mut ExprCall) { + v.visit_expr(&mut call.callee.v); + for arg in &mut call.args.v { + v.visit_arg(arg); + } +} + +pub fn walk_arg<'a, V: Visitor<'a>>(v: &mut V, arg: &'a mut Argument) { + match arg { + Argument::Pos(expr) => v.visit_expr(&mut expr.v), + Argument::Named(named) => v.visit_expr(&mut named.expr.v), + } +} + +pub fn walk_let<'a, V: Visitor<'a>>(v: &mut V, expr_let: &'a mut ExprLet) { + v.visit_def(&mut expr_let.pat.v); + if let Some(init) = &mut expr_let.init { + v.visit_expr(&mut init.v); + } +} + +pub fn walk_if<'a, V: Visitor<'a>>(v: &mut V, expr_if: &'a mut ExprIf) { + v.visit_expr(&mut expr_if.condition.v); + v.visit_expr(&mut expr_if.if_body.v); + if let Some(body) = &mut expr_if.else_body { + v.visit_expr(&mut body.v); + } +} + +pub fn walk_for<'a, V: Visitor<'a>>(v: &mut V, expr_for: &'a mut ExprFor) { + match &mut expr_for.pat.v { + ForPattern::Value(value) => v.visit_def(value), + ForPattern::KeyValue(key, value) => { + v.visit_def(key); + v.visit_def(value); + } + } + v.visit_expr(&mut expr_for.iter.v); + v.visit_expr(&mut expr_for.body.v); +} |
