summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-02-07 13:14:28 +0100
committerLaurenz <laurmaedje@gmail.com>2021-02-07 13:14:28 +0100
commitc80e13579f3e6ca8fb1aac5a6d423d902747368d (patch)
treeee62a7b7517acd16e9b2b5133c7ad1bdceff0d3c /src
parentbfc2f5aefc6c407de0b699b31dafd835fc2c9be3 (diff)
Dry-clean visitor with a macro 🏜
Diffstat (limited to 'src')
-rw-r--r--src/eval/capture.rs60
-rw-r--r--src/eval/mod.rs1
-rw-r--r--src/export/pdf.rs10
-rw-r--r--src/library/layout.rs12
-rw-r--r--src/syntax/mod.rs1
-rw-r--r--src/syntax/visit.rs263
6 files changed, 172 insertions, 175 deletions
diff --git a/src/eval/capture.rs b/src/eval/capture.rs
index 054b64ab..42b617a7 100644
--- a/src/eval/capture.rs
+++ b/src/eval/capture.rs
@@ -15,32 +15,60 @@ impl<'a> CapturesVisitor<'a> {
pub fn new(external: &'a Scopes) -> Self {
Self { external, internal: Scopes::default() }
}
+
+ /// Define an internal variable.
+ fn define(&mut self, ident: &Ident) {
+ self.internal.def_mut(ident.as_str(), Value::None);
+ }
}
-impl<'a> Visitor<'a> for CapturesVisitor<'a> {
- fn visit_scope_pre(&mut self) {
- self.internal.push();
+impl<'ast> Visit<'ast> for CapturesVisitor<'_> {
+ fn visit_expr(&mut self, item: &'ast mut Expr) {
+ match item {
+ Expr::Ident(ident) => {
+ // Find out whether the identifier is not locally defined, but
+ // captured, and if so, replace it with its value.
+ if self.internal.get(ident).is_none() {
+ if let Some(value) = self.external.get(ident) {
+ *item = Expr::Captured(Rc::clone(&value));
+ }
+ }
+ }
+ expr => visit_expr(self, expr),
+ }
}
- fn visit_scope_post(&mut self) {
+ fn visit_block(&mut self, item: &'ast mut ExprBlock) {
+ // Blocks create a scope except if directly in a template.
+ if item.scopes {
+ self.internal.push();
+ }
+ visit_block(self, item);
+ if item.scopes {
+ self.internal.pop();
+ }
+ }
+
+ fn visit_template(&mut self, item: &'ast mut ExprTemplate) {
+ // Templates always create a scope.
+ self.internal.push();
+ visit_template(self, item);
self.internal.pop();
}
- fn visit_def(&mut self, id: &mut Ident) {
- self.internal.def_mut(id.as_str(), Value::None);
+ fn visit_let(&mut self, item: &'ast mut ExprLet) {
+ self.define(&item.pat.v);
+ visit_let(self, item);
}
- fn visit_expr(&mut self, expr: &'a mut Expr) {
- if let Expr::Ident(ident) = expr {
- // Find out whether the identifier is not locally defined, but
- // captured, and if so, replace it with its value.
- if self.internal.get(ident).is_none() {
- if let Some(value) = self.external.get(ident) {
- *expr = Expr::Captured(Rc::clone(&value));
- }
+ fn visit_for(&mut self, item: &'ast mut ExprFor) {
+ match &mut item.pat.v {
+ ForPattern::Value(value) => self.define(value),
+ ForPattern::KeyValue(key, value) => {
+ self.define(key);
+ self.define(value);
}
- } else {
- walk_expr(self, expr);
}
+ visit_for(self, item);
}
}
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index 4f8961cc..cfd1c808 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -23,6 +23,7 @@ use crate::diag::Pass;
use crate::env::Env;
use crate::geom::{Angle, Length, Relative, Spec};
use crate::layout::{self, Expansion, NodeSpacing, NodeStack};
+use crate::syntax::visit::Visit;
use crate::syntax::*;
/// Evaluate a syntax tree into a layout tree.
diff --git a/src/export/pdf.rs b/src/export/pdf.rs
index e5124c21..b2a6bbfd 100644
--- a/src/export/pdf.rs
+++ b/src/export/pdf.rs
@@ -130,11 +130,11 @@ impl<'a> PdfExporter<'a> {
let mut content = Content::new();
for (pos, element) in &page.elements {
+ let x = pos.x.to_pt() as f32;
match element {
Element::Image(image) => {
let name = format!("Im{}", self.images.map(image.res));
let size = image.size;
- let x = pos.x.to_pt() as f32;
let y = (page.size.height - pos.y - size.height).to_pt() as f32;
let w = size.width.to_pt() as f32;
let h = size.height.to_pt() as f32;
@@ -151,16 +151,14 @@ impl<'a> PdfExporter<'a> {
match geometry.fill {
Fill::Color(Color::Rgba(c)) => {
content.fill_rgb(
- c.r as f32 / 255.,
- c.g as f32 / 255.,
- c.b as f32 / 255.,
+ c.r as f32 / 255.0,
+ c.g as f32 / 255.0,
+ c.b as f32 / 255.0,
);
}
Fill::Image(_) => todo!(),
}
- let x = pos.x.to_pt() as f32;
-
match &geometry.shape {
Shape::Rect(r) => {
let w = r.width.to_pt() as f32;
diff --git a/src/library/layout.rs b/src/library/layout.rs
index 2812a48f..e4839953 100644
--- a/src/library/layout.rs
+++ b/src/library/layout.rs
@@ -175,7 +175,16 @@ impl Display for Alignment {
/// # Named arguments
/// - Width of the box: `width`, of type `linear` relative to parent width.
/// - Height of the box: `height`, of type `linear` relative to parent height.
+/// - Main layouting direction: `main-dir`, of type `direction`.
+/// - Cross layouting direction: `cross-dir`, of type `direction`.
/// - Background color of the box: `color`, of type `color`.
+///
+/// # Relevant types and constants
+/// - Type `direction`
+/// - `ltr` (left to right)
+/// - `rtl` (right to left)
+/// - `ttb` (top to bottom)
+/// - `btt` (bottom to top)
pub fn box_(ctx: &mut EvalContext, args: &mut Args) -> Value {
let snapshot = ctx.state.clone();
@@ -210,13 +219,12 @@ pub fn box_(ctx: &mut EvalContext, args: &mut Args) -> Value {
if let Some(color) = color {
ctx.push(NodeBackground {
fill: Fill::Color(color),
- child: Node::Any(fixed_node.into()),
+ child: fixed_node.into(),
})
} else {
ctx.push(fixed_node);
}
-
ctx.state = snapshot;
Value::None
}
diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs
index af6715c6..8bb6931a 100644
--- a/src/syntax/mod.rs
+++ b/src/syntax/mod.rs
@@ -12,7 +12,6 @@ pub use ident::*;
pub use node::*;
pub use span::*;
pub use token::*;
-pub use visit::Visitor;
use crate::pretty::{Pretty, Printer};
diff --git a/src/syntax/visit.rs b/src/syntax/visit.rs
index 6f0e7ef3..2e4391ac 100644
--- a/src/syntax/visit.rs
+++ b/src/syntax/visit.rs
@@ -2,184 +2,147 @@
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) {}
+macro_rules! visit {
+ ($(fn $name:ident($v:ident, $item:ident: &mut $ty:ty) $body:block)*) => {
+ /// Traverses the syntax tree.
+ pub trait Visit<'ast> {
+ $(fn $name(&mut self, $item: &'ast mut $ty) {
+ $name(self, $item);
+ })*
+ }
- 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)
+ $(visit! {
+ @concat!("Walk a node of type [`", stringify!($ty), "`]."),
+ pub fn $name<'ast, V>($v: &mut V, $item: &'ast mut $ty)
+ where
+ V: Visit<'ast> + ?Sized
+ $body
+ })*
+ };
+ (@$doc:expr, $($tts:tt)*) => {
+ #[doc = $doc]
+ $($tts)*
}
- 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::Captured(_) => {}
+visit! {
+ fn visit_tree(v, item: &mut Tree) {
+ for node in item {
+ v.visit_node(&mut node.v);
+ }
}
-}
-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);
+ fn visit_node(v, item: &mut Node) {
+ match item {
+ Node::Strong => {}
+ Node::Emph => {}
+ Node::Space => {}
+ Node::Linebreak => {}
+ Node::Parbreak => {}
+ Node::Text(_) => {}
+ Node::Heading(n) => v.visit_tree(&mut n.contents),
+ Node::Raw(_) => {}
+ Node::Expr(expr) => v.visit_expr(expr),
+ }
}
-}
-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);
+ fn visit_expr(v, item: &mut Expr) {
+ match item {
+ 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::Captured(_) => {}
+ }
}
-}
-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);
+ fn visit_array(v, item: &mut ExprArray) {
+ for expr in item {
+ v.visit_expr(&mut expr.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);
-}
+ fn visit_dict(v, item: &mut ExprDict) {
+ for named in item {
+ v.visit_expr(&mut named.expr.v);
+ }
+ }
-pub fn walk_block<'a, V: Visitor<'a>>(v: &mut V, block: &'a mut ExprBlock) {
- if block.scopes {
- v.visit_scope_pre();
+ fn visit_template(v, item: &mut ExprTemplate) {
+ v.visit_tree(item);
}
- for expr in &mut block.exprs {
- v.visit_expr(&mut expr.v);
+
+ fn visit_group(v, item: &mut ExprGroup) {
+ v.visit_expr(&mut item.v);
}
- if block.scopes {
- v.visit_scope_post();
+
+ fn visit_block(v, item: &mut ExprBlock) {
+ for expr in &mut item.exprs {
+ v.visit_expr(&mut expr.v);
+ }
}
-}
-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);
-}
+ fn visit_binary(v, item: &mut ExprBinary) {
+ v.visit_expr(&mut item.lhs.v);
+ v.visit_expr(&mut item.rhs.v);
+ }
-pub fn walk_unary<'a, V: Visitor<'a>>(v: &mut V, unary: &'a mut ExprUnary) {
- v.visit_expr(&mut unary.expr.v);
-}
+ fn visit_unary(v, item: &mut ExprUnary) {
+ v.visit_expr(&mut item.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);
+ fn visit_call(v, item: &mut ExprCall) {
+ v.visit_expr(&mut item.callee.v);
+ v.visit_args(&mut item.args.v);
}
-}
-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),
+ fn visit_args(v, item: &mut ExprArgs) {
+ for arg in item {
+ v.visit_arg(arg);
+ }
}
-}
-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);
+ fn visit_arg(v, item: &mut Argument) {
+ match item {
+ Argument::Pos(expr) => v.visit_expr(&mut expr.v),
+ Argument::Named(named) => v.visit_expr(&mut named.expr.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);
+ fn visit_let(v, item: &mut ExprLet) {
+ if let Some(init) = &mut item.init {
+ v.visit_expr(&mut init.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);
+ fn visit_if(v, item: &mut ExprIf) {
+ v.visit_expr(&mut item.condition.v);
+ v.visit_expr(&mut item.if_body.v);
+ if let Some(body) = &mut item.else_body {
+ v.visit_expr(&mut body.v);
}
}
- v.visit_expr(&mut expr_for.iter.v);
- v.visit_expr(&mut expr_for.body.v);
+
+ fn visit_for(v, item: &mut ExprFor) {
+ v.visit_expr(&mut item.iter.v);
+ v.visit_expr(&mut item.body.v);
+ }
}