summaryrefslogtreecommitdiff
path: root/src/eval
diff options
context:
space:
mode:
Diffstat (limited to 'src/eval')
-rw-r--r--src/eval/class.rs11
-rw-r--r--src/eval/func.rs32
-rw-r--r--src/eval/layout.rs46
-rw-r--r--src/eval/mod.rs360
-rw-r--r--src/eval/module.rs20
-rw-r--r--src/eval/scope.rs5
-rw-r--r--src/eval/show.rs8
-rw-r--r--src/eval/styles.rs12
-rw-r--r--src/eval/template.rs67
9 files changed, 286 insertions, 275 deletions
diff --git a/src/eval/class.rs b/src/eval/class.rs
index 5601fb0b..5e1857d7 100644
--- a/src/eval/class.rs
+++ b/src/eval/class.rs
@@ -2,8 +2,9 @@ use std::any::TypeId;
use std::fmt::{self, Debug, Formatter, Write};
use std::hash::{Hash, Hasher};
-use super::{Args, Func, StyleMap, Template, Value, Vm};
+use super::{Args, Func, StyleMap, Template, Value};
use crate::diag::TypResult;
+use crate::Context;
/// A class of nodes.
///
@@ -38,7 +39,7 @@ use crate::diag::TypResult;
pub struct Class {
name: &'static str,
id: TypeId,
- construct: fn(&mut Vm, &mut Args) -> TypResult<Value>,
+ construct: fn(&mut Context, &mut Args) -> TypResult<Value>,
set: fn(&mut Args, &mut StyleMap) -> TypResult<()>,
}
@@ -81,8 +82,8 @@ impl Class {
/// This parses both property and data arguments (in this order), styles the
/// template constructed from the data with the style properties and wraps
/// it in a value.
- pub fn construct(&self, vm: &mut Vm, mut args: Args) -> TypResult<Value> {
- let value = (self.construct)(vm, &mut args)?;
+ pub fn construct(&self, ctx: &mut Context, mut args: Args) -> TypResult<Value> {
+ let value = (self.construct)(ctx, &mut args)?;
args.finish()?;
Ok(value)
}
@@ -125,7 +126,7 @@ pub trait Construct {
///
/// This is passed only the arguments that remain after execution of the
/// class's set rule.
- fn construct(vm: &mut Vm, args: &mut Args) -> TypResult<Template>;
+ fn construct(ctx: &mut Context, args: &mut Args) -> TypResult<Template>;
}
/// Set style properties of a class.
diff --git a/src/eval/func.rs b/src/eval/func.rs
index 128509f8..cd54a140 100644
--- a/src/eval/func.rs
+++ b/src/eval/func.rs
@@ -2,11 +2,12 @@ use std::fmt::{self, Debug, Formatter, Write};
use std::hash::{Hash, Hasher};
use std::sync::Arc;
-use super::{Cast, Eval, Scope, Value, Vm};
+use super::{Cast, Eval, Scope, Scopes, Value};
use crate::diag::{At, TypResult};
use crate::syntax::ast::Expr;
use crate::syntax::{Span, Spanned};
use crate::util::EcoString;
+use crate::Context;
/// An evaluatable function.
#[derive(Clone, Hash)]
@@ -27,7 +28,7 @@ impl Func {
/// Create a new function from a native rust function.
pub fn native(
name: &'static str,
- func: fn(&mut Vm, &mut Args) -> TypResult<Value>,
+ func: fn(&mut Context, &mut Args) -> TypResult<Value>,
) -> Self {
Self(Arc::new(Repr::Native(Native { name, func })))
}
@@ -46,14 +47,14 @@ impl Func {
}
}
- /// Call the function in the context with the arguments.
- pub fn call(&self, vm: &mut Vm, mut args: Args) -> TypResult<Value> {
+ /// Call the function with a virtual machine and arguments.
+ pub fn call(&self, ctx: &mut Context, mut args: Args) -> TypResult<Value> {
let value = match self.0.as_ref() {
- Repr::Native(native) => (native.func)(vm, &mut args)?,
- Repr::Closure(closure) => closure.call(vm, &mut args)?,
+ Repr::Native(native) => (native.func)(ctx, &mut args)?,
+ Repr::Closure(closure) => closure.call(ctx, &mut args)?,
Repr::With(wrapped, applied) => {
args.items.splice(.. 0, applied.items.iter().cloned());
- return wrapped.call(vm, args);
+ return wrapped.call(ctx, args);
}
};
args.finish()?;
@@ -88,7 +89,7 @@ struct Native {
/// The name of the function.
pub name: &'static str,
/// The function pointer.
- pub func: fn(&mut Vm, &mut Args) -> TypResult<Value>,
+ pub func: fn(&mut Context, &mut Args) -> TypResult<Value>,
}
impl Hash for Native {
@@ -115,15 +116,15 @@ pub struct Closure {
impl Closure {
/// Call the function in the context with the arguments.
- pub fn call(&self, vm: &mut Vm, args: &mut Args) -> TypResult<Value> {
+ pub fn call(&self, ctx: &mut Context, args: &mut Args) -> TypResult<Value> {
// Don't leak the scopes from the call site. Instead, we use the
// scope of captured variables we collected earlier.
- let prev_scopes = std::mem::take(&mut vm.scopes);
- vm.scopes.top = self.captured.clone();
+ let mut scp = Scopes::new(None);
+ scp.top = self.captured.clone();
// Parse the arguments according to the parameter list.
for (param, default) in &self.params {
- vm.scopes.top.def_mut(param, match default {
+ scp.top.def_mut(param, match default {
None => args.expect::<Value>(param)?,
Some(default) => {
args.named::<Value>(param)?.unwrap_or_else(|| default.clone())
@@ -133,14 +134,11 @@ impl Closure {
// Put the remaining arguments into the sink.
if let Some(sink) = &self.sink {
- vm.scopes.top.def_mut(sink, args.take());
+ scp.top.def_mut(sink, args.take());
}
// Evaluate the body.
- let value = self.body.eval(vm)?;
-
- // Restore the call site scopes.
- vm.scopes = prev_scopes;
+ let value = self.body.eval(ctx, &mut scp)?;
Ok(value)
}
diff --git a/src/eval/layout.rs b/src/eval/layout.rs
index 7608023a..1090aafc 100644
--- a/src/eval/layout.rs
+++ b/src/eval/layout.rs
@@ -11,7 +11,7 @@ use crate::frame::{Element, Frame, Geometry, Shape, Stroke};
use crate::geom::{Align, Length, Linear, Paint, Point, Sides, Size, Spec, Transform};
use crate::library::{AlignNode, PadNode, TransformNode, MOVE};
use crate::util::Prehashed;
-use crate::Vm;
+use crate::Context;
/// A node that can be layouted into a sequence of regions.
///
@@ -21,7 +21,7 @@ pub trait Layout {
/// Layout the node into the given regions, producing constrained frames.
fn layout(
&self,
- vm: &mut Vm,
+ ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>>;
@@ -36,14 +36,14 @@ pub trait Layout {
}
/// A sequence of regions to layout into.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Hash)]
pub struct Regions {
/// The (remaining) size of the first region.
pub first: Size,
/// The base size for relative sizing.
pub base: Size,
/// The height of followup regions. The width is the same for all regions.
- pub backlog: std::vec::IntoIter<Length>,
+ pub backlog: Vec<Length>,
/// The height of the final region that is repeated once the backlog is
/// drained. The width is the same for all regions.
pub last: Option<Length>,
@@ -58,7 +58,7 @@ impl Regions {
Self {
first: size,
base,
- backlog: vec![].into_iter(),
+ backlog: vec![],
last: None,
expand,
}
@@ -69,7 +69,7 @@ impl Regions {
Self {
first: size,
base,
- backlog: vec![].into_iter(),
+ backlog: vec![],
last: Some(size.y),
expand,
}
@@ -87,13 +87,7 @@ impl Regions {
Self {
first: f(self.first),
base: f(self.base),
- backlog: self
- .backlog
- .as_slice()
- .iter()
- .map(|&y| f(Size::new(x, y)).y)
- .collect::<Vec<_>>()
- .into_iter(),
+ backlog: self.backlog.iter().map(|&y| f(Size::new(x, y)).y).collect(),
last: self.last.map(|y| f(Size::new(x, y)).y),
expand: self.expand,
}
@@ -113,7 +107,10 @@ impl Regions {
/// Advance to the next region if there is any.
pub fn next(&mut self) {
- if let Some(height) = self.backlog.next().or(self.last) {
+ if let Some(height) = (!self.backlog.is_empty())
+ .then(|| self.backlog.remove(0))
+ .or(self.last)
+ {
self.first.y = height;
self.base.y = height;
}
@@ -125,7 +122,7 @@ impl Regions {
/// This iterater may be infinite.
pub fn iter(&self) -> impl Iterator<Item = Size> + '_ {
let first = std::iter::once(self.first);
- let backlog = self.backlog.as_slice().iter();
+ let backlog = self.backlog.iter();
let last = self.last.iter().cycle();
first.chain(backlog.chain(last).map(|&h| Size::new(self.first.x, h)))
}
@@ -218,15 +215,14 @@ impl LayoutNode {
}
impl Layout for LayoutNode {
- #[track_caller]
fn layout(
&self,
- vm: &mut Vm,
+ ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
// TODO(query)
- self.0.layout(vm, regions, styles.barred(self.id()))
+ self.0.layout(ctx, regions, styles.barred(self.id()))
}
fn pack(self) -> LayoutNode {
@@ -274,7 +270,7 @@ struct EmptyNode;
impl Layout for EmptyNode {
fn layout(
&self,
- _: &mut Vm,
+ _: &mut Context,
regions: &Regions,
_: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
@@ -296,7 +292,7 @@ struct SizedNode {
impl Layout for SizedNode {
fn layout(
&self,
- vm: &mut Vm,
+ ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
@@ -319,7 +315,7 @@ impl Layout for SizedNode {
};
// Layout the child.
- let mut frames = self.child.layout(vm, &pod, styles)?;
+ let mut frames = self.child.layout(ctx, &pod, styles)?;
// Ensure frame size matches regions size if expansion is on.
let frame = &mut frames[0];
@@ -342,11 +338,11 @@ struct FillNode {
impl Layout for FillNode {
fn layout(
&self,
- vm: &mut Vm,
+ ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
- let mut frames = self.child.layout(vm, regions, styles)?;
+ let mut frames = self.child.layout(ctx, regions, styles)?;
for frame in &mut frames {
let shape = Shape::filled(Geometry::Rect(frame.size), self.fill);
Arc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape));
@@ -367,11 +363,11 @@ struct StrokeNode {
impl Layout for StrokeNode {
fn layout(
&self,
- vm: &mut Vm,
+ ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
- let mut frames = self.child.layout(vm, regions, styles)?;
+ let mut frames = self.child.layout(ctx, regions, styles)?;
for frame in &mut frames {
let shape = Shape::stroked(Geometry::Rect(frame.size), self.stroke);
Arc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape));
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index a67a21d4..bc6c8fc8 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -13,6 +13,7 @@ mod class;
mod collapse;
mod func;
mod layout;
+mod module;
mod ops;
mod scope;
mod show;
@@ -25,15 +26,13 @@ pub use collapse::*;
pub use dict::*;
pub use func::*;
pub use layout::*;
+pub use module::*;
pub use scope::*;
pub use show::*;
pub use styles::*;
pub use template::*;
pub use value::*;
-use std::io;
-use std::mem;
-
use unicode_segmentation::UnicodeSegmentation;
use crate::diag::{At, Error, StrResult, Trace, Tracepoint, TypResult};
@@ -42,17 +41,7 @@ use crate::library;
use crate::syntax::ast::*;
use crate::syntax::{Span, Spanned};
use crate::util::EcoString;
-use crate::Vm;
-
-/// An evaluated module, ready for importing or conversion to a root layout
-/// tree.
-#[derive(Debug, Clone)]
-pub struct Module {
- /// The top-level definitions that were bound in this module.
- pub scope: Scope,
- /// The module's layoutable contents.
- pub template: Template,
-}
+use crate::Context;
/// Evaluate an expression.
pub trait Eval {
@@ -60,20 +49,21 @@ pub trait Eval {
type Output;
/// Evaluate the expression to the output value.
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output>;
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output>;
}
impl Eval for Markup {
type Output = Template;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
- eval_markup(vm, &mut self.nodes())
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
+ eval_markup(ctx, scp, &mut self.nodes())
}
}
/// Evaluate a stream of markup nodes.
fn eval_markup(
- vm: &mut Vm,
+ ctx: &mut Context,
+ scp: &mut Scopes,
nodes: &mut impl Iterator<Item = MarkupNode>,
) -> TypResult<Template> {
let mut seq = Vec::with_capacity(nodes.size_hint().1.unwrap_or_default());
@@ -81,19 +71,19 @@ fn eval_markup(
while let Some(node) = nodes.next() {
seq.push(match node {
MarkupNode::Expr(Expr::Set(set)) => {
- let styles = set.eval(vm)?;
- eval_markup(vm, nodes)?.styled_with_map(styles)
+ let styles = set.eval(ctx, scp)?;
+ eval_markup(ctx, scp, nodes)?.styled_with_map(styles)
}
MarkupNode::Expr(Expr::Show(show)) => {
- let styles = show.eval(vm)?;
- eval_markup(vm, nodes)?.styled_with_map(styles)
+ let styles = show.eval(ctx, scp)?;
+ eval_markup(ctx, scp, nodes)?.styled_with_map(styles)
}
MarkupNode::Expr(Expr::Wrap(wrap)) => {
- let tail = eval_markup(vm, nodes)?;
- vm.scopes.top.def_mut(wrap.binding().take(), tail);
- wrap.body().eval(vm)?.display()
+ let tail = eval_markup(ctx, scp, nodes)?;
+ scp.top.def_mut(wrap.binding().take(), tail);
+ wrap.body().eval(ctx, scp)?.display()
}
- _ => node.eval(vm)?,
+ _ => node.eval(ctx, scp)?,
});
}
@@ -103,20 +93,20 @@ fn eval_markup(
impl Eval for MarkupNode {
type Output = Template;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
Ok(match self {
Self::Space => Template::Space,
Self::Linebreak => Template::Linebreak,
Self::Parbreak => Template::Parbreak,
Self::Text(text) => Template::Text(text.clone()),
- Self::Strong(strong) => strong.eval(vm)?,
- Self::Emph(emph) => emph.eval(vm)?,
- Self::Raw(raw) => raw.eval(vm)?,
- Self::Math(math) => math.eval(vm)?,
- Self::Heading(heading) => heading.eval(vm)?,
- Self::List(list) => list.eval(vm)?,
- Self::Enum(enum_) => enum_.eval(vm)?,
- Self::Expr(expr) => expr.eval(vm)?.display(),
+ Self::Strong(strong) => strong.eval(ctx, scp)?,
+ Self::Emph(emph) => emph.eval(ctx, scp)?,
+ Self::Raw(raw) => raw.eval(ctx, scp)?,
+ Self::Math(math) => math.eval(ctx, scp)?,
+ Self::Heading(heading) => heading.eval(ctx, scp)?,
+ Self::List(list) => list.eval(ctx, scp)?,
+ Self::Enum(enum_) => enum_.eval(ctx, scp)?,
+ Self::Expr(expr) => expr.eval(ctx, scp)?.display(),
})
}
}
@@ -124,23 +114,27 @@ impl Eval for MarkupNode {
impl Eval for StrongNode {
type Output = Template;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
- Ok(Template::show(library::StrongNode(self.body().eval(vm)?)))
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
+ Ok(Template::show(library::StrongNode(
+ self.body().eval(ctx, scp)?,
+ )))
}
}
impl Eval for EmphNode {
type Output = Template;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
- Ok(Template::show(library::EmphNode(self.body().eval(vm)?)))
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
+ Ok(Template::show(library::EmphNode(
+ self.body().eval(ctx, scp)?,
+ )))
}
}
impl Eval for RawNode {
type Output = Template;
- fn eval(&self, _: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, _: &mut Context, _: &mut Scopes) -> TypResult<Self::Output> {
let template = Template::show(library::RawNode {
text: self.text.clone(),
block: self.block,
@@ -155,7 +149,7 @@ impl Eval for RawNode {
impl Eval for MathNode {
type Output = Template;
- fn eval(&self, _: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, _: &mut Context, _: &mut Scopes) -> TypResult<Self::Output> {
Ok(Template::show(library::MathNode {
formula: self.formula.clone(),
display: self.display,
@@ -166,9 +160,9 @@ impl Eval for MathNode {
impl Eval for HeadingNode {
type Output = Template;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
Ok(Template::show(library::HeadingNode {
- body: self.body().eval(vm)?,
+ body: self.body().eval(ctx, scp)?,
level: self.level(),
}))
}
@@ -177,10 +171,10 @@ impl Eval for HeadingNode {
impl Eval for ListNode {
type Output = Template;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
Ok(Template::List(library::ListItem {
number: None,
- body: Box::new(self.body().eval(vm)?),
+ body: Box::new(self.body().eval(ctx, scp)?),
}))
}
}
@@ -188,10 +182,10 @@ impl Eval for ListNode {
impl Eval for EnumNode {
type Output = Template;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
Ok(Template::Enum(library::ListItem {
number: self.number(),
- body: Box::new(self.body().eval(vm)?),
+ body: Box::new(self.body().eval(ctx, scp)?),
}))
}
}
@@ -199,33 +193,33 @@ impl Eval for EnumNode {
impl Eval for Expr {
type Output = Value;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
match self {
- Self::Lit(v) => v.eval(vm),
- Self::Ident(v) => v.eval(vm),
- Self::Array(v) => v.eval(vm).map(Value::Array),
- Self::Dict(v) => v.eval(vm).map(Value::Dict),
- Self::Template(v) => v.eval(vm).map(Value::Template),
- Self::Group(v) => v.eval(vm),
- Self::Block(v) => v.eval(vm),
- Self::Call(v) => v.eval(vm),
- Self::Closure(v) => v.eval(vm),
- Self::With(v) => v.eval(vm),
- Self::Unary(v) => v.eval(vm),
- Self::Binary(v) => v.eval(vm),
- Self::Let(v) => v.eval(vm),
+ Self::Lit(v) => v.eval(ctx, scp),
+ Self::Ident(v) => v.eval(ctx, scp),
+ Self::Array(v) => v.eval(ctx, scp).map(Value::Array),
+ Self::Dict(v) => v.eval(ctx, scp).map(Value::Dict),
+ Self::Template(v) => v.eval(ctx, scp).map(Value::Template),
+ Self::Group(v) => v.eval(ctx, scp),
+ Self::Block(v) => v.eval(ctx, scp),
+ Self::Call(v) => v.eval(ctx, scp),
+ Self::Closure(v) => v.eval(ctx, scp),
+ Self::With(v) => v.eval(ctx, scp),
+ Self::Unary(v) => v.eval(ctx, scp),
+ Self::Binary(v) => v.eval(ctx, scp),
+ Self::Let(v) => v.eval(ctx, scp),
Self::Set(_) | Self::Show(_) | Self::Wrap(_) => {
Err("set, show and wrap are only allowed directly in markup")
.at(self.span())
}
- Self::If(v) => v.eval(vm),
- Self::While(v) => v.eval(vm),
- Self::For(v) => v.eval(vm),
- Self::Import(v) => v.eval(vm),
- Self::Include(v) => v.eval(vm),
- Self::Break(v) => v.eval(vm),
- Self::Continue(v) => v.eval(vm),
- Self::Return(v) => v.eval(vm),
+ Self::If(v) => v.eval(ctx, scp),
+ Self::While(v) => v.eval(ctx, scp),
+ Self::For(v) => v.eval(ctx, scp),
+ Self::Import(v) => v.eval(ctx, scp),
+ Self::Include(v) => v.eval(ctx, scp).map(Value::Template),
+ Self::Break(v) => v.eval(ctx, scp),
+ Self::Continue(v) => v.eval(ctx, scp),
+ Self::Return(v) => v.eval(ctx, scp),
}
}
}
@@ -233,7 +227,7 @@ impl Eval for Expr {
impl Eval for Lit {
type Output = Value;
- fn eval(&self, _: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, _: &mut Context, _: &mut Scopes) -> TypResult<Self::Output> {
Ok(match self.kind() {
LitKind::None => Value::None,
LitKind::Auto => Value::Auto,
@@ -252,8 +246,8 @@ impl Eval for Lit {
impl Eval for Ident {
type Output = Value;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
- match vm.scopes.get(self) {
+ fn eval(&self, _: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
+ match scp.get(self) {
Some(slot) => Ok(slot.read().unwrap().clone()),
None => bail!(self.span(), "unknown variable"),
}
@@ -263,17 +257,17 @@ impl Eval for Ident {
impl Eval for ArrayExpr {
type Output = Array;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
- self.items().map(|expr| expr.eval(vm)).collect()
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
+ self.items().map(|expr| expr.eval(ctx, scp)).collect()
}
}
impl Eval for DictExpr {
type Output = Dict;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
self.items()
- .map(|x| Ok((x.name().take(), x.expr().eval(vm)?)))
+ .map(|x| Ok((x.name().take(), x.expr().eval(ctx, scp)?)))
.collect()
}
}
@@ -281,10 +275,10 @@ impl Eval for DictExpr {
impl Eval for TemplateExpr {
type Output = Template;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
- vm.scopes.enter();
- let template = self.body().eval(vm)?;
- vm.scopes.exit();
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
+ scp.enter();
+ let template = self.body().eval(ctx, scp)?;
+ scp.exit();
Ok(template)
}
}
@@ -292,24 +286,24 @@ impl Eval for TemplateExpr {
impl Eval for GroupExpr {
type Output = Value;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
- self.expr().eval(vm)
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
+ self.expr().eval(ctx, scp)
}
}
impl Eval for BlockExpr {
type Output = Value;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
- vm.scopes.enter();
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
+ scp.enter();
let mut output = Value::None;
for expr in self.exprs() {
- let value = expr.eval(vm)?;
+ let value = expr.eval(ctx, scp)?;
output = ops::join(output, value).at(expr.span())?;
}
- vm.scopes.exit();
+ scp.exit();
Ok(output)
}
@@ -318,8 +312,8 @@ impl Eval for BlockExpr {
impl Eval for UnaryExpr {
type Output = Value;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
- let value = self.expr().eval(vm)?;
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
+ let value = self.expr().eval(ctx, scp)?;
let result = match self.op() {
UnOp::Pos => ops::pos(value),
UnOp::Neg => ops::neg(value),
@@ -332,25 +326,25 @@ impl Eval for UnaryExpr {
impl Eval for BinaryExpr {
type Output = Value;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
match self.op() {
- BinOp::Add => self.apply(vm, ops::add),
- BinOp::Sub => self.apply(vm, ops::sub),
- BinOp::Mul => self.apply(vm, ops::mul),
- BinOp::Div => self.apply(vm, ops::div),
- BinOp::And => self.apply(vm, ops::and),
- BinOp::Or => self.apply(vm, ops::or),
- BinOp::Eq => self.apply(vm, ops::eq),
- BinOp::Neq => self.apply(vm, ops::neq),
- BinOp::Lt => self.apply(vm, ops::lt),
- BinOp::Leq => self.apply(vm, ops::leq),
- BinOp::Gt => self.apply(vm, ops::gt),
- BinOp::Geq => self.apply(vm, ops::geq),
- BinOp::Assign => self.assign(vm, |_, b| Ok(b)),
- BinOp::AddAssign => self.assign(vm, ops::add),
- BinOp::SubAssign => self.assign(vm, ops::sub),
- BinOp::MulAssign => self.assign(vm, ops::mul),
- BinOp::DivAssign => self.assign(vm, ops::div),
+ BinOp::Add => self.apply(ctx, scp, ops::add),
+ BinOp::Sub => self.apply(ctx, scp, ops::sub),
+ BinOp::Mul => self.apply(ctx, scp, ops::mul),
+ BinOp::Div => self.apply(ctx, scp, ops::div),
+ BinOp::And => self.apply(ctx, scp, ops::and),
+ BinOp::Or => self.apply(ctx, scp, ops::or),
+ BinOp::Eq => self.apply(ctx, scp, ops::eq),
+ BinOp::Neq => self.apply(ctx, scp, ops::neq),
+ BinOp::Lt => self.apply(ctx, scp, ops::lt),
+ BinOp::Leq => self.apply(ctx, scp, ops::leq),
+ BinOp::Gt => self.apply(ctx, scp, ops::gt),
+ BinOp::Geq => self.apply(ctx, scp, ops::geq),
+ BinOp::Assign => self.assign(ctx, scp, |_, b| Ok(b)),
+ BinOp::AddAssign => self.assign(ctx, scp, ops::add),
+ BinOp::SubAssign => self.assign(ctx, scp, ops::sub),
+ BinOp::MulAssign => self.assign(ctx, scp, ops::mul),
+ BinOp::DivAssign => self.assign(ctx, scp, ops::div),
}
}
}
@@ -359,10 +353,11 @@ impl BinaryExpr {
/// Apply a basic binary operation.
fn apply(
&self,
- vm: &mut Vm,
+ ctx: &mut Context,
+ scp: &mut Scopes,
op: fn(Value, Value) -> StrResult<Value>,
) -> TypResult<Value> {
- let lhs = self.lhs().eval(vm)?;
+ let lhs = self.lhs().eval(ctx, scp)?;
// Short-circuit boolean operations.
if (self.op() == BinOp::And && lhs == Value::Bool(false))
@@ -371,21 +366,23 @@ impl BinaryExpr {
return Ok(lhs);
}
- let rhs = self.rhs().eval(vm)?;
+ let rhs = self.rhs().eval(ctx, scp)?;
op(lhs, rhs).at(self.span())
}
/// Apply an assignment operation.
fn assign(
&self,
- vm: &mut Vm,
+ ctx: &mut Context,
+ scp: &mut Scopes,
op: fn(Value, Value) -> StrResult<Value>,
) -> TypResult<Value> {
- let rhs = self.rhs().eval(vm)?;
+ let rhs = self.rhs().eval(ctx, scp)?;
self.lhs().access(
- vm,
+ ctx,
+ scp,
Box::new(|target| {
- let lhs = mem::take(&mut *target);
+ let lhs = std::mem::take(&mut *target);
*target = op(lhs, rhs).at(self.span())?;
Ok(())
}),
@@ -397,10 +394,10 @@ impl BinaryExpr {
impl Eval for CallExpr {
type Output = Value;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
let span = self.callee().span();
- let callee = self.callee().eval(vm)?;
- let args = self.args().eval(vm)?;
+ let callee = self.callee().eval(ctx, scp)?;
+ let args = self.args().eval(ctx, scp)?;
match callee {
Value::Array(array) => {
@@ -413,12 +410,12 @@ impl Eval for CallExpr {
Value::Func(func) => {
let point = || Tracepoint::Call(func.name().map(ToString::to_string));
- func.call(vm, args).trace(point, self.span())
+ func.call(ctx, args).trace(point, self.span())
}
Value::Class(class) => {
let point = || Tracepoint::Call(Some(class.name().to_string()));
- class.construct(vm, args).trace(point, self.span())
+ class.construct(ctx, args).trace(point, self.span())
}
v => bail!(
@@ -433,7 +430,7 @@ impl Eval for CallExpr {
impl Eval for CallArgs {
type Output = Args;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
let mut items = Vec::new();
for arg in self.items() {
@@ -443,17 +440,20 @@ impl Eval for CallArgs {
items.push(Arg {
span,
name: None,
- value: Spanned::new(expr.eval(vm)?, expr.span()),
+ value: Spanned::new(expr.eval(ctx, scp)?, expr.span()),
});
}
CallArg::Named(named) => {
items.push(Arg {
span,
name: Some(named.name().take()),
- value: Spanned::new(named.expr().eval(vm)?, named.expr().span()),
+ value: Spanned::new(
+ named.expr().eval(ctx, scp)?,
+ named.expr().span(),
+ ),
});
}
- CallArg::Spread(expr) => match expr.eval(vm)? {
+ CallArg::Spread(expr) => match expr.eval(ctx, scp)? {
Value::None => {}
Value::Array(array) => {
items.extend(array.into_iter().map(|value| Arg {
@@ -482,13 +482,13 @@ impl Eval for CallArgs {
impl Eval for ClosureExpr {
type Output = Value;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
// The closure's name is defined by its let binding if there's one.
let name = self.name().map(Ident::take);
// Collect captured variables.
let captured = {
- let mut visitor = CapturesVisitor::new(&vm.scopes);
+ let mut visitor = CapturesVisitor::new(scp);
visitor.visit(self.as_red());
visitor.finish()
};
@@ -503,7 +503,8 @@ impl Eval for ClosureExpr {
params.push((name.take(), None));
}
ClosureParam::Named(named) => {
- params.push((named.name().take(), Some(named.expr().eval(vm)?)));
+ params
+ .push((named.name().take(), Some(named.expr().eval(ctx, scp)?)));
}
ClosureParam::Sink(name) => {
if sink.is_some() {
@@ -528,10 +529,10 @@ impl Eval for ClosureExpr {
impl Eval for WithExpr {
type Output = Value;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
let callee = self.callee();
- let func = callee.eval(vm)?.cast::<Func>().at(callee.span())?;
- let args = self.args().eval(vm)?;
+ let func = callee.eval(ctx, scp)?.cast::<Func>().at(callee.span())?;
+ let args = self.args().eval(ctx, scp)?;
Ok(Value::Func(func.with(args)))
}
}
@@ -539,12 +540,12 @@ impl Eval for WithExpr {
impl Eval for LetExpr {
type Output = Value;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
let value = match self.init() {
- Some(expr) => expr.eval(vm)?,
+ Some(expr) => expr.eval(ctx, scp)?,
None => Value::None,
};
- vm.scopes.top.def_mut(self.binding().take(), value);
+ scp.top.def_mut(self.binding().take(), value);
Ok(Value::None)
}
}
@@ -552,10 +553,10 @@ impl Eval for LetExpr {
impl Eval for SetExpr {
type Output = StyleMap;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
let class = self.class();
- let class = class.eval(vm)?.cast::<Class>().at(class.span())?;
- let args = self.args().eval(vm)?;
+ let class = class.eval(ctx, scp)?.cast::<Class>().at(class.span())?;
+ let args = self.args().eval(ctx, scp)?;
class.set(args)
}
}
@@ -563,11 +564,11 @@ impl Eval for SetExpr {
impl Eval for ShowExpr {
type Output = StyleMap;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
let class = self.class();
- let class = class.eval(vm)?.cast::<Class>().at(class.span())?;
+ let class = class.eval(ctx, scp)?.cast::<Class>().at(class.span())?;
let closure = self.closure();
- let func = closure.eval(vm)?.cast::<Func>().at(closure.span())?;
+ let func = closure.eval(ctx, scp)?.cast::<Func>().at(closure.span())?;
let mut styles = StyleMap::new();
styles.set_recipe(class.id(), func, self.span());
Ok(styles)
@@ -577,12 +578,12 @@ impl Eval for ShowExpr {
impl Eval for IfExpr {
type Output = Value;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
let condition = self.condition();
- if condition.eval(vm)?.cast::<bool>().at(condition.span())? {
- self.if_body().eval(vm)
+ if condition.eval(ctx, scp)?.cast::<bool>().at(condition.span())? {
+ self.if_body().eval(ctx, scp)
} else if let Some(else_body) = self.else_body() {
- else_body.eval(vm)
+ else_body.eval(ctx, scp)
} else {
Ok(Value::None)
}
@@ -592,13 +593,13 @@ impl Eval for IfExpr {
impl Eval for WhileExpr {
type Output = Value;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
let mut output = Value::None;
let condition = self.condition();
- while condition.eval(vm)?.cast::<bool>().at(condition.span())? {
+ while condition.eval(ctx, scp)?.cast::<bool>().at(condition.span())? {
let body = self.body();
- let value = body.eval(vm)?;
+ let value = body.eval(ctx, scp)?;
output = ops::join(output, value).at(body.span())?;
}
@@ -609,27 +610,27 @@ impl Eval for WhileExpr {
impl Eval for ForExpr {
type Output = Value;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
macro_rules! iter {
(for ($($binding:ident => $value:ident),*) in $iter:expr) => {{
let mut output = Value::None;
- vm.scopes.enter();
+ scp.enter();
#[allow(unused_parens)]
for ($($value),*) in $iter {
- $(vm.scopes.top.def_mut(&$binding, $value);)*
+ $(scp.top.def_mut(&$binding, $value);)*
- let value = self.body().eval(vm)?;
+ let value = self.body().eval(ctx, scp)?;
output = ops::join(output, value)
.at(self.body().span())?;
}
- vm.scopes.exit();
+ scp.exit();
return Ok(output);
}};
}
- let iter = self.iter().eval(vm)?;
+ let iter = self.iter().eval(ctx, scp)?;
let pattern = self.pattern();
let key = pattern.key().map(Ident::take);
let value = pattern.value().take();
@@ -672,21 +673,21 @@ impl Eval for ForExpr {
impl Eval for ImportExpr {
type Output = Value;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
let span = self.path().span();
- let path = self.path().eval(vm)?.cast::<EcoString>().at(span)?;
- let module = import(vm, &path, span)?;
+ let path = self.path().eval(ctx, scp)?.cast::<EcoString>().at(span)?;
+ let module = import(ctx, &path, span)?;
match self.imports() {
Imports::Wildcard => {
for (var, slot) in module.scope.iter() {
- vm.scopes.top.def_mut(var, slot.read().unwrap().clone());
+ scp.top.def_mut(var, slot.read().unwrap().clone());
}
}
Imports::Items(idents) => {
for ident in idents {
if let Some(slot) = module.scope.get(&ident) {
- vm.scopes.top.def_mut(ident.take(), slot.read().unwrap().clone());
+ scp.top.def_mut(ident.take(), slot.read().unwrap().clone());
} else {
bail!(ident.span(), "unresolved import");
}
@@ -699,40 +700,42 @@ impl Eval for ImportExpr {
}
impl Eval for IncludeExpr {
- type Output = Value;
+ type Output = Template;
- fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> {
let span = self.path().span();
- let path = self.path().eval(vm)?.cast::<EcoString>().at(span)?;
- let module = import(vm, &path, span)?;
- Ok(Value::Template(module.template.clone()))
+ let path = self.path().eval(ctx, scp)?.cast::<EcoString>().at(span)?;
+ let module = import(ctx, &path, span)?;
+ Ok(module.template.clone())
}
}
/// Process an import of a module relative to the current location.
-fn import(vm: &mut Vm, path: &str, span: Span) -> TypResult<Module> {
+fn import(ctx: &mut Context, path: &str, span: Span) -> TypResult<Module> {
// Load the source file.
- let full = vm.resolve(path);
- let id = vm.sources.load(&full).map_err(|err| {
+ let full = ctx.resolve(path);
+ let id = ctx.sources.load(&full).map_err(|err| {
Error::boxed(span, match err.kind() {
- io::ErrorKind::NotFound => "file not found".into(),
+ std::io::ErrorKind::NotFound => "file not found".into(),
_ => format!("failed to load source file ({})", err),
})
})?;
// Prevent cyclic importing.
- if vm.route.contains(&id) {
+ if ctx.route.contains(&id) {
bail!(span, "cyclic import");
}
// Evaluate the file.
- vm.evaluate(id).trace(|| Tracepoint::Import, span)
+ let module = ctx.evaluate(id).trace(|| Tracepoint::Import, span)?;
+ ctx.deps.extend(module.deps.iter().cloned());
+ Ok(module)
}
impl Eval for BreakExpr {
type Output = Value;
- fn eval(&self, _: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, _: &mut Context, _: &mut Scopes) -> TypResult<Self::Output> {
Err("break is not yet implemented").at(self.span())
}
}
@@ -740,7 +743,7 @@ impl Eval for BreakExpr {
impl Eval for ContinueExpr {
type Output = Value;
- fn eval(&self, _: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, _: &mut Context, _: &mut Scopes) -> TypResult<Self::Output> {
Err("continue is not yet implemented").at(self.span())
}
}
@@ -748,7 +751,7 @@ impl Eval for ContinueExpr {
impl Eval for ReturnExpr {
type Output = Value;
- fn eval(&self, _: &mut Vm) -> TypResult<Self::Output> {
+ fn eval(&self, _: &mut Context, _: &mut Scopes) -> TypResult<Self::Output> {
Err("return is not yet implemented").at(self.span())
}
}
@@ -758,25 +761,25 @@ impl Eval for ReturnExpr {
/// This only works if the expression is a valid lvalue.
pub trait Access {
/// Try to access the value.
- fn access(&self, vm: &mut Vm, f: Handler) -> TypResult<()>;
+ fn access(&self, ctx: &mut Context, scp: &mut Scopes, f: Handler) -> TypResult<()>;
}
/// Process an accessed value.
type Handler<'a> = Box<dyn FnOnce(&mut Value) -> TypResult<()> + 'a>;
impl Access for Expr {
- fn access(&self, vm: &mut Vm, f: Handler) -> TypResult<()> {
+ fn access(&self, ctx: &mut Context, scp: &mut Scopes, f: Handler) -> TypResult<()> {
match self {
- Expr::Ident(ident) => ident.access(vm, f),
- Expr::Call(call) => call.access(vm, f),
+ Expr::Ident(ident) => ident.access(ctx, scp, f),
+ Expr::Call(call) => call.access(ctx, scp, f),
_ => bail!(self.span(), "cannot access this expression mutably"),
}
}
}
impl Access for Ident {
- fn access(&self, vm: &mut Vm, f: Handler) -> TypResult<()> {
- match vm.scopes.get(self) {
+ fn access(&self, _: &mut Context, scp: &mut Scopes, f: Handler) -> TypResult<()> {
+ match scp.get(self) {
Some(slot) => match slot.try_write() {
Ok(mut guard) => f(&mut guard),
Err(_) => bail!(self.span(), "cannot mutate a constant"),
@@ -787,10 +790,11 @@ impl Access for Ident {
}
impl Access for CallExpr {
- fn access(&self, vm: &mut Vm, f: Handler) -> TypResult<()> {
- let args = self.args().eval(vm)?;
+ fn access(&self, ctx: &mut Context, scp: &mut Scopes, f: Handler) -> TypResult<()> {
+ let args = self.args().eval(ctx, scp)?;
self.callee().access(
- vm,
+ ctx,
+ scp,
Box::new(|value| match value {
Value::Array(array) => {
f(array.get_mut(args.into_index()?).at(self.span())?)
diff --git a/src/eval/module.rs b/src/eval/module.rs
new file mode 100644
index 00000000..478c76b7
--- /dev/null
+++ b/src/eval/module.rs
@@ -0,0 +1,20 @@
+use super::{Scope, Template};
+use crate::source::{SourceId, SourceStore};
+
+/// An evaluated module, ready for importing or layouting.
+#[derive(Debug, Clone)]
+pub struct Module {
+ /// The top-level definitions that were bound in this module.
+ pub scope: Scope,
+ /// The module's layoutable contents.
+ pub template: Template,
+ /// The source file revisions this module depends on.
+ pub deps: Vec<(SourceId, usize)>,
+}
+
+impl Module {
+ /// Whether the module is still valid for the given sources.
+ pub fn valid(&self, sources: &SourceStore) -> bool {
+ self.deps.iter().all(|&(id, rev)| rev == sources.get(id).rev())
+ }
+}
diff --git a/src/eval/scope.rs b/src/eval/scope.rs
index 0df4c4df..e09d05c8 100644
--- a/src/eval/scope.rs
+++ b/src/eval/scope.rs
@@ -4,9 +4,10 @@ use std::hash::{Hash, Hasher};
use std::iter;
use std::sync::{Arc, RwLock};
-use super::{Args, Class, Construct, Func, Set, Value, Vm};
+use super::{Args, Class, Construct, Func, Set, Value};
use crate::diag::TypResult;
use crate::util::EcoString;
+use crate::Context;
/// A slot where a variable is stored.
pub type Slot = Arc<RwLock<Value>>;
@@ -86,7 +87,7 @@ impl Scope {
pub fn def_func(
&mut self,
name: &'static str,
- func: fn(&mut Vm, &mut Args) -> TypResult<Value>,
+ func: fn(&mut Context, &mut Args) -> TypResult<Value>,
) {
self.def_const(name, Func::native(name, func));
}
diff --git a/src/eval/show.rs b/src/eval/show.rs
index ac0e2378..b0fb8172 100644
--- a/src/eval/show.rs
+++ b/src/eval/show.rs
@@ -6,12 +6,12 @@ use std::sync::Arc;
use super::{StyleChain, Template};
use crate::diag::TypResult;
use crate::util::Prehashed;
-use crate::Vm;
+use crate::Context;
/// A node that can be realized given some styles.
pub trait Show {
/// Realize the template in the given styles.
- fn show(&self, vm: &mut Vm, styles: StyleChain) -> TypResult<Template>;
+ fn show(&self, ctx: &mut Context, styles: StyleChain) -> TypResult<Template>;
/// Convert to a packed show node.
fn pack(self) -> ShowNode
@@ -42,8 +42,8 @@ impl ShowNode {
}
impl Show for ShowNode {
- fn show(&self, vm: &mut Vm, styles: StyleChain) -> TypResult<Template> {
- self.0.show(vm, styles)
+ fn show(&self, ctx: &mut Context, styles: StyleChain) -> TypResult<Template> {
+ self.0.show(ctx, styles)
}
fn pack(self) -> ShowNode {
diff --git a/src/eval/styles.rs b/src/eval/styles.rs
index 346eb784..bd1f808f 100644
--- a/src/eval/styles.rs
+++ b/src/eval/styles.rs
@@ -3,9 +3,10 @@ use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::sync::Arc;
-use super::{Args, Func, Span, Template, Value, Vm};
+use super::{Args, Func, Span, Template, Value};
use crate::diag::{At, TypResult};
use crate::library::{PageNode, ParNode};
+use crate::Context;
/// A map of style properties.
#[derive(Default, Clone, PartialEq, Hash)]
@@ -341,11 +342,6 @@ impl<'a> StyleChain<'a> {
*self = self.outer.copied().unwrap_or_default();
}
- /// Return the span of a recipe for the given node.
- pub(crate) fn recipe_span(self, node: TypeId) -> Option<Span> {
- self.recipes(node).next().map(|recipe| recipe.span)
- }
-
/// Return the chain, but without the last link if that one contains only
/// scoped styles. This is a hack.
pub(crate) fn unscoped(mut self, node: TypeId) -> Self {
@@ -415,12 +411,12 @@ impl<'a> StyleChain<'a> {
pub fn show(
self,
node: &dyn Any,
- vm: &mut Vm,
+ ctx: &mut Context,
values: impl IntoIterator<Item = Value>,
) -> TypResult<Option<Template>> {
Ok(if let Some(recipe) = self.recipes(node.type_id()).next() {
let args = Args::from_values(recipe.span, values);
- Some(recipe.func.call(vm, args)?.cast().at(recipe.span)?)
+ Some(recipe.func.call(ctx, args)?.cast().at(recipe.span)?)
} else {
None
})
diff --git a/src/eval/template.rs b/src/eval/template.rs
index b4e3c76d..a9e1262f 100644
--- a/src/eval/template.rs
+++ b/src/eval/template.rs
@@ -1,7 +1,6 @@
use std::fmt::Debug;
use std::hash::Hash;
use std::iter::Sum;
-use std::mem;
use std::ops::{Add, AddAssign};
use typed_arena::Arena;
@@ -169,21 +168,23 @@ impl Template {
}
/// Layout this template into a collection of pages.
- pub fn layout_pages(&self, vm: &mut Vm) -> TypResult<Vec<Arc<Frame>>> {
+ pub fn layout(&self, ctx: &mut Context) -> TypResult<Vec<Arc<Frame>>> {
let sya = Arena::new();
let tpa = Arena::new();
+ let styles = ctx.styles.clone();
+ let styles = StyleChain::new(&styles);
+
let mut builder = Builder::new(&sya, &tpa, true);
- let styles = StyleChain::new(vm.styles);
- builder.process(vm, self, styles)?;
- builder.finish(vm, styles)?;
+ builder.process(ctx, self, styles)?;
+ builder.finish(ctx, styles)?;
let mut frames = vec![];
let (pages, shared) = builder.pages.unwrap().finish();
for (page, map) in pages.iter() {
let number = 1 + frames.len();
- frames.extend(page.layout(vm, number, map.chain(&shared))?);
+ frames.extend(page.layout(ctx, number, map.chain(&shared))?);
}
Ok(frames)
@@ -224,7 +225,7 @@ impl Add for Template {
impl AddAssign for Template {
fn add_assign(&mut self, rhs: Self) {
- *self = mem::take(self) + rhs;
+ *self = std::mem::take(self) + rhs;
}
}
@@ -237,7 +238,7 @@ impl Sum for Template {
impl Layout for Template {
fn layout(
&self,
- vm: &mut Vm,
+ ctx: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
@@ -245,11 +246,11 @@ impl Layout for Template {
let tpa = Arena::new();
let mut builder = Builder::new(&sya, &tpa, false);
- builder.process(vm, self, styles)?;
- builder.finish(vm, styles)?;
+ builder.process(ctx, self, styles)?;
+ builder.finish(ctx, styles)?;
let (flow, shared) = builder.flow.finish();
- FlowNode(flow).layout(vm, regions, shared)
+ FlowNode(flow).layout(ctx, regions, shared)
}
fn pack(self) -> LayoutNode {
@@ -295,7 +296,7 @@ impl<'a> Builder<'a> {
/// Process a template.
fn process(
&mut self,
- vm: &mut Vm,
+ ctx: &mut Context,
template: &'a Template,
styles: StyleChain<'a>,
) -> TypResult<()> {
@@ -323,7 +324,7 @@ impl<'a> Builder<'a> {
builder.items.push(item.clone());
return Ok(());
}
- _ => self.finish_list(vm)?,
+ _ => self.finish_list(ctx)?,
}
}
@@ -394,25 +395,19 @@ impl<'a> Builder<'a> {
});
}
Template::Pagebreak => {
- self.finish_page(vm, true, true, styles)?;
+ self.finish_page(ctx, true, true, styles)?;
}
Template::Page(page) => {
- self.finish_page(vm, false, false, styles)?;
+ self.finish_page(ctx, false, false, styles)?;
if let Some(pages) = &mut self.pages {
pages.push(page.clone(), styles);
}
}
Template::Show(node) => {
let id = node.id();
- if vm.rules.contains(&id) {
- let span = styles.recipe_span(id).unwrap();
- return Err("show rule is recursive").at(span)?;
- }
- vm.rules.push(id);
- let template = node.show(vm, styles)?;
+ let template = node.show(ctx, styles)?;
let stored = self.tpa.alloc(template);
- self.process(vm, stored, styles.unscoped(id))?;
- vm.rules.pop();
+ self.process(ctx, stored, styles.unscoped(id))?;
}
Template::Styled(styled) => {
let (sub, map) = styled.as_ref();
@@ -422,17 +417,17 @@ impl<'a> Builder<'a> {
let interruption = map.interruption();
match interruption {
Some(Interruption::Page) => {
- self.finish_page(vm, false, true, styles)?
+ self.finish_page(ctx, false, true, styles)?
}
Some(Interruption::Par) => self.finish_par(styles),
None => {}
}
- self.process(vm, sub, styles)?;
+ self.process(ctx, sub, styles)?;
match interruption {
Some(Interruption::Page) => {
- self.finish_page(vm, true, false, styles)?
+ self.finish_page(ctx, true, false, styles)?
}
Some(Interruption::Par) => self.finish_par(styles),
None => {}
@@ -440,7 +435,7 @@ impl<'a> Builder<'a> {
}
Template::Sequence(seq) => {
for sub in seq.iter() {
- self.process(vm, sub, styles)?;
+ self.process(ctx, sub, styles)?;
}
}
}
@@ -450,7 +445,7 @@ impl<'a> Builder<'a> {
/// Finish the currently built paragraph.
fn finish_par(&mut self, styles: StyleChain<'a>) {
- let (par, shared) = mem::take(&mut self.par).finish();
+ let (par, shared) = std::mem::take(&mut self.par).finish();
if !par.is_empty() {
let node = ParNode(par).pack();
self.flow.supportive(FlowChild::Node(node), shared);
@@ -459,7 +454,7 @@ impl<'a> Builder<'a> {
}
/// Finish the currently built list.
- fn finish_list(&mut self, vm: &mut Vm) -> TypResult<()> {
+ fn finish_list(&mut self, ctx: &mut Context) -> TypResult<()> {
let ListBuilder { styles, kind, items, wide, staged } = match self.list.take() {
Some(list) => list,
None => return Ok(()),
@@ -471,9 +466,9 @@ impl<'a> Builder<'a> {
};
let stored = self.tpa.alloc(template);
- self.process(vm, stored, styles)?;
+ self.process(ctx, stored, styles)?;
for (template, styles) in staged {
- self.process(vm, template, styles)?;
+ self.process(ctx, template, styles)?;
}
Ok(())
@@ -482,15 +477,15 @@ impl<'a> Builder<'a> {
/// Finish the currently built page run.
fn finish_page(
&mut self,
- vm: &mut Vm,
+ ctx: &mut Context,
keep_last: bool,
keep_next: bool,
styles: StyleChain<'a>,
) -> TypResult<()> {
- self.finish_list(vm)?;
+ self.finish_list(ctx)?;
self.finish_par(styles);
if let Some(pages) = &mut self.pages {
- let (flow, shared) = mem::take(&mut self.flow).finish();
+ let (flow, shared) = std::mem::take(&mut self.flow).finish();
if !flow.is_empty() || (keep_last && self.keep_next) {
let styles = if flow.is_empty() { styles } else { shared };
let node = PageNode(FlowNode(flow).pack());
@@ -502,8 +497,8 @@ impl<'a> Builder<'a> {
}
/// Finish everything.
- fn finish(&mut self, vm: &mut Vm, styles: StyleChain<'a>) -> TypResult<()> {
- self.finish_page(vm, true, false, styles)
+ fn finish(&mut self, ctx: &mut Context, styles: StyleChain<'a>) -> TypResult<()> {
+ self.finish_page(ctx, true, false, styles)
}
}