summaryrefslogtreecommitdiff
path: root/src/eval/mod.rs
diff options
context:
space:
mode:
authorMartin <mhaug@live.de>2021-12-22 20:37:34 +0100
committerGitHub <noreply@github.com>2021-12-22 20:37:34 +0100
commitf6c7a8292dc1ab0560408fca9d74505e9d7cf13a (patch)
treebadd3076f6146cec34c55764600df5124c408521 /src/eval/mod.rs
parent738ff7e1f573bef678932b313be9969a17af8d22 (diff)
parent438255519e88bb790480306b9a9b452aaf054519 (diff)
Merge pull request #51 from typst/set-rules
Set rules
Diffstat (limited to 'src/eval/mod.rs')
-rw-r--r--src/eval/mod.rs194
1 files changed, 155 insertions, 39 deletions
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index a0c31e98..17cc46ef 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -6,21 +6,24 @@ mod array;
mod dict;
#[macro_use]
mod value;
+#[macro_use]
+mod styles;
mod capture;
+mod class;
mod function;
+mod node;
mod ops;
mod scope;
-mod template;
-mod walk;
pub use array::*;
pub use capture::*;
+pub use class::*;
pub use dict::*;
pub use function::*;
+pub use node::*;
pub use scope::*;
-pub use template::*;
+pub use styles::*;
pub use value::*;
-pub use walk::*;
use std::cell::RefMut;
use std::collections::HashMap;
@@ -33,6 +36,8 @@ use unicode_segmentation::UnicodeSegmentation;
use crate::diag::{At, Error, StrResult, Trace, Tracepoint, TypResult};
use crate::geom::{Angle, Fractional, Length, Relative};
use crate::image::ImageStore;
+use crate::layout::RootNode;
+use crate::library::{self, TextNode};
use crate::loading::Loader;
use crate::source::{SourceId, SourceStore};
use crate::syntax::ast::*;
@@ -40,20 +45,30 @@ use crate::syntax::{Span, Spanned};
use crate::util::{EcoString, RefMutExt};
use crate::Context;
-/// Evaluate a parsed source file into a module.
-pub fn eval(ctx: &mut Context, source: SourceId, markup: &Markup) -> TypResult<Module> {
- let mut ctx = EvalContext::new(ctx, source);
- let template = markup.eval(&mut ctx)?;
- Ok(Module { scope: ctx.scopes.top, template })
-}
-
-/// An evaluated module, ready for importing or instantiation.
+/// An evaluated module, ready for importing or conversion to a root layout
+/// tree.
#[derive(Debug, Default, Clone)]
pub struct Module {
/// The top-level definitions that were bound in this module.
pub scope: Scope,
- /// The template defined by this module.
- pub template: Template,
+ /// The module's layoutable contents.
+ pub node: Node,
+}
+
+impl Module {
+ /// Convert this module's node into a layout tree.
+ pub fn into_root(self) -> RootNode {
+ self.node.into_root()
+ }
+}
+
+/// Evaluate an expression.
+pub trait Eval {
+ /// The output of evaluating the expression.
+ type Output;
+
+ /// Evaluate the expression to the output value.
+ fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output>;
}
/// The context for evaluation.
@@ -70,8 +85,8 @@ pub struct EvalContext<'a> {
pub modules: HashMap<SourceId, Module>,
/// The active scopes.
pub scopes: Scopes<'a>,
- /// The currently built template.
- pub template: Template,
+ /// The active styles.
+ pub styles: Styles,
}
impl<'a> EvalContext<'a> {
@@ -84,7 +99,7 @@ impl<'a> EvalContext<'a> {
route: vec![source],
modules: HashMap::new(),
scopes: Scopes::new(Some(&ctx.std)),
- template: Template::new(),
+ styles: Styles::new(),
}
}
@@ -115,18 +130,20 @@ impl<'a> EvalContext<'a> {
// Prepare the new context.
let new_scopes = Scopes::new(self.scopes.base);
- let old_scopes = mem::replace(&mut self.scopes, new_scopes);
+ let prev_scopes = mem::replace(&mut self.scopes, new_scopes);
+ let prev_styles = mem::take(&mut self.styles);
self.route.push(id);
// Evaluate the module.
- let template = ast.eval(self).trace(|| Tracepoint::Import, span)?;
+ let node = ast.eval(self).trace(|| Tracepoint::Import, span)?;
// Restore the old context.
- let new_scopes = mem::replace(&mut self.scopes, old_scopes);
+ let new_scopes = mem::replace(&mut self.scopes, prev_scopes);
+ self.styles = prev_styles;
self.route.pop().unwrap();
// Save the evaluated module.
- let module = Module { scope: new_scopes.top, template };
+ let module = Module { scope: new_scopes.top, node };
self.modules.insert(id, module);
Ok(id)
@@ -145,29 +162,108 @@ impl<'a> EvalContext<'a> {
}
}
-/// Evaluate an expression.
-pub trait Eval {
- /// The output of evaluating the expression.
- type Output;
+impl Eval for Markup {
+ type Output = Node;
- /// Evaluate the expression to the output value.
- fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output>;
+ fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
+ let prev = mem::take(&mut ctx.styles);
+ let nodes = self.nodes();
+ let upper = nodes.size_hint().1.unwrap_or_default();
+ let mut seq = Vec::with_capacity(upper);
+ for piece in nodes {
+ seq.push((piece.eval(ctx)?, ctx.styles.clone()));
+ }
+ ctx.styles = prev;
+ Ok(Node::Sequence(seq))
+ }
}
-impl Eval for Markup {
- type Output = Template;
+impl Eval for MarkupNode {
+ type Output = Node;
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
- Ok({
- let prev = mem::take(&mut ctx.template);
- ctx.template.save();
- self.walk(ctx)?;
- ctx.template.restore();
- mem::replace(&mut ctx.template, prev)
+ Ok(match self {
+ Self::Space => Node::Space,
+ Self::Linebreak => Node::Linebreak,
+ Self::Parbreak => Node::Parbreak,
+ Self::Strong => {
+ ctx.styles.toggle(TextNode::STRONG);
+ Node::new()
+ }
+ Self::Emph => {
+ ctx.styles.toggle(TextNode::EMPH);
+ Node::new()
+ }
+ Self::Text(text) => Node::Text(text.clone()),
+ Self::Raw(raw) => raw.eval(ctx)?,
+ Self::Math(math) => math.eval(ctx)?,
+ Self::Heading(heading) => heading.eval(ctx)?,
+ Self::List(list) => list.eval(ctx)?,
+ Self::Enum(enum_) => enum_.eval(ctx)?,
+ Self::Expr(expr) => expr.eval(ctx)?.show(),
+ })
+ }
+}
+
+impl Eval for RawNode {
+ type Output = Node;
+
+ fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> {
+ let text = Node::Text(self.text.clone()).monospaced();
+ Ok(if self.block {
+ Node::Block(text.into_block())
+ } else {
+ text
})
}
}
+impl Eval for MathNode {
+ type Output = Node;
+
+ fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> {
+ let text = Node::Text(self.formula.trim().into()).monospaced();
+ Ok(if self.display {
+ Node::Block(text.into_block())
+ } else {
+ text
+ })
+ }
+}
+
+impl Eval for HeadingNode {
+ type Output = Node;
+
+ fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
+ Ok(Node::block(library::HeadingNode {
+ child: self.body().eval(ctx)?.into_block(),
+ level: self.level(),
+ }))
+ }
+}
+
+impl Eval for ListNode {
+ type Output = Node;
+
+ fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
+ Ok(Node::block(library::ListNode {
+ child: self.body().eval(ctx)?.into_block(),
+ labelling: library::Unordered,
+ }))
+ }
+}
+
+impl Eval for EnumNode {
+ type Output = Node;
+
+ fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
+ Ok(Node::block(library::ListNode {
+ child: self.body().eval(ctx)?.into_block(),
+ labelling: library::Ordered(self.number()),
+ }))
+ }
+}
+
impl Eval for Expr {
type Output = Value;
@@ -177,7 +273,7 @@ impl Eval for Expr {
Self::Ident(v) => v.eval(ctx),
Self::Array(v) => v.eval(ctx).map(Value::Array),
Self::Dict(v) => v.eval(ctx).map(Value::Dict),
- Self::Template(v) => v.eval(ctx).map(Value::Template),
+ Self::Template(v) => v.eval(ctx).map(Value::Node),
Self::Group(v) => v.eval(ctx),
Self::Block(v) => v.eval(ctx),
Self::Call(v) => v.eval(ctx),
@@ -186,6 +282,7 @@ impl Eval for Expr {
Self::Unary(v) => v.eval(ctx),
Self::Binary(v) => v.eval(ctx),
Self::Let(v) => v.eval(ctx),
+ Self::Set(v) => v.eval(ctx),
Self::If(v) => v.eval(ctx),
Self::While(v) => v.eval(ctx),
Self::For(v) => v.eval(ctx),
@@ -244,7 +341,7 @@ impl Eval for DictExpr {
}
impl Eval for TemplateExpr {
- type Output = Template;
+ type Output = Node;
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
self.body().eval(ctx)
@@ -372,9 +469,15 @@ impl Eval for CallExpr {
Ok(value)
}
+ Value::Class(class) => {
+ let node = class.construct(ctx, &mut args)?;
+ args.finish()?;
+ Ok(Value::Node(node))
+ }
+
v => bail!(
self.callee().span(),
- "expected function or collection, found {}",
+ "expected callable or collection, found {}",
v.type_name(),
),
}
@@ -541,6 +644,19 @@ impl Eval for LetExpr {
}
}
+impl Eval for SetExpr {
+ type Output = Value;
+
+ fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
+ let class = self.class();
+ let class = class.eval(ctx)?.cast::<Class>().at(class.span())?;
+ let mut args = self.args().eval(ctx)?;
+ class.set(&mut args, &mut ctx.styles)?;
+ args.finish()?;
+ Ok(Value::None)
+ }
+}
+
impl Eval for IfExpr {
type Output = Value;
@@ -665,7 +781,7 @@ impl Eval for IncludeExpr {
let resolved = path.eval(ctx)?.cast::<EcoString>().at(path.span())?;
let file = ctx.import(&resolved, path.span())?;
let module = &ctx.modules[&file];
- Ok(Value::Template(module.template.clone()))
+ Ok(Value::Node(module.node.clone()))
}
}