diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-03-21 17:46:09 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-03-21 17:50:56 +0100 |
| commit | 5e08028fb36aa766957cba64c5c665edf9b96fb7 (patch) | |
| tree | 912799dad3c1e25b7032f3e3bee009537c6f555b /src/eval | |
| parent | 898728f260923a91444eb23b522d0abf01a4299b (diff) | |
Syntax functions 🚀
This adds overridable functions that markup desugars into. Specifically:
- \ desugars into linebreak
- Two newlines desugar into parbreak
- * desugars into strong
- _ desugars into emph
- = .. desugars into heading
- `..` desugars into raw
Diffstat (limited to 'src/eval')
| -rw-r--r-- | src/eval/capture.rs | 36 | ||||
| -rw-r--r-- | src/eval/mod.rs | 99 | ||||
| -rw-r--r-- | src/eval/ops.rs | 2 | ||||
| -rw-r--r-- | src/eval/value.rs | 13 |
4 files changed, 81 insertions, 69 deletions
diff --git a/src/eval/capture.rs b/src/eval/capture.rs index c0354cd3..bee523ef 100644 --- a/src/eval/capture.rs +++ b/src/eval/capture.rs @@ -2,7 +2,7 @@ use std::rc::Rc; use super::{Scope, Scopes, Value}; use crate::syntax::visit::{visit_expr, Visit}; -use crate::syntax::{Expr, Ident}; +use crate::syntax::{Expr, Ident, Node}; /// A visitor that captures variable slots. #[derive(Debug)] @@ -26,20 +26,36 @@ impl<'a> CapturesVisitor<'a> { pub fn finish(self) -> Scope { self.captures } + + /// Find out whether the name is not locally defined and if so if it can be + /// captured. + fn process(&mut self, name: &str) { + if self.internal.get(name).is_none() { + if let Some(slot) = self.external.get(name) { + self.captures.def_slot(name, Rc::clone(slot)); + } + } + } } impl<'ast> Visit<'ast> for CapturesVisitor<'_> { + fn visit_node(&mut self, node: &'ast Node) { + match node { + Node::Text(_) => {} + Node::Space => {} + Node::Linebreak(_) => self.process(Node::LINEBREAK), + Node::Parbreak(_) => self.process(Node::PARBREAK), + Node::Strong(_) => self.process(Node::STRONG), + Node::Emph(_) => self.process(Node::EMPH), + Node::Heading(_) => self.process(Node::HEADING), + Node::Raw(_) => self.process(Node::RAW), + Node::Expr(expr) => self.visit_expr(expr), + } + } + fn visit_expr(&mut self, node: &'ast Expr) { match node { - Expr::Ident(ident) => { - // Find out whether the identifier is not locally defined, but - // captured, and if so, capture its value. - if self.internal.get(ident).is_none() { - if let Some(slot) = self.external.get(ident) { - self.captures.def_slot(ident.as_str(), Rc::clone(slot)); - } - } - } + Expr::Ident(ident) => self.process(ident), expr => visit_expr(self, expr), } } diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 6d8edf79..802e1347 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -20,23 +20,23 @@ use crate::geom::{Angle, Length, Relative}; use crate::syntax::visit::Visit; use crate::syntax::*; -/// Evaluate all expressions in a syntax tree. +/// Evaluate all nodes in a syntax tree. /// /// The `scope` consists of the base definitions that are present from the /// beginning (typically, the standard library). -pub fn eval(env: &mut Env, tree: &Tree, scope: &Scope) -> Pass<ExprMap> { +pub fn eval(env: &mut Env, tree: &Tree, scope: &Scope) -> Pass<NodeMap> { let mut ctx = EvalContext::new(env, scope); let map = tree.eval(&mut ctx); Pass::new(map, ctx.diags) } -/// A map from expressions to the values they evaluated to. +/// A map from nodes to the values they evaluated to. /// -/// The raw pointers point into the expressions contained in some [`Tree`]. -/// Since the lifetime is erased, the tree could go out of scope while the hash -/// map still lives. Although this could lead to lookup panics, it is not unsafe -/// since the pointers are never dereferenced. -pub type ExprMap = HashMap<*const Expr, Value>; +/// The raw pointers point into the nodes contained in some [`Tree`]. Since the +/// lifetime is erased, the tree could go out of scope while the hash map still +/// lives. Although this could lead to lookup panics, it is not unsafe since the +/// pointers are never dereferenced. +pub type NodeMap = HashMap<*const Node, Value>; /// The context for evaluation. #[derive(Debug)] @@ -75,23 +75,24 @@ pub trait Eval { } impl Eval for Tree { - type Output = ExprMap; + type Output = NodeMap; fn eval(&self, ctx: &mut EvalContext) -> Self::Output { - struct ExprVisitor<'a, 'b> { - map: ExprMap, - ctx: &'a mut EvalContext<'b>, - } + let mut map = NodeMap::new(); - impl<'ast> Visit<'ast> for ExprVisitor<'_, '_> { - fn visit_expr(&mut self, node: &'ast Expr) { - self.map.insert(node as *const _, node.eval(self.ctx)); - } + for node in self { + let value = if let Some(call) = node.desugar() { + call.eval(ctx) + } else if let Node::Expr(expr) = node { + expr.eval(ctx) + } else { + continue; + }; + + map.insert(node as *const _, value); } - let mut visitor = ExprVisitor { map: ExprMap::new(), ctx }; - visitor.visit_tree(self); - visitor.map + map } } @@ -99,46 +100,36 @@ impl Eval for Expr { type Output = Value; fn eval(&self, ctx: &mut EvalContext) -> Self::Output { - match self { - Self::Lit(lit) => lit.eval(ctx), - Self::Ident(v) => match ctx.scopes.get(&v) { + match *self { + Self::None(_) => Value::None, + Self::Bool(_, v) => Value::Bool(v), + Self::Int(_, v) => Value::Int(v), + Self::Float(_, v) => Value::Float(v), + Self::Length(_, v, unit) => Value::Length(Length::with_unit(v, unit)), + Self::Angle(_, v, unit) => Value::Angle(Angle::with_unit(v, unit)), + Self::Percent(_, v) => Value::Relative(Relative::new(v / 100.0)), + Self::Color(_, v) => Value::Color(Color::Rgba(v)), + Self::Str(_, ref v) => Value::Str(v.clone()), + Self::Ident(ref v) => match ctx.scopes.get(&v) { Some(slot) => slot.borrow().clone(), None => { ctx.diag(error!(v.span, "unknown variable")); Value::Error } }, - Self::Array(v) => Value::Array(v.eval(ctx)), - Self::Dict(v) => Value::Dict(v.eval(ctx)), - Self::Template(v) => Value::Template(vec![v.eval(ctx)]), - Self::Group(v) => v.eval(ctx), - Self::Block(v) => v.eval(ctx), - Self::Call(v) => v.eval(ctx), - Self::Closure(v) => v.eval(ctx), - Self::Unary(v) => v.eval(ctx), - Self::Binary(v) => v.eval(ctx), - Self::Let(v) => v.eval(ctx), - Self::If(v) => v.eval(ctx), - Self::While(v) => v.eval(ctx), - Self::For(v) => v.eval(ctx), - } - } -} - -impl Eval for Lit { - type Output = Value; - - fn eval(&self, _: &mut EvalContext) -> Self::Output { - match self.kind { - LitKind::None => Value::None, - LitKind::Bool(v) => Value::Bool(v), - LitKind::Int(v) => Value::Int(v), - LitKind::Float(v) => Value::Float(v), - LitKind::Length(v, unit) => Value::Length(Length::with_unit(v, unit)), - LitKind::Angle(v, unit) => Value::Angle(Angle::with_unit(v, unit)), - LitKind::Percent(v) => Value::Relative(Relative::new(v / 100.0)), - LitKind::Color(v) => Value::Color(Color::Rgba(v)), - LitKind::Str(ref v) => Value::Str(v.clone()), + Self::Array(ref v) => Value::Array(v.eval(ctx)), + Self::Dict(ref v) => Value::Dict(v.eval(ctx)), + Self::Template(ref v) => Value::Template(vec![v.eval(ctx)]), + Self::Group(ref v) => v.eval(ctx), + Self::Block(ref v) => v.eval(ctx), + Self::Call(ref v) => v.eval(ctx), + Self::Closure(ref v) => v.eval(ctx), + Self::Unary(ref v) => v.eval(ctx), + Self::Binary(ref v) => v.eval(ctx), + Self::Let(ref v) => v.eval(ctx), + Self::If(ref v) => v.eval(ctx), + Self::While(ref v) => v.eval(ctx), + Self::For(ref v) => v.eval(ctx), } } } diff --git a/src/eval/ops.rs b/src/eval/ops.rs index bef4dd58..da3432a2 100644 --- a/src/eval/ops.rs +++ b/src/eval/ops.rs @@ -1,5 +1,4 @@ use super::{ArrayValue, DictValue, TemplateNode, Value}; -use crate::syntax::Span; use Value::*; /// Apply the plus operator to a value. @@ -184,7 +183,6 @@ fn value_eq(lhs: &Value, rhs: &Value) -> bool { (&Linear(a), &Relative(b)) => a.rel == b && a.abs.is_zero(), (Array(a), Array(b)) => array_eq(a, b), (Dict(a), Dict(b)) => dict_eq(a, b), - (Template(a), Template(b)) => Span::without_cmp(|| a == b), (a, b) => a == b, } } diff --git a/src/eval/value.rs b/src/eval/value.rs index 485829f3..288e5ed7 100644 --- a/src/eval/value.rs +++ b/src/eval/value.rs @@ -4,7 +4,7 @@ use std::fmt::{self, Debug, Display, Formatter}; use std::ops::Deref; use std::rc::Rc; -use super::{EvalContext, ExprMap}; +use super::{EvalContext, NodeMap}; use crate::color::Color; use crate::diag::DiagSet; use crate::exec::ExecContext; @@ -107,7 +107,7 @@ pub type TemplateValue = Vec<TemplateNode>; /// /// Evaluating a template expression creates only a single node. Adding multiple /// templates can yield multi-node templates. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone)] pub enum TemplateNode { /// A template that consists of a syntax tree plus already evaluated /// expression. @@ -115,7 +115,7 @@ pub enum TemplateNode { /// The syntax tree of the corresponding template expression. tree: Rc<Tree>, /// The evaluated expressions for the `tree`. - map: ExprMap, + map: NodeMap, }, /// A template that was converted from a string. Str(String), @@ -123,6 +123,13 @@ pub enum TemplateNode { Func(TemplateFunc), } +impl PartialEq for TemplateNode { + fn eq(&self, _: &Self) -> bool { + // TODO: Figure out what we want here. + false + } +} + /// A reference-counted dynamic template node that can implement custom /// behaviour. #[derive(Clone)] |
