summaryrefslogtreecommitdiff
path: root/src/eval
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-03-21 17:46:09 +0100
committerLaurenz <laurmaedje@gmail.com>2021-03-21 17:50:56 +0100
commit5e08028fb36aa766957cba64c5c665edf9b96fb7 (patch)
tree912799dad3c1e25b7032f3e3bee009537c6f555b /src/eval
parent898728f260923a91444eb23b522d0abf01a4299b (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.rs36
-rw-r--r--src/eval/mod.rs99
-rw-r--r--src/eval/ops.rs2
-rw-r--r--src/eval/value.rs13
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)]