mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Merge eval and layout contexts into Vm
This commit is contained in:
parent
3d965ae6a4
commit
c5e67af22b
@ -5,7 +5,7 @@ use iai::{black_box, main, Iai};
|
|||||||
use typst::loading::MemLoader;
|
use typst::loading::MemLoader;
|
||||||
use typst::parse::{parse, Scanner, TokenMode, Tokens};
|
use typst::parse::{parse, Scanner, TokenMode, Tokens};
|
||||||
use typst::source::SourceId;
|
use typst::source::SourceId;
|
||||||
use typst::Context;
|
use typst::{Context, Vm};
|
||||||
|
|
||||||
const SRC: &str = include_str!("bench.typ");
|
const SRC: &str = include_str!("bench.typ");
|
||||||
const FONT: &[u8] = include_bytes!("../fonts/IBMPlexSans-Regular.ttf");
|
const FONT: &[u8] = include_bytes!("../fonts/IBMPlexSans-Regular.ttf");
|
||||||
@ -69,13 +69,15 @@ fn bench_edit(iai: &mut Iai) {
|
|||||||
|
|
||||||
fn bench_eval(iai: &mut Iai) {
|
fn bench_eval(iai: &mut Iai) {
|
||||||
let (mut ctx, id) = context();
|
let (mut ctx, id) = context();
|
||||||
iai.run(|| ctx.evaluate(id).unwrap());
|
let mut vm = Vm::new(&mut ctx);
|
||||||
|
iai.run(|| vm.evaluate(id).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_layout(iai: &mut Iai) {
|
fn bench_layout(iai: &mut Iai) {
|
||||||
let (mut ctx, id) = context();
|
let (mut ctx, id) = context();
|
||||||
let module = ctx.evaluate(id).unwrap();
|
let mut vm = Vm::new(&mut ctx);
|
||||||
iai.run(|| module.template.layout(&mut ctx));
|
let module = vm.evaluate(id).unwrap();
|
||||||
|
iai.run(|| module.template.layout(&mut vm));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_highlight(iai: &mut Iai) {
|
fn bench_highlight(iai: &mut Iai) {
|
||||||
|
@ -28,7 +28,7 @@ impl<'a> CapturesVisitor<'a> {
|
|||||||
|
|
||||||
/// Bind a new internal variable.
|
/// Bind a new internal variable.
|
||||||
pub fn bind(&mut self, ident: Ident) {
|
pub fn bind(&mut self, ident: Ident) {
|
||||||
self.internal.def_mut(ident.take(), Value::None);
|
self.internal.top.def_mut(ident.take(), Value::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Capture a variable if it isn't internal.
|
/// Capture a variable if it isn't internal.
|
||||||
@ -135,9 +135,9 @@ mod tests {
|
|||||||
let red = RedNode::from_root(green, SourceId::from_raw(0));
|
let red = RedNode::from_root(green, SourceId::from_raw(0));
|
||||||
|
|
||||||
let mut scopes = Scopes::new(None);
|
let mut scopes = Scopes::new(None);
|
||||||
scopes.def_const("x", 0);
|
scopes.top.def_const("x", 0);
|
||||||
scopes.def_const("y", 0);
|
scopes.top.def_const("y", 0);
|
||||||
scopes.def_const("z", 0);
|
scopes.top.def_const("z", 0);
|
||||||
|
|
||||||
let mut visitor = CapturesVisitor::new(&scopes);
|
let mut visitor = CapturesVisitor::new(&scopes);
|
||||||
visitor.visit(red.as_ref());
|
visitor.visit(red.as_ref());
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::fmt::{self, Debug, Formatter, Write};
|
use std::fmt::{self, Debug, Formatter, Write};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
use super::{Args, EvalContext, Func, StyleMap, Template, Value};
|
use super::{Args, Func, StyleMap, Template, Value, Vm};
|
||||||
use crate::diag::TypResult;
|
use crate::diag::TypResult;
|
||||||
|
|
||||||
/// A class of nodes.
|
/// A class of nodes.
|
||||||
@ -36,7 +36,7 @@ use crate::diag::TypResult;
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Class {
|
pub struct Class {
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
construct: fn(&mut EvalContext, &mut Args) -> TypResult<Value>,
|
construct: fn(&mut Vm, &mut Args) -> TypResult<Value>,
|
||||||
set: fn(&mut Args, &mut StyleMap) -> TypResult<()>,
|
set: fn(&mut Args, &mut StyleMap) -> TypResult<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,8 +73,8 @@ impl Class {
|
|||||||
/// This parses both property and data arguments (in this order), styles the
|
/// This parses both property and data arguments (in this order), styles the
|
||||||
/// template constructed from the data with the style properties and wraps
|
/// template constructed from the data with the style properties and wraps
|
||||||
/// it in a value.
|
/// it in a value.
|
||||||
pub fn construct(&self, ctx: &mut EvalContext, mut args: Args) -> TypResult<Value> {
|
pub fn construct(&self, vm: &mut Vm, mut args: Args) -> TypResult<Value> {
|
||||||
let value = (self.construct)(ctx, &mut args)?;
|
let value = (self.construct)(vm, &mut args)?;
|
||||||
args.finish()?;
|
args.finish()?;
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
@ -117,7 +117,7 @@ pub trait Construct {
|
|||||||
///
|
///
|
||||||
/// This is passed only the arguments that remain after execution of the
|
/// This is passed only the arguments that remain after execution of the
|
||||||
/// class's set rule.
|
/// class's set rule.
|
||||||
fn construct(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Template>;
|
fn construct(vm: &mut Vm, args: &mut Args) -> TypResult<Template>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set style properties of a class.
|
/// Set style properties of a class.
|
||||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Debug, Formatter, Write};
|
|||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use super::{Cast, Eval, EvalContext, Scope, Value};
|
use super::{Cast, Eval, Scope, Value, Vm};
|
||||||
use crate::diag::{At, TypResult};
|
use crate::diag::{At, TypResult};
|
||||||
use crate::syntax::ast::Expr;
|
use crate::syntax::ast::Expr;
|
||||||
use crate::syntax::{Span, Spanned};
|
use crate::syntax::{Span, Spanned};
|
||||||
@ -27,7 +27,7 @@ impl Func {
|
|||||||
/// Create a new function from a native rust function.
|
/// Create a new function from a native rust function.
|
||||||
pub fn native(
|
pub fn native(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
func: fn(&mut EvalContext, &mut Args) -> TypResult<Value>,
|
func: fn(&mut Vm, &mut Args) -> TypResult<Value>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self(Arc::new(Repr::Native(Native { name, func })))
|
Self(Arc::new(Repr::Native(Native { name, func })))
|
||||||
}
|
}
|
||||||
@ -47,13 +47,13 @@ impl Func {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Call the function in the context with the arguments.
|
/// Call the function in the context with the arguments.
|
||||||
pub fn call(&self, ctx: &mut EvalContext, mut args: Args) -> TypResult<Value> {
|
pub fn call(&self, vm: &mut Vm, mut args: Args) -> TypResult<Value> {
|
||||||
let value = match self.0.as_ref() {
|
let value = match self.0.as_ref() {
|
||||||
Repr::Native(native) => (native.func)(ctx, &mut args)?,
|
Repr::Native(native) => (native.func)(vm, &mut args)?,
|
||||||
Repr::Closure(closure) => closure.call(ctx, &mut args)?,
|
Repr::Closure(closure) => closure.call(vm, &mut args)?,
|
||||||
Repr::With(wrapped, applied) => {
|
Repr::With(wrapped, applied) => {
|
||||||
args.items.splice(.. 0, applied.items.iter().cloned());
|
args.items.splice(.. 0, applied.items.iter().cloned());
|
||||||
return wrapped.call(ctx, args);
|
return wrapped.call(vm, args);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
args.finish()?;
|
args.finish()?;
|
||||||
@ -88,7 +88,7 @@ struct Native {
|
|||||||
/// The name of the function.
|
/// The name of the function.
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
/// The function pointer.
|
/// The function pointer.
|
||||||
pub func: fn(&mut EvalContext, &mut Args) -> TypResult<Value>,
|
pub func: fn(&mut Vm, &mut Args) -> TypResult<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for Native {
|
impl Hash for Native {
|
||||||
@ -115,15 +115,15 @@ pub struct Closure {
|
|||||||
|
|
||||||
impl Closure {
|
impl Closure {
|
||||||
/// Call the function in the context with the arguments.
|
/// Call the function in the context with the arguments.
|
||||||
pub fn call(&self, ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn call(&self, vm: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
// Don't leak the scopes from the call site. Instead, we use the
|
// Don't leak the scopes from the call site. Instead, we use the
|
||||||
// scope of captured variables we collected earlier.
|
// scope of captured variables we collected earlier.
|
||||||
let prev_scopes = std::mem::take(&mut ctx.scopes);
|
let prev_scopes = std::mem::take(&mut vm.scopes);
|
||||||
ctx.scopes.top = self.captured.clone();
|
vm.scopes.top = self.captured.clone();
|
||||||
|
|
||||||
// Parse the arguments according to the parameter list.
|
// Parse the arguments according to the parameter list.
|
||||||
for (param, default) in &self.params {
|
for (param, default) in &self.params {
|
||||||
ctx.scopes.def_mut(param, match default {
|
vm.scopes.top.def_mut(param, match default {
|
||||||
None => args.expect::<Value>(param)?,
|
None => args.expect::<Value>(param)?,
|
||||||
Some(default) => {
|
Some(default) => {
|
||||||
args.named::<Value>(param)?.unwrap_or_else(|| default.clone())
|
args.named::<Value>(param)?.unwrap_or_else(|| default.clone())
|
||||||
@ -133,14 +133,14 @@ impl Closure {
|
|||||||
|
|
||||||
// Put the remaining arguments into the sink.
|
// Put the remaining arguments into the sink.
|
||||||
if let Some(sink) = &self.sink {
|
if let Some(sink) = &self.sink {
|
||||||
ctx.scopes.def_mut(sink, args.take());
|
vm.scopes.top.def_mut(sink, args.take());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate the body.
|
// Evaluate the body.
|
||||||
let value = self.body.eval(ctx)?;
|
let value = self.body.eval(vm)?;
|
||||||
|
|
||||||
// Restore the call site scopes.
|
// Restore the call site scopes.
|
||||||
ctx.scopes = prev_scopes;
|
vm.scopes = prev_scopes;
|
||||||
|
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
427
src/eval/mod.rs
427
src/eval/mod.rs
@ -29,24 +29,19 @@ pub use styles::*;
|
|||||||
pub use template::*;
|
pub use template::*;
|
||||||
pub use value::*;
|
pub use value::*;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
use crate::diag::{At, Error, StrResult, Trace, Tracepoint, TypResult};
|
use crate::diag::{At, Error, StrResult, Trace, Tracepoint, TypResult};
|
||||||
use crate::geom::{Angle, Fractional, Length, Relative};
|
use crate::geom::{Angle, Fractional, Length, Relative};
|
||||||
use crate::image::ImageStore;
|
|
||||||
use crate::layout::Layout;
|
use crate::layout::Layout;
|
||||||
use crate::library::{self, ORDERED, UNORDERED};
|
use crate::library::{self, ORDERED, UNORDERED};
|
||||||
use crate::loading::Loader;
|
|
||||||
use crate::source::{SourceId, SourceStore};
|
|
||||||
use crate::syntax::ast::*;
|
use crate::syntax::ast::*;
|
||||||
use crate::syntax::{Span, Spanned};
|
use crate::syntax::{Span, Spanned};
|
||||||
use crate::util::EcoString;
|
use crate::util::EcoString;
|
||||||
use crate::Context;
|
use crate::Vm;
|
||||||
|
|
||||||
/// An evaluated module, ready for importing or conversion to a root layout
|
/// An evaluated module, ready for importing or conversion to a root layout
|
||||||
/// tree.
|
/// tree.
|
||||||
@ -64,106 +59,20 @@ pub trait Eval {
|
|||||||
type Output;
|
type Output;
|
||||||
|
|
||||||
/// Evaluate the expression to the output value.
|
/// Evaluate the expression to the output value.
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output>;
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output>;
|
||||||
}
|
|
||||||
|
|
||||||
/// The context for evaluation.
|
|
||||||
pub struct EvalContext<'a> {
|
|
||||||
/// The loader from which resources (files and images) are loaded.
|
|
||||||
pub loader: &'a dyn Loader,
|
|
||||||
/// Stores loaded source files.
|
|
||||||
pub sources: &'a mut SourceStore,
|
|
||||||
/// Stores decoded images.
|
|
||||||
pub images: &'a mut ImageStore,
|
|
||||||
/// The stack of imported files that led to evaluation of the current file.
|
|
||||||
pub route: Vec<SourceId>,
|
|
||||||
/// Caches imported modules.
|
|
||||||
pub modules: HashMap<SourceId, Module>,
|
|
||||||
/// The active scopes.
|
|
||||||
pub scopes: Scopes<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> EvalContext<'a> {
|
|
||||||
/// Create a new evaluation context.
|
|
||||||
pub fn new(ctx: &'a mut Context, source: SourceId) -> Self {
|
|
||||||
Self {
|
|
||||||
loader: ctx.loader.as_ref(),
|
|
||||||
sources: &mut ctx.sources,
|
|
||||||
images: &mut ctx.images,
|
|
||||||
route: vec![source],
|
|
||||||
modules: HashMap::new(),
|
|
||||||
scopes: Scopes::new(Some(&ctx.std)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Process an import of a module relative to the current location.
|
|
||||||
pub fn import(&mut self, path: &str, span: Span) -> TypResult<SourceId> {
|
|
||||||
// Load the source file.
|
|
||||||
let full = self.make_path(path);
|
|
||||||
let id = self.sources.load(&full).map_err(|err| {
|
|
||||||
Error::boxed(span, match err.kind() {
|
|
||||||
io::ErrorKind::NotFound => "file not found".into(),
|
|
||||||
_ => format!("failed to load source file ({})", err),
|
|
||||||
})
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// Prevent cyclic importing.
|
|
||||||
if self.route.contains(&id) {
|
|
||||||
bail!(span, "cyclic import");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check whether the module was already loaded.
|
|
||||||
if self.modules.get(&id).is_some() {
|
|
||||||
return Ok(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the file.
|
|
||||||
let source = self.sources.get(id);
|
|
||||||
let ast = source.ast()?;
|
|
||||||
|
|
||||||
// Prepare the new context.
|
|
||||||
let new_scopes = Scopes::new(self.scopes.base);
|
|
||||||
let prev_scopes = mem::replace(&mut self.scopes, new_scopes);
|
|
||||||
self.route.push(id);
|
|
||||||
|
|
||||||
// Evaluate the module.
|
|
||||||
let template = ast.eval(self).trace(|| Tracepoint::Import, span)?;
|
|
||||||
|
|
||||||
// Restore the old context.
|
|
||||||
let new_scopes = mem::replace(&mut self.scopes, prev_scopes);
|
|
||||||
self.route.pop().unwrap();
|
|
||||||
|
|
||||||
// Save the evaluated module.
|
|
||||||
let module = Module { scope: new_scopes.top, template };
|
|
||||||
self.modules.insert(id, module);
|
|
||||||
|
|
||||||
Ok(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Complete a user-entered path (relative to the source file) to be
|
|
||||||
/// relative to the compilation environment's root.
|
|
||||||
pub fn make_path(&self, path: &str) -> PathBuf {
|
|
||||||
if let Some(&id) = self.route.last() {
|
|
||||||
if let Some(dir) = self.sources.get(id).path().parent() {
|
|
||||||
return dir.join(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
path.into()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for Markup {
|
impl Eval for Markup {
|
||||||
type Output = Template;
|
type Output = Template;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
eval_markup(ctx, &mut self.nodes())
|
eval_markup(vm, &mut self.nodes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a stream of markup nodes.
|
/// Evaluate a stream of markup nodes.
|
||||||
fn eval_markup(
|
fn eval_markup(
|
||||||
ctx: &mut EvalContext,
|
vm: &mut Vm,
|
||||||
nodes: &mut impl Iterator<Item = MarkupNode>,
|
nodes: &mut impl Iterator<Item = MarkupNode>,
|
||||||
) -> TypResult<Template> {
|
) -> TypResult<Template> {
|
||||||
let mut seq = Vec::with_capacity(nodes.size_hint().1.unwrap_or_default());
|
let mut seq = Vec::with_capacity(nodes.size_hint().1.unwrap_or_default());
|
||||||
@ -172,21 +81,21 @@ fn eval_markup(
|
|||||||
seq.push(match node {
|
seq.push(match node {
|
||||||
MarkupNode::Expr(Expr::Set(set)) => {
|
MarkupNode::Expr(Expr::Set(set)) => {
|
||||||
let class = set.class();
|
let class = set.class();
|
||||||
let class = class.eval(ctx)?.cast::<Class>().at(class.span())?;
|
let class = class.eval(vm)?.cast::<Class>().at(class.span())?;
|
||||||
let args = set.args().eval(ctx)?;
|
let args = set.args().eval(vm)?;
|
||||||
let styles = class.set(args)?;
|
let styles = class.set(args)?;
|
||||||
let tail = eval_markup(ctx, nodes)?;
|
let tail = eval_markup(vm, nodes)?;
|
||||||
tail.styled_with_map(styles)
|
tail.styled_with_map(styles)
|
||||||
}
|
}
|
||||||
MarkupNode::Expr(Expr::Show(show)) => {
|
MarkupNode::Expr(Expr::Show(show)) => {
|
||||||
return Err("show rules are not yet implemented").at(show.span());
|
return Err("show rules are not yet implemented").at(show.span());
|
||||||
}
|
}
|
||||||
MarkupNode::Expr(Expr::Wrap(wrap)) => {
|
MarkupNode::Expr(Expr::Wrap(wrap)) => {
|
||||||
let tail = eval_markup(ctx, nodes)?;
|
let tail = eval_markup(vm, nodes)?;
|
||||||
ctx.scopes.def_mut(wrap.binding().take(), tail);
|
vm.scopes.top.def_mut(wrap.binding().take(), tail);
|
||||||
wrap.body().eval(ctx)?.display()
|
wrap.body().eval(vm)?.display()
|
||||||
}
|
}
|
||||||
_ => node.eval(ctx)?,
|
_ => node.eval(vm)?,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,20 +105,20 @@ fn eval_markup(
|
|||||||
impl Eval for MarkupNode {
|
impl Eval for MarkupNode {
|
||||||
type Output = Template;
|
type Output = Template;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
Ok(match self {
|
Ok(match self {
|
||||||
Self::Space => Template::Space,
|
Self::Space => Template::Space,
|
||||||
Self::Linebreak => Template::Linebreak,
|
Self::Linebreak => Template::Linebreak,
|
||||||
Self::Parbreak => Template::Parbreak,
|
Self::Parbreak => Template::Parbreak,
|
||||||
Self::Text(text) => Template::Text(text.clone()),
|
Self::Text(text) => Template::Text(text.clone()),
|
||||||
Self::Strong(strong) => strong.eval(ctx)?,
|
Self::Strong(strong) => strong.eval(vm)?,
|
||||||
Self::Emph(emph) => emph.eval(ctx)?,
|
Self::Emph(emph) => emph.eval(vm)?,
|
||||||
Self::Raw(raw) => raw.eval(ctx)?,
|
Self::Raw(raw) => raw.eval(vm)?,
|
||||||
Self::Math(math) => math.eval(ctx)?,
|
Self::Math(math) => math.eval(vm)?,
|
||||||
Self::Heading(heading) => heading.eval(ctx)?,
|
Self::Heading(heading) => heading.eval(vm)?,
|
||||||
Self::List(list) => list.eval(ctx)?,
|
Self::List(list) => list.eval(vm)?,
|
||||||
Self::Enum(enum_) => enum_.eval(ctx)?,
|
Self::Enum(enum_) => enum_.eval(vm)?,
|
||||||
Self::Expr(expr) => expr.eval(ctx)?.display(),
|
Self::Expr(expr) => expr.eval(vm)?.display(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -217,23 +126,23 @@ impl Eval for MarkupNode {
|
|||||||
impl Eval for StrongNode {
|
impl Eval for StrongNode {
|
||||||
type Output = Template;
|
type Output = Template;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
Ok(Template::show(library::StrongNode(self.body().eval(ctx)?)))
|
Ok(Template::show(library::StrongNode(self.body().eval(vm)?)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for EmphNode {
|
impl Eval for EmphNode {
|
||||||
type Output = Template;
|
type Output = Template;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
Ok(Template::show(library::EmphNode(self.body().eval(ctx)?)))
|
Ok(Template::show(library::EmphNode(self.body().eval(vm)?)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for RawNode {
|
impl Eval for RawNode {
|
||||||
type Output = Template;
|
type Output = Template;
|
||||||
|
|
||||||
fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, _: &mut Vm) -> TypResult<Self::Output> {
|
||||||
let template = Template::show(library::RawNode {
|
let template = Template::show(library::RawNode {
|
||||||
text: self.text.clone(),
|
text: self.text.clone(),
|
||||||
block: self.block,
|
block: self.block,
|
||||||
@ -248,7 +157,7 @@ impl Eval for RawNode {
|
|||||||
impl Eval for MathNode {
|
impl Eval for MathNode {
|
||||||
type Output = Template;
|
type Output = Template;
|
||||||
|
|
||||||
fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, _: &mut Vm) -> TypResult<Self::Output> {
|
||||||
Ok(Template::show(library::MathNode {
|
Ok(Template::show(library::MathNode {
|
||||||
formula: self.formula.clone(),
|
formula: self.formula.clone(),
|
||||||
display: self.display,
|
display: self.display,
|
||||||
@ -259,9 +168,9 @@ impl Eval for MathNode {
|
|||||||
impl Eval for HeadingNode {
|
impl Eval for HeadingNode {
|
||||||
type Output = Template;
|
type Output = Template;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
Ok(Template::show(library::HeadingNode {
|
Ok(Template::show(library::HeadingNode {
|
||||||
body: self.body().eval(ctx)?,
|
body: self.body().eval(vm)?,
|
||||||
level: self.level(),
|
level: self.level(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -270,10 +179,10 @@ impl Eval for HeadingNode {
|
|||||||
impl Eval for ListNode {
|
impl Eval for ListNode {
|
||||||
type Output = Template;
|
type Output = Template;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
Ok(Template::show(library::ListNode::<UNORDERED> {
|
Ok(Template::show(library::ListNode::<UNORDERED> {
|
||||||
number: None,
|
number: None,
|
||||||
child: self.body().eval(ctx)?.pack(),
|
child: self.body().eval(vm)?.pack(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -281,10 +190,10 @@ impl Eval for ListNode {
|
|||||||
impl Eval for EnumNode {
|
impl Eval for EnumNode {
|
||||||
type Output = Template;
|
type Output = Template;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
Ok(Template::show(library::ListNode::<ORDERED> {
|
Ok(Template::show(library::ListNode::<ORDERED> {
|
||||||
number: self.number(),
|
number: self.number(),
|
||||||
child: self.body().eval(ctx)?.pack(),
|
child: self.body().eval(vm)?.pack(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,32 +201,32 @@ impl Eval for EnumNode {
|
|||||||
impl Eval for Expr {
|
impl Eval for Expr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
match self {
|
match self {
|
||||||
Self::Lit(v) => v.eval(ctx),
|
Self::Lit(v) => v.eval(vm),
|
||||||
Self::Ident(v) => v.eval(ctx),
|
Self::Ident(v) => v.eval(vm),
|
||||||
Self::Array(v) => v.eval(ctx).map(Value::Array),
|
Self::Array(v) => v.eval(vm).map(Value::Array),
|
||||||
Self::Dict(v) => v.eval(ctx).map(Value::Dict),
|
Self::Dict(v) => v.eval(vm).map(Value::Dict),
|
||||||
Self::Template(v) => v.eval(ctx).map(Value::Template),
|
Self::Template(v) => v.eval(vm).map(Value::Template),
|
||||||
Self::Group(v) => v.eval(ctx),
|
Self::Group(v) => v.eval(vm),
|
||||||
Self::Block(v) => v.eval(ctx),
|
Self::Block(v) => v.eval(vm),
|
||||||
Self::Call(v) => v.eval(ctx),
|
Self::Call(v) => v.eval(vm),
|
||||||
Self::Closure(v) => v.eval(ctx),
|
Self::Closure(v) => v.eval(vm),
|
||||||
Self::With(v) => v.eval(ctx),
|
Self::With(v) => v.eval(vm),
|
||||||
Self::Unary(v) => v.eval(ctx),
|
Self::Unary(v) => v.eval(vm),
|
||||||
Self::Binary(v) => v.eval(ctx),
|
Self::Binary(v) => v.eval(vm),
|
||||||
Self::Let(v) => v.eval(ctx),
|
Self::Let(v) => v.eval(vm),
|
||||||
Self::Set(v) => v.eval(ctx),
|
Self::Set(v) => v.eval(vm),
|
||||||
Self::Show(v) => v.eval(ctx),
|
Self::Show(v) => v.eval(vm),
|
||||||
Self::Wrap(v) => v.eval(ctx),
|
Self::Wrap(v) => v.eval(vm),
|
||||||
Self::If(v) => v.eval(ctx),
|
Self::If(v) => v.eval(vm),
|
||||||
Self::While(v) => v.eval(ctx),
|
Self::While(v) => v.eval(vm),
|
||||||
Self::For(v) => v.eval(ctx),
|
Self::For(v) => v.eval(vm),
|
||||||
Self::Import(v) => v.eval(ctx),
|
Self::Import(v) => v.eval(vm),
|
||||||
Self::Include(v) => v.eval(ctx),
|
Self::Include(v) => v.eval(vm),
|
||||||
Self::Break(v) => v.eval(ctx),
|
Self::Break(v) => v.eval(vm),
|
||||||
Self::Continue(v) => v.eval(ctx),
|
Self::Continue(v) => v.eval(vm),
|
||||||
Self::Return(v) => v.eval(ctx),
|
Self::Return(v) => v.eval(vm),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -325,7 +234,7 @@ impl Eval for Expr {
|
|||||||
impl Eval for Lit {
|
impl Eval for Lit {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, _: &mut Vm) -> TypResult<Self::Output> {
|
||||||
Ok(match self.kind() {
|
Ok(match self.kind() {
|
||||||
LitKind::None => Value::None,
|
LitKind::None => Value::None,
|
||||||
LitKind::Auto => Value::Auto,
|
LitKind::Auto => Value::Auto,
|
||||||
@ -344,8 +253,8 @@ impl Eval for Lit {
|
|||||||
impl Eval for Ident {
|
impl Eval for Ident {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
match ctx.scopes.get(self) {
|
match vm.scopes.get(self) {
|
||||||
Some(slot) => Ok(slot.read().unwrap().clone()),
|
Some(slot) => Ok(slot.read().unwrap().clone()),
|
||||||
None => bail!(self.span(), "unknown variable"),
|
None => bail!(self.span(), "unknown variable"),
|
||||||
}
|
}
|
||||||
@ -355,17 +264,17 @@ impl Eval for Ident {
|
|||||||
impl Eval for ArrayExpr {
|
impl Eval for ArrayExpr {
|
||||||
type Output = Array;
|
type Output = Array;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
self.items().map(|expr| expr.eval(ctx)).collect()
|
self.items().map(|expr| expr.eval(vm)).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for DictExpr {
|
impl Eval for DictExpr {
|
||||||
type Output = Dict;
|
type Output = Dict;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
self.items()
|
self.items()
|
||||||
.map(|x| Ok((x.name().take(), x.expr().eval(ctx)?)))
|
.map(|x| Ok((x.name().take(), x.expr().eval(vm)?)))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -373,10 +282,10 @@ impl Eval for DictExpr {
|
|||||||
impl Eval for TemplateExpr {
|
impl Eval for TemplateExpr {
|
||||||
type Output = Template;
|
type Output = Template;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
ctx.scopes.enter();
|
vm.scopes.enter();
|
||||||
let template = self.body().eval(ctx)?;
|
let template = self.body().eval(vm)?;
|
||||||
ctx.scopes.exit();
|
vm.scopes.exit();
|
||||||
Ok(template)
|
Ok(template)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -384,24 +293,24 @@ impl Eval for TemplateExpr {
|
|||||||
impl Eval for GroupExpr {
|
impl Eval for GroupExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
self.expr().eval(ctx)
|
self.expr().eval(vm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for BlockExpr {
|
impl Eval for BlockExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
ctx.scopes.enter();
|
vm.scopes.enter();
|
||||||
|
|
||||||
let mut output = Value::None;
|
let mut output = Value::None;
|
||||||
for expr in self.exprs() {
|
for expr in self.exprs() {
|
||||||
let value = expr.eval(ctx)?;
|
let value = expr.eval(vm)?;
|
||||||
output = ops::join(output, value).at(expr.span())?;
|
output = ops::join(output, value).at(expr.span())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.scopes.exit();
|
vm.scopes.exit();
|
||||||
|
|
||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
@ -410,8 +319,8 @@ impl Eval for BlockExpr {
|
|||||||
impl Eval for UnaryExpr {
|
impl Eval for UnaryExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
let value = self.expr().eval(ctx)?;
|
let value = self.expr().eval(vm)?;
|
||||||
let result = match self.op() {
|
let result = match self.op() {
|
||||||
UnOp::Pos => ops::pos(value),
|
UnOp::Pos => ops::pos(value),
|
||||||
UnOp::Neg => ops::neg(value),
|
UnOp::Neg => ops::neg(value),
|
||||||
@ -424,25 +333,25 @@ impl Eval for UnaryExpr {
|
|||||||
impl Eval for BinaryExpr {
|
impl Eval for BinaryExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
match self.op() {
|
match self.op() {
|
||||||
BinOp::Add => self.apply(ctx, ops::add),
|
BinOp::Add => self.apply(vm, ops::add),
|
||||||
BinOp::Sub => self.apply(ctx, ops::sub),
|
BinOp::Sub => self.apply(vm, ops::sub),
|
||||||
BinOp::Mul => self.apply(ctx, ops::mul),
|
BinOp::Mul => self.apply(vm, ops::mul),
|
||||||
BinOp::Div => self.apply(ctx, ops::div),
|
BinOp::Div => self.apply(vm, ops::div),
|
||||||
BinOp::And => self.apply(ctx, ops::and),
|
BinOp::And => self.apply(vm, ops::and),
|
||||||
BinOp::Or => self.apply(ctx, ops::or),
|
BinOp::Or => self.apply(vm, ops::or),
|
||||||
BinOp::Eq => self.apply(ctx, ops::eq),
|
BinOp::Eq => self.apply(vm, ops::eq),
|
||||||
BinOp::Neq => self.apply(ctx, ops::neq),
|
BinOp::Neq => self.apply(vm, ops::neq),
|
||||||
BinOp::Lt => self.apply(ctx, ops::lt),
|
BinOp::Lt => self.apply(vm, ops::lt),
|
||||||
BinOp::Leq => self.apply(ctx, ops::leq),
|
BinOp::Leq => self.apply(vm, ops::leq),
|
||||||
BinOp::Gt => self.apply(ctx, ops::gt),
|
BinOp::Gt => self.apply(vm, ops::gt),
|
||||||
BinOp::Geq => self.apply(ctx, ops::geq),
|
BinOp::Geq => self.apply(vm, ops::geq),
|
||||||
BinOp::Assign => self.assign(ctx, |_, b| Ok(b)),
|
BinOp::Assign => self.assign(vm, |_, b| Ok(b)),
|
||||||
BinOp::AddAssign => self.assign(ctx, ops::add),
|
BinOp::AddAssign => self.assign(vm, ops::add),
|
||||||
BinOp::SubAssign => self.assign(ctx, ops::sub),
|
BinOp::SubAssign => self.assign(vm, ops::sub),
|
||||||
BinOp::MulAssign => self.assign(ctx, ops::mul),
|
BinOp::MulAssign => self.assign(vm, ops::mul),
|
||||||
BinOp::DivAssign => self.assign(ctx, ops::div),
|
BinOp::DivAssign => self.assign(vm, ops::div),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -451,10 +360,10 @@ impl BinaryExpr {
|
|||||||
/// Apply a basic binary operation.
|
/// Apply a basic binary operation.
|
||||||
fn apply(
|
fn apply(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut EvalContext,
|
vm: &mut Vm,
|
||||||
op: fn(Value, Value) -> StrResult<Value>,
|
op: fn(Value, Value) -> StrResult<Value>,
|
||||||
) -> TypResult<Value> {
|
) -> TypResult<Value> {
|
||||||
let lhs = self.lhs().eval(ctx)?;
|
let lhs = self.lhs().eval(vm)?;
|
||||||
|
|
||||||
// Short-circuit boolean operations.
|
// Short-circuit boolean operations.
|
||||||
if (self.op() == BinOp::And && lhs == Value::Bool(false))
|
if (self.op() == BinOp::And && lhs == Value::Bool(false))
|
||||||
@ -463,19 +372,19 @@ impl BinaryExpr {
|
|||||||
return Ok(lhs);
|
return Ok(lhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rhs = self.rhs().eval(ctx)?;
|
let rhs = self.rhs().eval(vm)?;
|
||||||
op(lhs, rhs).at(self.span())
|
op(lhs, rhs).at(self.span())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply an assignment operation.
|
/// Apply an assignment operation.
|
||||||
fn assign(
|
fn assign(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut EvalContext,
|
vm: &mut Vm,
|
||||||
op: fn(Value, Value) -> StrResult<Value>,
|
op: fn(Value, Value) -> StrResult<Value>,
|
||||||
) -> TypResult<Value> {
|
) -> TypResult<Value> {
|
||||||
let rhs = self.rhs().eval(ctx)?;
|
let rhs = self.rhs().eval(vm)?;
|
||||||
self.lhs().access(
|
self.lhs().access(
|
||||||
ctx,
|
vm,
|
||||||
Box::new(|target| {
|
Box::new(|target| {
|
||||||
let lhs = mem::take(&mut *target);
|
let lhs = mem::take(&mut *target);
|
||||||
*target = op(lhs, rhs).at(self.span())?;
|
*target = op(lhs, rhs).at(self.span())?;
|
||||||
@ -489,10 +398,10 @@ impl BinaryExpr {
|
|||||||
impl Eval for CallExpr {
|
impl Eval for CallExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
let span = self.callee().span();
|
let span = self.callee().span();
|
||||||
let callee = self.callee().eval(ctx)?;
|
let callee = self.callee().eval(vm)?;
|
||||||
let args = self.args().eval(ctx)?;
|
let args = self.args().eval(vm)?;
|
||||||
|
|
||||||
match callee {
|
match callee {
|
||||||
Value::Array(array) => {
|
Value::Array(array) => {
|
||||||
@ -505,12 +414,12 @@ impl Eval for CallExpr {
|
|||||||
|
|
||||||
Value::Func(func) => {
|
Value::Func(func) => {
|
||||||
let point = || Tracepoint::Call(func.name().map(ToString::to_string));
|
let point = || Tracepoint::Call(func.name().map(ToString::to_string));
|
||||||
func.call(ctx, args).trace(point, self.span())
|
func.call(vm, args).trace(point, self.span())
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Class(class) => {
|
Value::Class(class) => {
|
||||||
let point = || Tracepoint::Call(Some(class.name().to_string()));
|
let point = || Tracepoint::Call(Some(class.name().to_string()));
|
||||||
class.construct(ctx, args).trace(point, self.span())
|
class.construct(vm, args).trace(point, self.span())
|
||||||
}
|
}
|
||||||
|
|
||||||
v => bail!(
|
v => bail!(
|
||||||
@ -525,7 +434,7 @@ impl Eval for CallExpr {
|
|||||||
impl Eval for CallArgs {
|
impl Eval for CallArgs {
|
||||||
type Output = Args;
|
type Output = Args;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
let mut items = Vec::new();
|
let mut items = Vec::new();
|
||||||
|
|
||||||
for arg in self.items() {
|
for arg in self.items() {
|
||||||
@ -535,17 +444,17 @@ impl Eval for CallArgs {
|
|||||||
items.push(Arg {
|
items.push(Arg {
|
||||||
span,
|
span,
|
||||||
name: None,
|
name: None,
|
||||||
value: Spanned::new(expr.eval(ctx)?, expr.span()),
|
value: Spanned::new(expr.eval(vm)?, expr.span()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
CallArg::Named(named) => {
|
CallArg::Named(named) => {
|
||||||
items.push(Arg {
|
items.push(Arg {
|
||||||
span,
|
span,
|
||||||
name: Some(named.name().take()),
|
name: Some(named.name().take()),
|
||||||
value: Spanned::new(named.expr().eval(ctx)?, named.expr().span()),
|
value: Spanned::new(named.expr().eval(vm)?, named.expr().span()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
CallArg::Spread(expr) => match expr.eval(ctx)? {
|
CallArg::Spread(expr) => match expr.eval(vm)? {
|
||||||
Value::None => {}
|
Value::None => {}
|
||||||
Value::Array(array) => {
|
Value::Array(array) => {
|
||||||
items.extend(array.into_iter().map(|value| Arg {
|
items.extend(array.into_iter().map(|value| Arg {
|
||||||
@ -574,13 +483,13 @@ impl Eval for CallArgs {
|
|||||||
impl Eval for ClosureExpr {
|
impl Eval for ClosureExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
// The closure's name is defined by its let binding if there's one.
|
// The closure's name is defined by its let binding if there's one.
|
||||||
let name = self.name().map(Ident::take);
|
let name = self.name().map(Ident::take);
|
||||||
|
|
||||||
// Collect captured variables.
|
// Collect captured variables.
|
||||||
let captured = {
|
let captured = {
|
||||||
let mut visitor = CapturesVisitor::new(&ctx.scopes);
|
let mut visitor = CapturesVisitor::new(&vm.scopes);
|
||||||
visitor.visit(self.as_red());
|
visitor.visit(self.as_red());
|
||||||
visitor.finish()
|
visitor.finish()
|
||||||
};
|
};
|
||||||
@ -595,7 +504,7 @@ impl Eval for ClosureExpr {
|
|||||||
params.push((name.take(), None));
|
params.push((name.take(), None));
|
||||||
}
|
}
|
||||||
ClosureParam::Named(named) => {
|
ClosureParam::Named(named) => {
|
||||||
params.push((named.name().take(), Some(named.expr().eval(ctx)?)));
|
params.push((named.name().take(), Some(named.expr().eval(vm)?)));
|
||||||
}
|
}
|
||||||
ClosureParam::Sink(name) => {
|
ClosureParam::Sink(name) => {
|
||||||
if sink.is_some() {
|
if sink.is_some() {
|
||||||
@ -620,10 +529,10 @@ impl Eval for ClosureExpr {
|
|||||||
impl Eval for WithExpr {
|
impl Eval for WithExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
let callee = self.callee();
|
let callee = self.callee();
|
||||||
let func = callee.eval(ctx)?.cast::<Func>().at(callee.span())?;
|
let func = callee.eval(vm)?.cast::<Func>().at(callee.span())?;
|
||||||
let args = self.args().eval(ctx)?;
|
let args = self.args().eval(vm)?;
|
||||||
Ok(Value::Func(func.with(args)))
|
Ok(Value::Func(func.with(args)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -631,12 +540,12 @@ impl Eval for WithExpr {
|
|||||||
impl Eval for LetExpr {
|
impl Eval for LetExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
let value = match self.init() {
|
let value = match self.init() {
|
||||||
Some(expr) => expr.eval(ctx)?,
|
Some(expr) => expr.eval(vm)?,
|
||||||
None => Value::None,
|
None => Value::None,
|
||||||
};
|
};
|
||||||
ctx.scopes.def_mut(self.binding().take(), value);
|
vm.scopes.top.def_mut(self.binding().take(), value);
|
||||||
Ok(Value::None)
|
Ok(Value::None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -644,7 +553,7 @@ impl Eval for LetExpr {
|
|||||||
impl Eval for SetExpr {
|
impl Eval for SetExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, _: &mut Vm) -> TypResult<Self::Output> {
|
||||||
Err("set is only allowed directly in markup").at(self.span())
|
Err("set is only allowed directly in markup").at(self.span())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -652,7 +561,7 @@ impl Eval for SetExpr {
|
|||||||
impl Eval for ShowExpr {
|
impl Eval for ShowExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, _: &mut Vm) -> TypResult<Self::Output> {
|
||||||
Err("show is only allowed directly in markup").at(self.span())
|
Err("show is only allowed directly in markup").at(self.span())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -660,7 +569,7 @@ impl Eval for ShowExpr {
|
|||||||
impl Eval for WrapExpr {
|
impl Eval for WrapExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, _: &mut Vm) -> TypResult<Self::Output> {
|
||||||
Err("wrap is only allowed directly in markup").at(self.span())
|
Err("wrap is only allowed directly in markup").at(self.span())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -668,12 +577,12 @@ impl Eval for WrapExpr {
|
|||||||
impl Eval for IfExpr {
|
impl Eval for IfExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
let condition = self.condition();
|
let condition = self.condition();
|
||||||
if condition.eval(ctx)?.cast::<bool>().at(condition.span())? {
|
if condition.eval(vm)?.cast::<bool>().at(condition.span())? {
|
||||||
self.if_body().eval(ctx)
|
self.if_body().eval(vm)
|
||||||
} else if let Some(else_body) = self.else_body() {
|
} else if let Some(else_body) = self.else_body() {
|
||||||
else_body.eval(ctx)
|
else_body.eval(vm)
|
||||||
} else {
|
} else {
|
||||||
Ok(Value::None)
|
Ok(Value::None)
|
||||||
}
|
}
|
||||||
@ -683,13 +592,13 @@ impl Eval for IfExpr {
|
|||||||
impl Eval for WhileExpr {
|
impl Eval for WhileExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
let mut output = Value::None;
|
let mut output = Value::None;
|
||||||
|
|
||||||
let condition = self.condition();
|
let condition = self.condition();
|
||||||
while condition.eval(ctx)?.cast::<bool>().at(condition.span())? {
|
while condition.eval(vm)?.cast::<bool>().at(condition.span())? {
|
||||||
let body = self.body();
|
let body = self.body();
|
||||||
let value = body.eval(ctx)?;
|
let value = body.eval(vm)?;
|
||||||
output = ops::join(output, value).at(body.span())?;
|
output = ops::join(output, value).at(body.span())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -700,27 +609,27 @@ impl Eval for WhileExpr {
|
|||||||
impl Eval for ForExpr {
|
impl Eval for ForExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
macro_rules! iter {
|
macro_rules! iter {
|
||||||
(for ($($binding:ident => $value:ident),*) in $iter:expr) => {{
|
(for ($($binding:ident => $value:ident),*) in $iter:expr) => {{
|
||||||
let mut output = Value::None;
|
let mut output = Value::None;
|
||||||
ctx.scopes.enter();
|
vm.scopes.enter();
|
||||||
|
|
||||||
#[allow(unused_parens)]
|
#[allow(unused_parens)]
|
||||||
for ($($value),*) in $iter {
|
for ($($value),*) in $iter {
|
||||||
$(ctx.scopes.def_mut(&$binding, $value);)*
|
$(vm.scopes.top.def_mut(&$binding, $value);)*
|
||||||
|
|
||||||
let value = self.body().eval(ctx)?;
|
let value = self.body().eval(vm)?;
|
||||||
output = ops::join(output, value)
|
output = ops::join(output, value)
|
||||||
.at(self.body().span())?;
|
.at(self.body().span())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.scopes.exit();
|
vm.scopes.exit();
|
||||||
return Ok(output);
|
return Ok(output);
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
let iter = self.iter().eval(ctx)?;
|
let iter = self.iter().eval(vm)?;
|
||||||
let pattern = self.pattern();
|
let pattern = self.pattern();
|
||||||
let key = pattern.key().map(Ident::take);
|
let key = pattern.key().map(Ident::take);
|
||||||
let value = pattern.value().take();
|
let value = pattern.value().take();
|
||||||
@ -763,22 +672,21 @@ impl Eval for ForExpr {
|
|||||||
impl Eval for ImportExpr {
|
impl Eval for ImportExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
let path = self.path();
|
let span = self.path().span();
|
||||||
let resolved = path.eval(ctx)?.cast::<EcoString>().at(path.span())?;
|
let path = self.path().eval(vm)?.cast::<EcoString>().at(span)?;
|
||||||
let file = ctx.import(&resolved, path.span())?;
|
let module = import(vm, &path, span)?;
|
||||||
let module = &ctx.modules[&file];
|
|
||||||
|
|
||||||
match self.imports() {
|
match self.imports() {
|
||||||
Imports::Wildcard => {
|
Imports::Wildcard => {
|
||||||
for (var, slot) in module.scope.iter() {
|
for (var, slot) in module.scope.iter() {
|
||||||
ctx.scopes.def_mut(var, slot.read().unwrap().clone());
|
vm.scopes.top.def_mut(var, slot.read().unwrap().clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Imports::Items(idents) => {
|
Imports::Items(idents) => {
|
||||||
for ident in idents {
|
for ident in idents {
|
||||||
if let Some(slot) = module.scope.get(&ident) {
|
if let Some(slot) = module.scope.get(&ident) {
|
||||||
ctx.scopes.def_mut(ident.take(), slot.read().unwrap().clone());
|
vm.scopes.top.def_mut(ident.take(), slot.read().unwrap().clone());
|
||||||
} else {
|
} else {
|
||||||
bail!(ident.span(), "unresolved import");
|
bail!(ident.span(), "unresolved import");
|
||||||
}
|
}
|
||||||
@ -793,19 +701,38 @@ impl Eval for ImportExpr {
|
|||||||
impl Eval for IncludeExpr {
|
impl Eval for IncludeExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Vm) -> TypResult<Self::Output> {
|
||||||
let path = self.path();
|
let span = self.path().span();
|
||||||
let resolved = path.eval(ctx)?.cast::<EcoString>().at(path.span())?;
|
let path = self.path().eval(vm)?.cast::<EcoString>().at(span)?;
|
||||||
let file = ctx.import(&resolved, path.span())?;
|
let module = import(vm, &path, span)?;
|
||||||
let module = &ctx.modules[&file];
|
|
||||||
Ok(Value::Template(module.template.clone()))
|
Ok(Value::Template(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> {
|
||||||
|
// Load the source file.
|
||||||
|
let full = vm.resolve(path);
|
||||||
|
let id = vm.sources.load(&full).map_err(|err| {
|
||||||
|
Error::boxed(span, match err.kind() {
|
||||||
|
io::ErrorKind::NotFound => "file not found".into(),
|
||||||
|
_ => format!("failed to load source file ({})", err),
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Prevent cyclic importing.
|
||||||
|
if vm.route.contains(&id) {
|
||||||
|
bail!(span, "cyclic import");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate the file.
|
||||||
|
vm.evaluate(id).trace(|| Tracepoint::Import, span)
|
||||||
|
}
|
||||||
|
|
||||||
impl Eval for BreakExpr {
|
impl Eval for BreakExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, _: &mut Vm) -> TypResult<Self::Output> {
|
||||||
Err("break is not yet implemented").at(self.span())
|
Err("break is not yet implemented").at(self.span())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -813,7 +740,7 @@ impl Eval for BreakExpr {
|
|||||||
impl Eval for ContinueExpr {
|
impl Eval for ContinueExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, _: &mut Vm) -> TypResult<Self::Output> {
|
||||||
Err("continue is not yet implemented").at(self.span())
|
Err("continue is not yet implemented").at(self.span())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -821,7 +748,7 @@ impl Eval for ContinueExpr {
|
|||||||
impl Eval for ReturnExpr {
|
impl Eval for ReturnExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, _: &mut EvalContext) -> TypResult<Self::Output> {
|
fn eval(&self, _: &mut Vm) -> TypResult<Self::Output> {
|
||||||
Err("return is not yet implemented").at(self.span())
|
Err("return is not yet implemented").at(self.span())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -831,25 +758,25 @@ impl Eval for ReturnExpr {
|
|||||||
/// This only works if the expression is a valid lvalue.
|
/// This only works if the expression is a valid lvalue.
|
||||||
pub trait Access {
|
pub trait Access {
|
||||||
/// Try to access the value.
|
/// Try to access the value.
|
||||||
fn access(&self, ctx: &mut EvalContext, f: Handler) -> TypResult<()>;
|
fn access(&self, vm: &mut Vm, f: Handler) -> TypResult<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process an accessed value.
|
/// Process an accessed value.
|
||||||
type Handler<'a> = Box<dyn FnOnce(&mut Value) -> TypResult<()> + 'a>;
|
type Handler<'a> = Box<dyn FnOnce(&mut Value) -> TypResult<()> + 'a>;
|
||||||
|
|
||||||
impl Access for Expr {
|
impl Access for Expr {
|
||||||
fn access(&self, ctx: &mut EvalContext, f: Handler) -> TypResult<()> {
|
fn access(&self, vm: &mut Vm, f: Handler) -> TypResult<()> {
|
||||||
match self {
|
match self {
|
||||||
Expr::Ident(ident) => ident.access(ctx, f),
|
Expr::Ident(ident) => ident.access(vm, f),
|
||||||
Expr::Call(call) => call.access(ctx, f),
|
Expr::Call(call) => call.access(vm, f),
|
||||||
_ => bail!(self.span(), "cannot access this expression mutably"),
|
_ => bail!(self.span(), "cannot access this expression mutably"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Access for Ident {
|
impl Access for Ident {
|
||||||
fn access(&self, ctx: &mut EvalContext, f: Handler) -> TypResult<()> {
|
fn access(&self, vm: &mut Vm, f: Handler) -> TypResult<()> {
|
||||||
match ctx.scopes.get(self) {
|
match vm.scopes.get(self) {
|
||||||
Some(slot) => match slot.try_write() {
|
Some(slot) => match slot.try_write() {
|
||||||
Ok(mut guard) => f(&mut guard),
|
Ok(mut guard) => f(&mut guard),
|
||||||
Err(_) => bail!(self.span(), "cannot mutate a constant"),
|
Err(_) => bail!(self.span(), "cannot mutate a constant"),
|
||||||
@ -860,10 +787,10 @@ impl Access for Ident {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Access for CallExpr {
|
impl Access for CallExpr {
|
||||||
fn access(&self, ctx: &mut EvalContext, f: Handler) -> TypResult<()> {
|
fn access(&self, vm: &mut Vm, f: Handler) -> TypResult<()> {
|
||||||
let args = self.args().eval(ctx)?;
|
let args = self.args().eval(vm)?;
|
||||||
self.callee().access(
|
self.callee().access(
|
||||||
ctx,
|
vm,
|
||||||
Box::new(|value| match value {
|
Box::new(|value| match value {
|
||||||
Value::Array(array) => {
|
Value::Array(array) => {
|
||||||
f(array.get_mut(args.into_index()?).at(self.span())?)
|
f(array.get_mut(args.into_index()?).at(self.span())?)
|
||||||
|
@ -4,7 +4,7 @@ use std::hash::{Hash, Hasher};
|
|||||||
use std::iter;
|
use std::iter;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use super::{Args, Class, Construct, EvalContext, Func, Set, Value};
|
use super::{Args, Class, Construct, Func, Set, Value, Vm};
|
||||||
use crate::diag::TypResult;
|
use crate::diag::TypResult;
|
||||||
use crate::util::EcoString;
|
use crate::util::EcoString;
|
||||||
|
|
||||||
@ -40,21 +40,6 @@ impl<'a> Scopes<'a> {
|
|||||||
self.top = self.scopes.pop().expect("no pushed scope");
|
self.top = self.scopes.pop().expect("no pushed scope");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Define a constant variable with a value in the active scope.
|
|
||||||
pub fn def_const(&mut self, var: impl Into<EcoString>, value: impl Into<Value>) {
|
|
||||||
self.top.def_const(var, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Define a mutable variable with a value in the active scope.
|
|
||||||
pub fn def_mut(&mut self, var: impl Into<EcoString>, value: impl Into<Value>) {
|
|
||||||
self.top.def_mut(var, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Define a variable with a slot in the active scope.
|
|
||||||
pub fn def_slot(&mut self, var: impl Into<EcoString>, slot: Slot) {
|
|
||||||
self.top.def_slot(var, slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Look up the slot of a variable.
|
/// Look up the slot of a variable.
|
||||||
pub fn get(&self, var: &str) -> Option<&Slot> {
|
pub fn get(&self, var: &str) -> Option<&Slot> {
|
||||||
iter::once(&self.top)
|
iter::once(&self.top)
|
||||||
@ -101,7 +86,7 @@ impl Scope {
|
|||||||
pub fn def_func(
|
pub fn def_func(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
func: fn(&mut EvalContext, &mut Args) -> TypResult<Value>,
|
func: fn(&mut Vm, &mut Args) -> TypResult<Value>,
|
||||||
) {
|
) {
|
||||||
self.def_const(name, Func::native(name, func));
|
self.def_const(name, Func::native(name, func));
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ use crate::library::{
|
|||||||
TextNode, UNDERLINE,
|
TextNode, UNDERLINE,
|
||||||
};
|
};
|
||||||
use crate::util::EcoString;
|
use crate::util::EcoString;
|
||||||
use crate::Context;
|
|
||||||
|
|
||||||
/// Composable representation of styled content.
|
/// Composable representation of styled content.
|
||||||
///
|
///
|
||||||
@ -166,19 +165,19 @@ impl Template {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Layout this template into a collection of pages.
|
/// Layout this template into a collection of pages.
|
||||||
pub fn layout(&self, ctx: &mut Context) -> Vec<Arc<Frame>> {
|
pub fn layout(&self, vm: &mut Vm) -> Vec<Arc<Frame>> {
|
||||||
let style_arena = Arena::new();
|
let style_arena = Arena::new();
|
||||||
let template_arena = Arena::new();
|
let template_arena = Arena::new();
|
||||||
let (mut ctx, styles) = LayoutContext::new(ctx);
|
|
||||||
|
|
||||||
let mut builder = Builder::new(&style_arena, &template_arena, true);
|
let mut builder = Builder::new(&style_arena, &template_arena, true);
|
||||||
builder.process(self, styles);
|
let chain = StyleChain::new(vm.styles);
|
||||||
builder.finish_page(true, false, styles);
|
builder.process(self, chain);
|
||||||
|
builder.finish_page(true, false, chain);
|
||||||
|
|
||||||
let (pages, shared) = builder.pages.unwrap().finish();
|
let (pages, shared) = builder.pages.unwrap().finish();
|
||||||
pages
|
pages
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|(page, map)| page.layout(&mut ctx, map.chain(&shared)))
|
.flat_map(|(page, map)| page.layout(vm, map.chain(&shared)))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -267,7 +266,7 @@ impl Sum for Template {
|
|||||||
impl Layout for Template {
|
impl Layout for Template {
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> Vec<Constrained<Arc<Frame>>> {
|
) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
@ -279,7 +278,7 @@ impl Layout for Template {
|
|||||||
builder.finish_par(styles);
|
builder.finish_par(styles);
|
||||||
|
|
||||||
let (flow, shared) = builder.flow.finish();
|
let (flow, shared) = builder.flow.finish();
|
||||||
FlowNode(flow).layout(ctx, regions, shared)
|
FlowNode(flow).layout(vm, regions, shared)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pack(self) -> LayoutNode {
|
fn pack(self) -> LayoutNode {
|
||||||
|
@ -16,13 +16,11 @@ use std::hash::{Hash, Hasher};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::eval::StyleChain;
|
use crate::eval::StyleChain;
|
||||||
use crate::font::FontStore;
|
|
||||||
use crate::frame::{Element, Frame, Geometry, Shape, Stroke};
|
use crate::frame::{Element, Frame, Geometry, Shape, Stroke};
|
||||||
use crate::geom::{Align, Linear, Paint, Point, Sides, Size, Spec, Transform};
|
use crate::geom::{Align, Linear, Paint, Point, Sides, Size, Spec, Transform};
|
||||||
use crate::image::ImageStore;
|
|
||||||
use crate::library::{AlignNode, PadNode, TransformNode, MOVE};
|
use crate::library::{AlignNode, PadNode, TransformNode, MOVE};
|
||||||
use crate::util::Prehashed;
|
use crate::util::Prehashed;
|
||||||
use crate::Context;
|
use crate::Vm;
|
||||||
|
|
||||||
/// A node that can be layouted into a sequence of regions.
|
/// A node that can be layouted into a sequence of regions.
|
||||||
///
|
///
|
||||||
@ -32,7 +30,7 @@ pub trait Layout {
|
|||||||
/// Layout the node into the given regions, producing constrained frames.
|
/// Layout the node into the given regions, producing constrained frames.
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> Vec<Constrained<Arc<Frame>>>;
|
) -> Vec<Constrained<Arc<Frame>>>;
|
||||||
@ -46,35 +44,6 @@ pub trait Layout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The context for layouting.
|
|
||||||
pub struct LayoutContext<'a> {
|
|
||||||
/// Stores parsed font faces.
|
|
||||||
pub fonts: &'a mut FontStore,
|
|
||||||
/// Stores decoded images.
|
|
||||||
pub images: &'a mut ImageStore,
|
|
||||||
/// Caches layouting artifacts.
|
|
||||||
#[cfg(feature = "layout-cache")]
|
|
||||||
pub layout_cache: &'a mut LayoutCache,
|
|
||||||
/// How deeply nested the current layout tree position is.
|
|
||||||
#[cfg(feature = "layout-cache")]
|
|
||||||
level: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> LayoutContext<'a> {
|
|
||||||
/// Create a new layout context and style chain.
|
|
||||||
pub fn new(ctx: &'a mut Context) -> (Self, StyleChain<'a>) {
|
|
||||||
let this = Self {
|
|
||||||
fonts: &mut ctx.fonts,
|
|
||||||
images: &mut ctx.images,
|
|
||||||
#[cfg(feature = "layout-cache")]
|
|
||||||
layout_cache: &mut ctx.layout_cache,
|
|
||||||
#[cfg(feature = "layout-cache")]
|
|
||||||
level: 0,
|
|
||||||
};
|
|
||||||
(this, StyleChain::new(&ctx.styles))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type-erased layouting node with a precomputed hash.
|
/// A type-erased layouting node with a precomputed hash.
|
||||||
#[derive(Clone, Hash)]
|
#[derive(Clone, Hash)]
|
||||||
pub struct LayoutNode(Arc<Prehashed<dyn Bounds>>);
|
pub struct LayoutNode(Arc<Prehashed<dyn Bounds>>);
|
||||||
@ -165,7 +134,7 @@ impl Layout for LayoutNode {
|
|||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> Vec<Constrained<Arc<Frame>>> {
|
) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
@ -185,14 +154,14 @@ impl Layout for LayoutNode {
|
|||||||
// This is not written with `unwrap_or_else`, because then the
|
// This is not written with `unwrap_or_else`, because then the
|
||||||
// #[track_caller] annotation doesn't work.
|
// #[track_caller] annotation doesn't work.
|
||||||
#[cfg(feature = "layout-cache")]
|
#[cfg(feature = "layout-cache")]
|
||||||
if let Some(frames) = ctx.layout_cache.get(hash, regions) {
|
if let Some(frames) = vm.layout_cache.get(hash, regions) {
|
||||||
frames
|
frames
|
||||||
} else {
|
} else {
|
||||||
ctx.level += 1;
|
vm.level += 1;
|
||||||
let frames = self.0.layout(ctx, regions, styles);
|
let frames = self.0.layout(vm, regions, styles);
|
||||||
ctx.level -= 1;
|
vm.level -= 1;
|
||||||
|
|
||||||
let entry = FramesEntry::new(frames.clone(), ctx.level);
|
let entry = FramesEntry::new(frames.clone(), vm.level);
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
if !entry.check(regions) {
|
if !entry.check(regions) {
|
||||||
@ -205,7 +174,7 @@ impl Layout for LayoutNode {
|
|||||||
panic!("constraints did not match regions they were created for");
|
panic!("constraints did not match regions they were created for");
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.layout_cache.insert(hash, entry);
|
vm.layout_cache.insert(hash, entry);
|
||||||
frames
|
frames
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -276,7 +245,7 @@ struct EmptyNode;
|
|||||||
impl Layout for EmptyNode {
|
impl Layout for EmptyNode {
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
_: &mut LayoutContext,
|
_: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
_: StyleChain,
|
_: StyleChain,
|
||||||
) -> Vec<Constrained<Arc<Frame>>> {
|
) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
@ -299,7 +268,7 @@ struct SizedNode {
|
|||||||
impl Layout for SizedNode {
|
impl Layout for SizedNode {
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> Vec<Constrained<Arc<Frame>>> {
|
) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
@ -323,7 +292,7 @@ impl Layout for SizedNode {
|
|||||||
Regions::one(size, base, expand)
|
Regions::one(size, base, expand)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut frames = self.child.layout(ctx, &pod, styles);
|
let mut frames = self.child.layout(vm, &pod, styles);
|
||||||
let Constrained { item: frame, cts } = &mut frames[0];
|
let Constrained { item: frame, cts } = &mut frames[0];
|
||||||
|
|
||||||
// Ensure frame size matches regions size if expansion is on.
|
// Ensure frame size matches regions size if expansion is on.
|
||||||
@ -353,11 +322,11 @@ struct FillNode {
|
|||||||
impl Layout for FillNode {
|
impl Layout for FillNode {
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> Vec<Constrained<Arc<Frame>>> {
|
) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
let mut frames = self.child.layout(ctx, regions, styles);
|
let mut frames = self.child.layout(vm, regions, styles);
|
||||||
for Constrained { item: frame, .. } in &mut frames {
|
for Constrained { item: frame, .. } in &mut frames {
|
||||||
let shape = Shape::filled(Geometry::Rect(frame.size), self.fill);
|
let shape = Shape::filled(Geometry::Rect(frame.size), self.fill);
|
||||||
Arc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape));
|
Arc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape));
|
||||||
@ -378,11 +347,11 @@ struct StrokeNode {
|
|||||||
impl Layout for StrokeNode {
|
impl Layout for StrokeNode {
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> Vec<Constrained<Arc<Frame>>> {
|
) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
let mut frames = self.child.layout(ctx, regions, styles);
|
let mut frames = self.child.layout(vm, regions, styles);
|
||||||
for Constrained { item: frame, .. } in &mut frames {
|
for Constrained { item: frame, .. } in &mut frames {
|
||||||
let shape = Shape::stroked(Geometry::Rect(frame.size), self.stroke);
|
let shape = Shape::stroked(Geometry::Rect(frame.size), self.stroke);
|
||||||
Arc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape));
|
Arc::make_mut(frame).prepend(Point::zero(), Element::Shape(shape));
|
||||||
|
126
src/lib.rs
126
src/lib.rs
@ -22,7 +22,7 @@
|
|||||||
//! [parsed]: parse::parse
|
//! [parsed]: parse::parse
|
||||||
//! [green tree]: syntax::GreenNode
|
//! [green tree]: syntax::GreenNode
|
||||||
//! [AST]: syntax::ast
|
//! [AST]: syntax::ast
|
||||||
//! [evaluate]: Context::evaluate
|
//! [evaluate]: Vm::evaluate
|
||||||
//! [module]: eval::Module
|
//! [module]: eval::Module
|
||||||
//! [template]: eval::Template
|
//! [template]: eval::Template
|
||||||
//! [layouted]: eval::Template::layout
|
//! [layouted]: eval::Template::layout
|
||||||
@ -51,10 +51,12 @@ pub mod parse;
|
|||||||
pub mod source;
|
pub mod source;
|
||||||
pub mod syntax;
|
pub mod syntax;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::diag::TypResult;
|
use crate::diag::TypResult;
|
||||||
use crate::eval::{Eval, EvalContext, Module, Scope, StyleMap};
|
use crate::eval::{Eval, Module, Scope, Scopes, StyleMap};
|
||||||
use crate::export::RenderCache;
|
use crate::export::RenderCache;
|
||||||
use crate::font::FontStore;
|
use crate::font::FontStore;
|
||||||
use crate::frame::Frame;
|
use crate::frame::Frame;
|
||||||
@ -106,27 +108,13 @@ impl Context {
|
|||||||
&self.styles
|
&self.styles
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a source file and return the resulting module.
|
|
||||||
///
|
|
||||||
/// Returns either a module containing a scope with top-level bindings and a
|
|
||||||
/// layoutable template or diagnostics in the form of a vector of error
|
|
||||||
/// message with file and span information.
|
|
||||||
pub fn evaluate(&mut self, id: SourceId) -> TypResult<Module> {
|
|
||||||
let markup = self.sources.get(id).ast()?;
|
|
||||||
let mut ctx = EvalContext::new(self, id);
|
|
||||||
let template = markup.eval(&mut ctx)?;
|
|
||||||
Ok(Module { scope: ctx.scopes.top, template })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Typeset a source file into a collection of layouted frames.
|
/// Typeset a source file into a collection of layouted frames.
|
||||||
///
|
///
|
||||||
/// Returns either a vector of frames representing individual pages or
|
/// Returns either a vector of frames representing individual pages or
|
||||||
/// diagnostics in the form of a vector of error message with file and span
|
/// diagnostics in the form of a vector of error message with file and span
|
||||||
/// information.
|
/// information.
|
||||||
pub fn typeset(&mut self, id: SourceId) -> TypResult<Vec<Arc<Frame>>> {
|
pub fn typeset(&mut self, id: SourceId) -> TypResult<Vec<Arc<Frame>>> {
|
||||||
let module = self.evaluate(id)?;
|
Vm::new(self).typeset(id)
|
||||||
let frames = module.template.layout(self);
|
|
||||||
Ok(frames)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Garbage-collect caches.
|
/// Garbage-collect caches.
|
||||||
@ -208,3 +196,107 @@ impl Default for ContextBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A virtual machine for a single typesetting process.
|
||||||
|
pub struct Vm<'a> {
|
||||||
|
/// The loader the context was created with.
|
||||||
|
pub loader: &'a dyn Loader,
|
||||||
|
/// Stores loaded source files.
|
||||||
|
pub sources: &'a mut SourceStore,
|
||||||
|
/// Stores parsed font faces.
|
||||||
|
pub fonts: &'a mut FontStore,
|
||||||
|
/// Stores decoded images.
|
||||||
|
pub images: &'a mut ImageStore,
|
||||||
|
/// Caches layouting artifacts.
|
||||||
|
#[cfg(feature = "layout-cache")]
|
||||||
|
pub layout_cache: &'a mut LayoutCache,
|
||||||
|
/// The default styles.
|
||||||
|
pub styles: &'a StyleMap,
|
||||||
|
/// The stack of imported files that led to evaluation of the current file.
|
||||||
|
pub route: Vec<SourceId>,
|
||||||
|
/// Caches imported modules.
|
||||||
|
pub modules: HashMap<SourceId, Module>,
|
||||||
|
/// The active scopes.
|
||||||
|
pub scopes: Scopes<'a>,
|
||||||
|
/// How deeply nested the current layout tree position is.
|
||||||
|
#[cfg(feature = "layout-cache")]
|
||||||
|
pub level: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Vm<'a> {
|
||||||
|
/// Create a new virtual machine.
|
||||||
|
pub fn new(ctx: &'a mut Context) -> Self {
|
||||||
|
Self {
|
||||||
|
loader: ctx.loader.as_ref(),
|
||||||
|
sources: &mut ctx.sources,
|
||||||
|
fonts: &mut ctx.fonts,
|
||||||
|
images: &mut ctx.images,
|
||||||
|
layout_cache: &mut ctx.layout_cache,
|
||||||
|
styles: &ctx.styles,
|
||||||
|
route: vec![],
|
||||||
|
modules: HashMap::new(),
|
||||||
|
scopes: Scopes::new(Some(&ctx.std)),
|
||||||
|
level: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Evaluate a source file and return the resulting module.
|
||||||
|
///
|
||||||
|
/// Returns either a module containing a scope with top-level bindings and a
|
||||||
|
/// layoutable template or diagnostics in the form of a vector of error
|
||||||
|
/// message with file and span information.
|
||||||
|
pub fn evaluate(&mut self, id: SourceId) -> TypResult<Module> {
|
||||||
|
// Prevent cyclic evaluation.
|
||||||
|
assert!(!self.route.contains(&id));
|
||||||
|
|
||||||
|
// Check whether the module was already loaded.
|
||||||
|
if let Some(module) = self.modules.get(&id) {
|
||||||
|
return Ok(module.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the file.
|
||||||
|
let source = self.sources.get(id);
|
||||||
|
let ast = source.ast()?;
|
||||||
|
|
||||||
|
// Prepare the new context.
|
||||||
|
let fresh = Scopes::new(self.scopes.base);
|
||||||
|
let prev = std::mem::replace(&mut self.scopes, fresh);
|
||||||
|
self.route.push(id);
|
||||||
|
|
||||||
|
// Evaluate the module.
|
||||||
|
let template = ast.eval(self)?;
|
||||||
|
|
||||||
|
// Restore the old context.
|
||||||
|
let scope = std::mem::replace(&mut self.scopes, prev).top;
|
||||||
|
self.route.pop().unwrap();
|
||||||
|
|
||||||
|
// Save the evaluated module.
|
||||||
|
let module = Module { scope, template };
|
||||||
|
self.modules.insert(id, module.clone());
|
||||||
|
|
||||||
|
Ok(module)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Typeset a source file into a collection of layouted frames.
|
||||||
|
///
|
||||||
|
/// Returns either a vector of frames representing individual pages or
|
||||||
|
/// diagnostics in the form of a vector of error message with file and span
|
||||||
|
/// information.
|
||||||
|
pub fn typeset(&mut self, id: SourceId) -> TypResult<Vec<Arc<Frame>>> {
|
||||||
|
let module = self.evaluate(id)?;
|
||||||
|
let frames = module.template.layout(self);
|
||||||
|
Ok(frames)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolve a user-entered path (relative to the source file) to be
|
||||||
|
/// relative to the compilation environment's root.
|
||||||
|
pub fn resolve(&self, path: &str) -> PathBuf {
|
||||||
|
if let Some(&id) = self.route.last() {
|
||||||
|
if let Some(dir) = self.sources.get(id).path().parent() {
|
||||||
|
return dir.join(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
path.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -14,7 +14,7 @@ pub struct AlignNode {
|
|||||||
|
|
||||||
#[class]
|
#[class]
|
||||||
impl AlignNode {
|
impl AlignNode {
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
let aligns: Spec<_> = args.find()?.unwrap_or_default();
|
let aligns: Spec<_> = args.find()?.unwrap_or_default();
|
||||||
let body: LayoutNode = args.expect("body")?;
|
let body: LayoutNode = args.expect("body")?;
|
||||||
Ok(Template::block(body.aligned(aligns)))
|
Ok(Template::block(body.aligned(aligns)))
|
||||||
@ -24,7 +24,7 @@ impl AlignNode {
|
|||||||
impl Layout for AlignNode {
|
impl Layout for AlignNode {
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> Vec<Constrained<Arc<Frame>>> {
|
) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
@ -39,7 +39,7 @@ impl Layout for AlignNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Layout the child.
|
// Layout the child.
|
||||||
let mut frames = self.child.layout(ctx, &pod, passed.chain(&styles));
|
let mut frames = self.child.layout(vm, &pod, passed.chain(&styles));
|
||||||
|
|
||||||
for ((current, base), Constrained { item: frame, cts }) in
|
for ((current, base), Constrained { item: frame, cts }) in
|
||||||
regions.iter().zip(&mut frames)
|
regions.iter().zip(&mut frames)
|
||||||
|
@ -18,7 +18,7 @@ impl ColumnsNode {
|
|||||||
/// The size of the gutter space between each column.
|
/// The size of the gutter space between each column.
|
||||||
pub const GUTTER: Linear = Relative::new(0.04).into();
|
pub const GUTTER: Linear = Relative::new(0.04).into();
|
||||||
|
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
Ok(Template::block(Self {
|
Ok(Template::block(Self {
|
||||||
columns: args.expect("column count")?,
|
columns: args.expect("column count")?,
|
||||||
child: args.expect("body")?,
|
child: args.expect("body")?,
|
||||||
@ -29,14 +29,14 @@ impl ColumnsNode {
|
|||||||
impl Layout for ColumnsNode {
|
impl Layout for ColumnsNode {
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> Vec<Constrained<Arc<Frame>>> {
|
) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
// Separating the infinite space into infinite columns does not make
|
// Separating the infinite space into infinite columns does not make
|
||||||
// much sense.
|
// much sense.
|
||||||
if regions.current.x.is_infinite() {
|
if regions.current.x.is_infinite() {
|
||||||
return self.child.layout(ctx, regions, styles);
|
return self.child.layout(vm, regions, styles);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the width of the gutter and each column.
|
// Determine the width of the gutter and each column.
|
||||||
@ -59,7 +59,7 @@ impl Layout for ColumnsNode {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Layout the children.
|
// Layout the children.
|
||||||
let mut frames = self.child.layout(ctx, &pod, styles).into_iter();
|
let mut frames = self.child.layout(vm, &pod, styles).into_iter();
|
||||||
|
|
||||||
let dir = styles.get(ParNode::DIR);
|
let dir = styles.get(ParNode::DIR);
|
||||||
let total_regions = (frames.len() as f32 / columns as f32).ceil() as usize;
|
let total_regions = (frames.len() as f32 / columns as f32).ceil() as usize;
|
||||||
@ -111,7 +111,7 @@ pub struct ColbreakNode;
|
|||||||
|
|
||||||
#[class]
|
#[class]
|
||||||
impl ColbreakNode {
|
impl ColbreakNode {
|
||||||
fn construct(_: &mut EvalContext, _: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, _: &mut Args) -> TypResult<Template> {
|
||||||
Ok(Template::Colbreak)
|
Ok(Template::Colbreak)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ pub struct BoxNode;
|
|||||||
|
|
||||||
#[class]
|
#[class]
|
||||||
impl BoxNode {
|
impl BoxNode {
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
let width = args.named("width")?;
|
let width = args.named("width")?;
|
||||||
let height = args.named("height")?;
|
let height = args.named("height")?;
|
||||||
let body: LayoutNode = args.find()?.unwrap_or_default();
|
let body: LayoutNode = args.find()?.unwrap_or_default();
|
||||||
@ -20,7 +20,7 @@ pub struct BlockNode;
|
|||||||
|
|
||||||
#[class]
|
#[class]
|
||||||
impl BlockNode {
|
impl BlockNode {
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
Ok(Template::Block(args.find()?.unwrap_or_default()))
|
Ok(Template::Block(args.find()?.unwrap_or_default()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ impl<const L: DecoLine> DecoNode<L> {
|
|||||||
/// with the glyphs. Does not apply to strikethrough.
|
/// with the glyphs. Does not apply to strikethrough.
|
||||||
pub const EVADE: bool = true;
|
pub const EVADE: bool = true;
|
||||||
|
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
Ok(Template::show(Self(args.expect::<Template>("body")?)))
|
Ok(Template::show(Self(args.expect::<Template>("body")?)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ pub enum FlowChild {
|
|||||||
impl Layout for FlowNode {
|
impl Layout for FlowNode {
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> Vec<Constrained<Arc<Frame>>> {
|
) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
@ -56,7 +56,7 @@ impl Layout for FlowNode {
|
|||||||
layouter.layout_spacing(*kind);
|
layouter.layout_spacing(*kind);
|
||||||
}
|
}
|
||||||
FlowChild::Node(ref node) => {
|
FlowChild::Node(ref node) => {
|
||||||
layouter.layout_node(ctx, node, styles);
|
layouter.layout_node(vm, node, styles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -161,12 +161,7 @@ impl FlowLayouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Layout a node.
|
/// Layout a node.
|
||||||
pub fn layout_node(
|
pub fn layout_node(&mut self, vm: &mut Vm, node: &LayoutNode, styles: StyleChain) {
|
||||||
&mut self,
|
|
||||||
ctx: &mut LayoutContext,
|
|
||||||
node: &LayoutNode,
|
|
||||||
styles: StyleChain,
|
|
||||||
) {
|
|
||||||
// Don't even try layouting into a full region.
|
// Don't even try layouting into a full region.
|
||||||
if self.regions.is_full() {
|
if self.regions.is_full() {
|
||||||
self.finish_region();
|
self.finish_region();
|
||||||
@ -176,7 +171,7 @@ impl FlowLayouter {
|
|||||||
// aligned later.
|
// aligned later.
|
||||||
if let Some(placed) = node.downcast::<PlaceNode>() {
|
if let Some(placed) = node.downcast::<PlaceNode>() {
|
||||||
if placed.out_of_flow() {
|
if placed.out_of_flow() {
|
||||||
let frame = node.layout(ctx, &self.regions, styles).remove(0);
|
let frame = node.layout(vm, &self.regions, styles).remove(0);
|
||||||
self.items.push(FlowItem::Placed(frame.item));
|
self.items.push(FlowItem::Placed(frame.item));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -193,7 +188,7 @@ impl FlowLayouter {
|
|||||||
.unwrap_or(Align::Top),
|
.unwrap_or(Align::Top),
|
||||||
);
|
);
|
||||||
|
|
||||||
let frames = node.layout(ctx, &self.regions, styles);
|
let frames = node.layout(vm, &self.regions, styles);
|
||||||
let len = frames.len();
|
let len = frames.len();
|
||||||
for (i, frame) in frames.into_iter().enumerate() {
|
for (i, frame) in frames.into_iter().enumerate() {
|
||||||
// Grow our size, shrink the region and save the frame for later.
|
// Grow our size, shrink the region and save the frame for later.
|
||||||
|
@ -15,7 +15,7 @@ pub struct GridNode {
|
|||||||
|
|
||||||
#[class]
|
#[class]
|
||||||
impl GridNode {
|
impl GridNode {
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
let columns = args.named("columns")?.unwrap_or_default();
|
let columns = args.named("columns")?.unwrap_or_default();
|
||||||
let rows = args.named("rows")?.unwrap_or_default();
|
let rows = args.named("rows")?.unwrap_or_default();
|
||||||
let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default();
|
let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default();
|
||||||
@ -35,7 +35,7 @@ impl GridNode {
|
|||||||
impl Layout for GridNode {
|
impl Layout for GridNode {
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> Vec<Constrained<Arc<Frame>>> {
|
) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
@ -49,7 +49,7 @@ impl Layout for GridNode {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Measure the columsna nd layout the grid row-by-row.
|
// Measure the columsna nd layout the grid row-by-row.
|
||||||
layouter.layout(ctx)
|
layouter.layout(vm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,19 +205,19 @@ impl<'a> GridLayouter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Determines the columns sizes and then layouts the grid row-by-row.
|
/// Determines the columns sizes and then layouts the grid row-by-row.
|
||||||
pub fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Arc<Frame>>> {
|
pub fn layout(mut self, vm: &mut Vm) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
self.measure_columns(ctx);
|
self.measure_columns(vm);
|
||||||
|
|
||||||
for y in 0 .. self.rows.len() {
|
for y in 0 .. self.rows.len() {
|
||||||
// Skip to next region if current one is full, but only for content
|
// Skip to next region if current one is full, but only for content
|
||||||
// rows, not for gutter rows.
|
// rows, not for gutter rows.
|
||||||
if y % 2 == 0 && self.regions.is_full() {
|
if y % 2 == 0 && self.regions.is_full() {
|
||||||
self.finish_region(ctx);
|
self.finish_region(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.rows[y] {
|
match self.rows[y] {
|
||||||
TrackSizing::Auto => self.layout_auto_row(ctx, y),
|
TrackSizing::Auto => self.layout_auto_row(vm, y),
|
||||||
TrackSizing::Linear(v) => self.layout_linear_row(ctx, v, y),
|
TrackSizing::Linear(v) => self.layout_linear_row(vm, v, y),
|
||||||
TrackSizing::Fractional(v) => {
|
TrackSizing::Fractional(v) => {
|
||||||
self.cts.exact.y = Some(self.full);
|
self.cts.exact.y = Some(self.full);
|
||||||
self.lrows.push(Row::Fr(v, y));
|
self.lrows.push(Row::Fr(v, y));
|
||||||
@ -226,12 +226,12 @@ impl<'a> GridLayouter<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.finish_region(ctx);
|
self.finish_region(vm);
|
||||||
self.finished
|
self.finished
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine all column sizes.
|
/// Determine all column sizes.
|
||||||
fn measure_columns(&mut self, ctx: &mut LayoutContext) {
|
fn measure_columns(&mut self, vm: &mut Vm) {
|
||||||
enum Case {
|
enum Case {
|
||||||
/// The column sizing is only determined by specified linear sizes.
|
/// The column sizing is only determined by specified linear sizes.
|
||||||
PurelyLinear,
|
PurelyLinear,
|
||||||
@ -277,7 +277,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
let available = self.regions.current.x - linear;
|
let available = self.regions.current.x - linear;
|
||||||
if available >= Length::zero() {
|
if available >= Length::zero() {
|
||||||
// Determine size of auto columns.
|
// Determine size of auto columns.
|
||||||
let (auto, count) = self.measure_auto_columns(ctx, available);
|
let (auto, count) = self.measure_auto_columns(vm, available);
|
||||||
|
|
||||||
// If there is remaining space, distribute it to fractional columns,
|
// If there is remaining space, distribute it to fractional columns,
|
||||||
// otherwise shrink auto columns.
|
// otherwise shrink auto columns.
|
||||||
@ -313,7 +313,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
/// Measure the size that is available to auto columns.
|
/// Measure the size that is available to auto columns.
|
||||||
fn measure_auto_columns(
|
fn measure_auto_columns(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
available: Length,
|
available: Length,
|
||||||
) -> (Length, usize) {
|
) -> (Length, usize) {
|
||||||
let mut auto = Length::zero();
|
let mut auto = Length::zero();
|
||||||
@ -340,7 +340,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
pod.base.y = v.resolve(self.regions.base.y);
|
pod.base.y = v.resolve(self.regions.base.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
let frame = node.layout(ctx, &pod, self.styles).remove(0).item;
|
let frame = node.layout(vm, &pod, self.styles).remove(0).item;
|
||||||
resolved.set_max(frame.size.x);
|
resolved.set_max(frame.size.x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -394,7 +394,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
|
|
||||||
/// Layout a row with automatic height. Such a row may break across multiple
|
/// Layout a row with automatic height. Such a row may break across multiple
|
||||||
/// regions.
|
/// regions.
|
||||||
fn layout_auto_row(&mut self, ctx: &mut LayoutContext, y: usize) {
|
fn layout_auto_row(&mut self, vm: &mut Vm, y: usize) {
|
||||||
let mut resolved: Vec<Length> = vec![];
|
let mut resolved: Vec<Length> = vec![];
|
||||||
|
|
||||||
// Determine the size for each region of the row.
|
// Determine the size for each region of the row.
|
||||||
@ -409,7 +409,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut sizes = node
|
let mut sizes = node
|
||||||
.layout(ctx, &pod, self.styles)
|
.layout(vm, &pod, self.styles)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|frame| frame.item.size.y);
|
.map(|frame| frame.item.size.y);
|
||||||
|
|
||||||
@ -432,7 +432,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
|
|
||||||
// Layout into a single region.
|
// Layout into a single region.
|
||||||
if let &[first] = resolved.as_slice() {
|
if let &[first] = resolved.as_slice() {
|
||||||
let frame = self.layout_single_row(ctx, first, y);
|
let frame = self.layout_single_row(vm, first, y);
|
||||||
self.push_row(frame);
|
self.push_row(frame);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -449,28 +449,28 @@ impl<'a> GridLayouter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Layout into multiple regions.
|
// Layout into multiple regions.
|
||||||
let frames = self.layout_multi_row(ctx, &resolved, y);
|
let frames = self.layout_multi_row(vm, &resolved, y);
|
||||||
let len = frames.len();
|
let len = frames.len();
|
||||||
for (i, frame) in frames.into_iter().enumerate() {
|
for (i, frame) in frames.into_iter().enumerate() {
|
||||||
self.push_row(frame);
|
self.push_row(frame);
|
||||||
if i + 1 < len {
|
if i + 1 < len {
|
||||||
self.cts.exact.y = Some(self.full);
|
self.cts.exact.y = Some(self.full);
|
||||||
self.finish_region(ctx);
|
self.finish_region(vm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Layout a row with linear height. Such a row cannot break across multiple
|
/// Layout a row with linear height. Such a row cannot break across multiple
|
||||||
/// regions, but it may force a region break.
|
/// regions, but it may force a region break.
|
||||||
fn layout_linear_row(&mut self, ctx: &mut LayoutContext, v: Linear, y: usize) {
|
fn layout_linear_row(&mut self, vm: &mut Vm, v: Linear, y: usize) {
|
||||||
let resolved = v.resolve(self.regions.base.y);
|
let resolved = v.resolve(self.regions.base.y);
|
||||||
let frame = self.layout_single_row(ctx, resolved, y);
|
let frame = self.layout_single_row(vm, resolved, y);
|
||||||
|
|
||||||
// Skip to fitting region.
|
// Skip to fitting region.
|
||||||
let height = frame.size.y;
|
let height = frame.size.y;
|
||||||
while !self.regions.current.y.fits(height) && !self.regions.in_last() {
|
while !self.regions.current.y.fits(height) && !self.regions.in_last() {
|
||||||
self.cts.max.y = Some(self.used.y + height);
|
self.cts.max.y = Some(self.used.y + height);
|
||||||
self.finish_region(ctx);
|
self.finish_region(vm);
|
||||||
|
|
||||||
// Don't skip multiple regions for gutter and don't push a row.
|
// Don't skip multiple regions for gutter and don't push a row.
|
||||||
if y % 2 == 1 {
|
if y % 2 == 1 {
|
||||||
@ -484,7 +484,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
/// Layout a row with fixed height and return its frame.
|
/// Layout a row with fixed height and return its frame.
|
||||||
fn layout_single_row(
|
fn layout_single_row(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
height: Length,
|
height: Length,
|
||||||
y: usize,
|
y: usize,
|
||||||
) -> Frame {
|
) -> Frame {
|
||||||
@ -502,7 +502,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
.select(self.regions.base, size);
|
.select(self.regions.base, size);
|
||||||
|
|
||||||
let pod = Regions::one(size, base, Spec::splat(true));
|
let pod = Regions::one(size, base, Spec::splat(true));
|
||||||
let frame = node.layout(ctx, &pod, self.styles).remove(0);
|
let frame = node.layout(vm, &pod, self.styles).remove(0);
|
||||||
output.push_frame(pos, frame.item);
|
output.push_frame(pos, frame.item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -515,7 +515,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
/// Layout a row spanning multiple regions.
|
/// Layout a row spanning multiple regions.
|
||||||
fn layout_multi_row(
|
fn layout_multi_row(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
heights: &[Length],
|
heights: &[Length],
|
||||||
y: usize,
|
y: usize,
|
||||||
) -> Vec<Frame> {
|
) -> Vec<Frame> {
|
||||||
@ -542,7 +542,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Push the layouted frames into the individual output frames.
|
// Push the layouted frames into the individual output frames.
|
||||||
let frames = node.layout(ctx, &pod, self.styles);
|
let frames = node.layout(vm, &pod, self.styles);
|
||||||
for (output, frame) in outputs.iter_mut().zip(frames) {
|
for (output, frame) in outputs.iter_mut().zip(frames) {
|
||||||
output.push_frame(pos, frame.item);
|
output.push_frame(pos, frame.item);
|
||||||
}
|
}
|
||||||
@ -562,7 +562,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Finish rows for one region.
|
/// Finish rows for one region.
|
||||||
fn finish_region(&mut self, ctx: &mut LayoutContext) {
|
fn finish_region(&mut self, vm: &mut Vm) {
|
||||||
// Determine the size of the grid in this region, expanding fully if
|
// Determine the size of the grid in this region, expanding fully if
|
||||||
// there are fr rows.
|
// there are fr rows.
|
||||||
let mut size = self.used;
|
let mut size = self.used;
|
||||||
@ -584,7 +584,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
Row::Fr(v, y) => {
|
Row::Fr(v, y) => {
|
||||||
let remaining = self.full - self.used.y;
|
let remaining = self.full - self.used.y;
|
||||||
let height = v.resolve(self.fr, remaining);
|
let height = v.resolve(self.fr, remaining);
|
||||||
self.layout_single_row(ctx, height, y)
|
self.layout_single_row(vm, height, y)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ impl HeadingNode {
|
|||||||
/// The extra padding below the heading.
|
/// The extra padding below the heading.
|
||||||
pub const BELOW: Length = Length::zero();
|
pub const BELOW: Length = Length::zero();
|
||||||
|
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
Ok(Template::show(Self {
|
Ok(Template::show(Self {
|
||||||
body: args.expect("body")?,
|
body: args.expect("body")?,
|
||||||
level: args.named("level")?.unwrap_or(1),
|
level: args.named("level")?.unwrap_or(1),
|
||||||
|
@ -8,7 +8,7 @@ pub struct HideNode(pub LayoutNode);
|
|||||||
|
|
||||||
#[class]
|
#[class]
|
||||||
impl HideNode {
|
impl HideNode {
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
Ok(Template::inline(Self(args.expect("body")?)))
|
Ok(Template::inline(Self(args.expect("body")?)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -16,11 +16,11 @@ impl HideNode {
|
|||||||
impl Layout for HideNode {
|
impl Layout for HideNode {
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> Vec<Constrained<Arc<Frame>>> {
|
) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
let mut frames = self.0.layout(ctx, regions, styles);
|
let mut frames = self.0.layout(vm, regions, styles);
|
||||||
|
|
||||||
// Clear the frames.
|
// Clear the frames.
|
||||||
for Constrained { item: frame, .. } in &mut frames {
|
for Constrained { item: frame, .. } in &mut frames {
|
||||||
|
@ -14,10 +14,10 @@ impl ImageNode {
|
|||||||
/// How the image should adjust itself to a given area.
|
/// How the image should adjust itself to a given area.
|
||||||
pub const FIT: ImageFit = ImageFit::Cover;
|
pub const FIT: ImageFit = ImageFit::Cover;
|
||||||
|
|
||||||
fn construct(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(vm: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
let path = args.expect::<Spanned<EcoString>>("path to image file")?;
|
let path = args.expect::<Spanned<EcoString>>("path to image file")?;
|
||||||
let full = ctx.make_path(&path.v);
|
let full = vm.resolve(&path.v);
|
||||||
let id = ctx.images.load(&full).map_err(|err| {
|
let id = vm.images.load(&full).map_err(|err| {
|
||||||
Error::boxed(path.span, match err.kind() {
|
Error::boxed(path.span, match err.kind() {
|
||||||
std::io::ErrorKind::NotFound => "file not found".into(),
|
std::io::ErrorKind::NotFound => "file not found".into(),
|
||||||
_ => format!("failed to load image ({})", err),
|
_ => format!("failed to load image ({})", err),
|
||||||
@ -36,11 +36,11 @@ impl ImageNode {
|
|||||||
impl Layout for ImageNode {
|
impl Layout for ImageNode {
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> Vec<Constrained<Arc<Frame>>> {
|
) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
let img = ctx.images.get(self.0);
|
let img = vm.images.get(self.0);
|
||||||
let pxw = img.width() as f64;
|
let pxw = img.width() as f64;
|
||||||
let pxh = img.height() as f64;
|
let pxh = img.height() as f64;
|
||||||
let px_ratio = pxw / pxh;
|
let px_ratio = pxw / pxh;
|
||||||
|
@ -21,7 +21,7 @@ impl LinkNode {
|
|||||||
/// Whether to underline link.
|
/// Whether to underline link.
|
||||||
pub const UNDERLINE: bool = true;
|
pub const UNDERLINE: bool = true;
|
||||||
|
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
let url = args.expect::<EcoString>("url")?;
|
let url = args.expect::<EcoString>("url")?;
|
||||||
let body = args.find()?.unwrap_or_else(|| {
|
let body = args.find()?.unwrap_or_else(|| {
|
||||||
let mut text = url.as_str();
|
let mut text = url.as_str();
|
||||||
|
@ -19,7 +19,7 @@ impl<const L: Labelling> ListNode<L> {
|
|||||||
/// The space between the label and the body of each item.
|
/// The space between the label and the body of each item.
|
||||||
pub const BODY_INDENT: Linear = Relative::new(0.5).into();
|
pub const BODY_INDENT: Linear = Relative::new(0.5).into();
|
||||||
|
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
Ok(args
|
Ok(args
|
||||||
.all()?
|
.all()?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -13,7 +13,7 @@ pub struct MathNode {
|
|||||||
|
|
||||||
#[class]
|
#[class]
|
||||||
impl MathNode {
|
impl MathNode {
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
Ok(Template::show(Self {
|
Ok(Template::show(Self {
|
||||||
formula: args.expect("formula")?,
|
formula: args.expect("formula")?,
|
||||||
display: args.named("display")?.unwrap_or(false),
|
display: args.named("display")?.unwrap_or(false),
|
||||||
|
@ -64,16 +64,17 @@ pub mod prelude {
|
|||||||
|
|
||||||
pub use crate::diag::{At, TypResult};
|
pub use crate::diag::{At, TypResult};
|
||||||
pub use crate::eval::{
|
pub use crate::eval::{
|
||||||
Args, Construct, EvalContext, Merge, Property, Scope, Set, Show, ShowNode, Smart,
|
Args, Construct, Merge, Property, Scope, Set, Show, ShowNode, Smart, StyleChain,
|
||||||
StyleChain, StyleMap, StyleVec, Template, Value,
|
StyleMap, StyleVec, Template, Value,
|
||||||
};
|
};
|
||||||
pub use crate::frame::*;
|
pub use crate::frame::*;
|
||||||
pub use crate::geom::*;
|
pub use crate::geom::*;
|
||||||
pub use crate::layout::{
|
pub use crate::layout::{
|
||||||
Constrain, Constrained, Constraints, Layout, LayoutContext, LayoutNode, Regions,
|
Constrain, Constrained, Constraints, Layout, LayoutNode, Regions,
|
||||||
};
|
};
|
||||||
pub use crate::syntax::{Span, Spanned};
|
pub use crate::syntax::{Span, Spanned};
|
||||||
pub use crate::util::{EcoString, OptionExt};
|
pub use crate::util::{EcoString, OptionExt};
|
||||||
|
pub use crate::Vm;
|
||||||
}
|
}
|
||||||
|
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
@ -13,7 +13,7 @@ pub struct PadNode {
|
|||||||
|
|
||||||
#[class]
|
#[class]
|
||||||
impl PadNode {
|
impl PadNode {
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
let all = args.find()?;
|
let all = args.find()?;
|
||||||
let left = args.named("left")?;
|
let left = args.named("left")?;
|
||||||
let top = args.named("top")?;
|
let top = args.named("top")?;
|
||||||
@ -34,13 +34,13 @@ impl PadNode {
|
|||||||
impl Layout for PadNode {
|
impl Layout for PadNode {
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> Vec<Constrained<Arc<Frame>>> {
|
) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
// Layout child into padded regions.
|
// Layout child into padded regions.
|
||||||
let pod = regions.map(|size| shrink(size, self.padding));
|
let pod = regions.map(|size| shrink(size, self.padding));
|
||||||
let mut frames = self.child.layout(ctx, &pod, styles);
|
let mut frames = self.child.layout(vm, &pod, styles);
|
||||||
|
|
||||||
for ((current, base), Constrained { item: frame, cts }) in
|
for ((current, base), Constrained { item: frame, cts }) in
|
||||||
regions.iter().zip(&mut frames)
|
regions.iter().zip(&mut frames)
|
||||||
|
@ -31,7 +31,7 @@ impl PageNode {
|
|||||||
/// How many columns the page has.
|
/// How many columns the page has.
|
||||||
pub const COLUMNS: NonZeroUsize = NonZeroUsize::new(1).unwrap();
|
pub const COLUMNS: NonZeroUsize = NonZeroUsize::new(1).unwrap();
|
||||||
|
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
Ok(Template::Page(Self(args.expect("body")?)))
|
Ok(Template::Page(Self(args.expect("body")?)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ impl PageNode {
|
|||||||
|
|
||||||
impl PageNode {
|
impl PageNode {
|
||||||
/// Layout the page run into a sequence of frames, one per page.
|
/// Layout the page run into a sequence of frames, one per page.
|
||||||
pub fn layout(&self, ctx: &mut LayoutContext, styles: StyleChain) -> Vec<Arc<Frame>> {
|
pub fn layout(&self, vm: &mut Vm, styles: StyleChain) -> Vec<Arc<Frame>> {
|
||||||
// When one of the lengths is infinite the page fits its content along
|
// When one of the lengths is infinite the page fits its content along
|
||||||
// that axis.
|
// that axis.
|
||||||
let width = styles.get(Self::WIDTH).unwrap_or(Length::inf());
|
let width = styles.get(Self::WIDTH).unwrap_or(Length::inf());
|
||||||
@ -104,7 +104,7 @@ impl PageNode {
|
|||||||
let expand = size.map(Length::is_finite);
|
let expand = size.map(Length::is_finite);
|
||||||
let regions = Regions::repeat(size, size, expand);
|
let regions = Regions::repeat(size, size, expand);
|
||||||
child
|
child
|
||||||
.layout(ctx, ®ions, styles)
|
.layout(vm, ®ions, styles)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|c| c.item)
|
.map(|c| c.item)
|
||||||
.collect()
|
.collect()
|
||||||
@ -124,7 +124,7 @@ pub struct PagebreakNode;
|
|||||||
|
|
||||||
#[class]
|
#[class]
|
||||||
impl PagebreakNode {
|
impl PagebreakNode {
|
||||||
fn construct(_: &mut EvalContext, _: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, _: &mut Args) -> TypResult<Template> {
|
||||||
Ok(Template::Pagebreak)
|
Ok(Template::Pagebreak)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ impl ParNode {
|
|||||||
/// The extra spacing between paragraphs (dependent on scaled font size).
|
/// The extra spacing between paragraphs (dependent on scaled font size).
|
||||||
pub const SPACING: Linear = Relative::new(0.55).into();
|
pub const SPACING: Linear = Relative::new(0.55).into();
|
||||||
|
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
// The paragraph constructor is special: It doesn't create a paragraph
|
// The paragraph constructor is special: It doesn't create a paragraph
|
||||||
// since that happens automatically through markup. Instead, it just
|
// since that happens automatically through markup. Instead, it just
|
||||||
// lifts the passed body to the block level so that it won't merge with
|
// lifts the passed body to the block level so that it won't merge with
|
||||||
@ -82,7 +82,7 @@ impl ParNode {
|
|||||||
impl Layout for ParNode {
|
impl Layout for ParNode {
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> Vec<Constrained<Arc<Frame>>> {
|
) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
@ -95,10 +95,10 @@ impl Layout for ParNode {
|
|||||||
|
|
||||||
// Prepare paragraph layout by building a representation on which we can
|
// Prepare paragraph layout by building a representation on which we can
|
||||||
// do line breaking without layouting each and every line from scratch.
|
// do line breaking without layouting each and every line from scratch.
|
||||||
let layouter = ParLayouter::new(self, ctx, regions, &styles, bidi);
|
let layouter = ParLayouter::new(self, vm, regions, &styles, bidi);
|
||||||
|
|
||||||
// Find suitable linebreaks.
|
// Find suitable linebreaks.
|
||||||
layouter.layout(ctx, regions.clone())
|
layouter.layout(vm, regions.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ pub struct ParbreakNode;
|
|||||||
|
|
||||||
#[class]
|
#[class]
|
||||||
impl ParbreakNode {
|
impl ParbreakNode {
|
||||||
fn construct(_: &mut EvalContext, _: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, _: &mut Args) -> TypResult<Template> {
|
||||||
Ok(Template::Parbreak)
|
Ok(Template::Parbreak)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,7 +177,7 @@ pub struct LinebreakNode;
|
|||||||
|
|
||||||
#[class]
|
#[class]
|
||||||
impl LinebreakNode {
|
impl LinebreakNode {
|
||||||
fn construct(_: &mut EvalContext, _: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, _: &mut Args) -> TypResult<Template> {
|
||||||
Ok(Template::Linebreak)
|
Ok(Template::Linebreak)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -216,7 +216,7 @@ impl<'a> ParLayouter<'a> {
|
|||||||
/// Prepare initial shaped text and layouted children.
|
/// Prepare initial shaped text and layouted children.
|
||||||
fn new(
|
fn new(
|
||||||
par: &'a ParNode,
|
par: &'a ParNode,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: &'a StyleChain<'a>,
|
styles: &'a StyleChain<'a>,
|
||||||
bidi: BidiInfo<'a>,
|
bidi: BidiInfo<'a>,
|
||||||
@ -236,7 +236,7 @@ impl<'a> ParLayouter<'a> {
|
|||||||
cursor += count;
|
cursor += count;
|
||||||
let subrange = start .. cursor;
|
let subrange = start .. cursor;
|
||||||
let text = &bidi.text[subrange.clone()];
|
let text = &bidi.text[subrange.clone()];
|
||||||
let shaped = shape(ctx.fonts, text, styles, level.dir());
|
let shaped = shape(vm.fonts, text, styles, level.dir());
|
||||||
items.push(ParItem::Text(shaped));
|
items.push(ParItem::Text(shaped));
|
||||||
ranges.push(subrange);
|
ranges.push(subrange);
|
||||||
}
|
}
|
||||||
@ -255,7 +255,7 @@ impl<'a> ParLayouter<'a> {
|
|||||||
ParChild::Node(node) => {
|
ParChild::Node(node) => {
|
||||||
let size = Size::new(regions.current.x, regions.base.y);
|
let size = Size::new(regions.current.x, regions.base.y);
|
||||||
let pod = Regions::one(size, regions.base, Spec::splat(false));
|
let pod = Regions::one(size, regions.base, Spec::splat(false));
|
||||||
let frame = node.layout(ctx, &pod, styles).remove(0);
|
let frame = node.layout(vm, &pod, styles).remove(0);
|
||||||
items.push(ParItem::Frame(Arc::take(frame.item)));
|
items.push(ParItem::Frame(Arc::take(frame.item)));
|
||||||
ranges.push(range);
|
ranges.push(range);
|
||||||
}
|
}
|
||||||
@ -270,11 +270,7 @@ impl<'a> ParLayouter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Find first-fit line breaks and build the paragraph.
|
/// Find first-fit line breaks and build the paragraph.
|
||||||
fn layout(
|
fn layout(self, vm: &mut Vm, regions: Regions) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
self,
|
|
||||||
ctx: &mut LayoutContext,
|
|
||||||
regions: Regions,
|
|
||||||
) -> Vec<Constrained<Arc<Frame>>> {
|
|
||||||
let mut stack = LineStack::new(self.leading, regions);
|
let mut stack = LineStack::new(self.leading, regions);
|
||||||
|
|
||||||
// The current line attempt.
|
// The current line attempt.
|
||||||
@ -288,7 +284,7 @@ impl<'a> ParLayouter<'a> {
|
|||||||
// TODO: Provide line break opportunities on alignment changes.
|
// TODO: Provide line break opportunities on alignment changes.
|
||||||
for (end, mandatory) in LineBreakIterator::new(self.bidi.text) {
|
for (end, mandatory) in LineBreakIterator::new(self.bidi.text) {
|
||||||
// Compute the line and its size.
|
// Compute the line and its size.
|
||||||
let mut line = LineLayout::new(ctx, &self, start .. end);
|
let mut line = LineLayout::new(vm, &self, start .. end);
|
||||||
|
|
||||||
// If the line doesn't fit anymore, we push the last fitting attempt
|
// If the line doesn't fit anymore, we push the last fitting attempt
|
||||||
// into the stack and rebuild the line from its end. The resulting
|
// into the stack and rebuild the line from its end. The resulting
|
||||||
@ -318,7 +314,7 @@ impl<'a> ParLayouter<'a> {
|
|||||||
stack.push(last_line);
|
stack.push(last_line);
|
||||||
stack.cts.min.y = Some(stack.size.y);
|
stack.cts.min.y = Some(stack.size.y);
|
||||||
start = last_end;
|
start = last_end;
|
||||||
line = LineLayout::new(ctx, &self, start .. end);
|
line = LineLayout::new(vm, &self, start .. end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -335,7 +331,7 @@ impl<'a> ParLayouter<'a> {
|
|||||||
// below.
|
// below.
|
||||||
let too_large = stack.size.y + self.leading + line.size.y;
|
let too_large = stack.size.y + self.leading + line.size.y;
|
||||||
stack.cts.max.y.set_min(too_large);
|
stack.cts.max.y.set_min(too_large);
|
||||||
stack.finish_region(ctx);
|
stack.finish_region(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the line does not fit horizontally or we have a mandatory
|
// If the line does not fit horizontally or we have a mandatory
|
||||||
@ -350,7 +346,7 @@ impl<'a> ParLayouter<'a> {
|
|||||||
// If there is a trailing line break at the end of the
|
// If there is a trailing line break at the end of the
|
||||||
// paragraph, we want to force an empty line.
|
// paragraph, we want to force an empty line.
|
||||||
if mandatory && end == self.bidi.text.len() {
|
if mandatory && end == self.bidi.text.len() {
|
||||||
let line = LineLayout::new(ctx, &self, end .. end);
|
let line = LineLayout::new(vm, &self, end .. end);
|
||||||
if stack.regions.current.y.fits(line.size.y) {
|
if stack.regions.current.y.fits(line.size.y) {
|
||||||
stack.push(line);
|
stack.push(line);
|
||||||
}
|
}
|
||||||
@ -370,7 +366,7 @@ impl<'a> ParLayouter<'a> {
|
|||||||
stack.cts.min.y = Some(stack.size.y);
|
stack.cts.min.y = Some(stack.size.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
stack.finish(ctx)
|
stack.finish(vm)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find the index of the item whose range contains the `text_offset`.
|
/// Find the index of the item whose range contains the `text_offset`.
|
||||||
@ -408,7 +404,7 @@ struct LineLayout<'a> {
|
|||||||
|
|
||||||
impl<'a> LineLayout<'a> {
|
impl<'a> LineLayout<'a> {
|
||||||
/// Create a line which spans the given range.
|
/// Create a line which spans the given range.
|
||||||
fn new(ctx: &mut LayoutContext, par: &'a ParLayouter<'a>, mut line: Range) -> Self {
|
fn new(vm: &mut Vm, par: &'a ParLayouter<'a>, mut line: Range) -> Self {
|
||||||
// Find the items which bound the text range.
|
// Find the items which bound the text range.
|
||||||
let last_idx = par.find(line.end.saturating_sub(1)).unwrap();
|
let last_idx = par.find(line.end.saturating_sub(1)).unwrap();
|
||||||
let first_idx = if line.is_empty() {
|
let first_idx = if line.is_empty() {
|
||||||
@ -438,7 +434,7 @@ impl<'a> LineLayout<'a> {
|
|||||||
// empty string.
|
// empty string.
|
||||||
if !range.is_empty() || rest.is_empty() {
|
if !range.is_empty() || rest.is_empty() {
|
||||||
// Reshape that part.
|
// Reshape that part.
|
||||||
let reshaped = shaped.reshape(ctx.fonts, range);
|
let reshaped = shaped.reshape(vm.fonts, range);
|
||||||
last = Some(ParItem::Text(reshaped));
|
last = Some(ParItem::Text(reshaped));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,7 +455,7 @@ impl<'a> LineLayout<'a> {
|
|||||||
// Reshape if necessary.
|
// Reshape if necessary.
|
||||||
if range.len() < shaped.text.len() {
|
if range.len() < shaped.text.len() {
|
||||||
if !range.is_empty() {
|
if !range.is_empty() {
|
||||||
let reshaped = shaped.reshape(ctx.fonts, range);
|
let reshaped = shaped.reshape(vm.fonts, range);
|
||||||
first = Some(ParItem::Text(reshaped));
|
first = Some(ParItem::Text(reshaped));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -504,7 +500,7 @@ impl<'a> LineLayout<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Build the line's frame.
|
/// Build the line's frame.
|
||||||
fn build(&self, ctx: &LayoutContext, width: Length) -> Frame {
|
fn build(&self, ctx: &Vm, width: Length) -> Frame {
|
||||||
let size = Size::new(self.size.x.max(width), self.size.y);
|
let size = Size::new(self.size.x.max(width), self.size.y);
|
||||||
let remaining = size.x - self.size.x;
|
let remaining = size.x - self.size.x;
|
||||||
|
|
||||||
@ -622,7 +618,7 @@ impl<'a> LineStack<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Finish the frame for one region.
|
/// Finish the frame for one region.
|
||||||
fn finish_region(&mut self, ctx: &LayoutContext) {
|
fn finish_region(&mut self, ctx: &Vm) {
|
||||||
if self.regions.expand.x || self.fractional {
|
if self.regions.expand.x || self.fractional {
|
||||||
self.size.x = self.regions.current.x;
|
self.size.x = self.regions.current.x;
|
||||||
self.cts.exact.x = Some(self.regions.current.x);
|
self.cts.exact.x = Some(self.regions.current.x);
|
||||||
@ -653,7 +649,7 @@ impl<'a> LineStack<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Finish the last region and return the built frames.
|
/// Finish the last region and return the built frames.
|
||||||
fn finish(mut self, ctx: &LayoutContext) -> Vec<Constrained<Arc<Frame>>> {
|
fn finish(mut self, ctx: &Vm) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
self.finish_region(ctx);
|
self.finish_region(ctx);
|
||||||
self.finished
|
self.finished
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ pub struct PlaceNode(pub LayoutNode);
|
|||||||
|
|
||||||
#[class]
|
#[class]
|
||||||
impl PlaceNode {
|
impl PlaceNode {
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
let aligns = args.find()?.unwrap_or(Spec::with_x(Some(Align::Left)));
|
let aligns = args.find()?.unwrap_or(Spec::with_x(Some(Align::Left)));
|
||||||
let tx = args.named("dx")?.unwrap_or_default();
|
let tx = args.named("dx")?.unwrap_or_default();
|
||||||
let ty = args.named("dy")?.unwrap_or_default();
|
let ty = args.named("dy")?.unwrap_or_default();
|
||||||
@ -23,7 +23,7 @@ impl PlaceNode {
|
|||||||
impl Layout for PlaceNode {
|
impl Layout for PlaceNode {
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> Vec<Constrained<Arc<Frame>>> {
|
) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
@ -37,7 +37,7 @@ impl Layout for PlaceNode {
|
|||||||
Regions::one(regions.base, regions.base, expand)
|
Regions::one(regions.base, regions.base, expand)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut frames = self.0.layout(ctx, &pod, styles);
|
let mut frames = self.0.layout(vm, &pod, styles);
|
||||||
let Constrained { item: frame, cts } = &mut frames[0];
|
let Constrained { item: frame, cts } = &mut frames[0];
|
||||||
|
|
||||||
// If expansion is off, zero all sizes so that we don't take up any
|
// If expansion is off, zero all sizes so that we don't take up any
|
||||||
|
@ -31,7 +31,7 @@ impl RawNode {
|
|||||||
/// The language to syntax-highlight in.
|
/// The language to syntax-highlight in.
|
||||||
pub const LANG: Option<EcoString> = None;
|
pub const LANG: Option<EcoString> = None;
|
||||||
|
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
Ok(Template::show(Self {
|
Ok(Template::show(Self {
|
||||||
text: args.expect("text")?,
|
text: args.expect("text")?,
|
||||||
block: args.named("block")?.unwrap_or(false),
|
block: args.named("block")?.unwrap_or(false),
|
||||||
|
@ -20,7 +20,7 @@ impl<const S: ShapeKind> ShapeNode<S> {
|
|||||||
/// How much to pad the shape's content.
|
/// How much to pad the shape's content.
|
||||||
pub const PADDING: Linear = Linear::zero();
|
pub const PADDING: Linear = Linear::zero();
|
||||||
|
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
let size = match S {
|
let size = match S {
|
||||||
SQUARE => args.named::<Length>("size")?.map(Linear::from),
|
SQUARE => args.named::<Length>("size")?.map(Linear::from),
|
||||||
CIRCLE => args.named::<Length>("radius")?.map(|r| 2.0 * Linear::from(r)),
|
CIRCLE => args.named::<Length>("radius")?.map(|r| 2.0 * Linear::from(r)),
|
||||||
@ -46,7 +46,7 @@ impl<const S: ShapeKind> ShapeNode<S> {
|
|||||||
impl<const S: ShapeKind> Layout for ShapeNode<S> {
|
impl<const S: ShapeKind> Layout for ShapeNode<S> {
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> Vec<Constrained<Arc<Frame>>> {
|
) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
@ -61,7 +61,7 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> {
|
|||||||
let child = child.clone().padded(Sides::splat(padding));
|
let child = child.clone().padded(Sides::splat(padding));
|
||||||
|
|
||||||
let mut pod = Regions::one(regions.current, regions.base, regions.expand);
|
let mut pod = Regions::one(regions.current, regions.base, regions.expand);
|
||||||
frames = child.layout(ctx, &pod, styles);
|
frames = child.layout(vm, &pod, styles);
|
||||||
|
|
||||||
// Relayout with full expansion into square region to make sure
|
// Relayout with full expansion into square region to make sure
|
||||||
// the result is really a square or circle.
|
// the result is really a square or circle.
|
||||||
@ -77,7 +77,7 @@ impl<const S: ShapeKind> Layout for ShapeNode<S> {
|
|||||||
|
|
||||||
pod.current = Size::splat(length);
|
pod.current = Size::splat(length);
|
||||||
pod.expand = Spec::splat(true);
|
pod.expand = Spec::splat(true);
|
||||||
frames = child.layout(ctx, &pod, styles);
|
frames = child.layout(vm, &pod, styles);
|
||||||
frames[0].cts = Constraints::tight(regions);
|
frames[0].cts = Constraints::tight(regions);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -7,7 +7,7 @@ pub struct HNode;
|
|||||||
|
|
||||||
#[class]
|
#[class]
|
||||||
impl HNode {
|
impl HNode {
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
Ok(Template::Horizontal(args.expect("spacing")?))
|
Ok(Template::Horizontal(args.expect("spacing")?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -17,7 +17,7 @@ pub struct VNode;
|
|||||||
|
|
||||||
#[class]
|
#[class]
|
||||||
impl VNode {
|
impl VNode {
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
Ok(Template::Vertical(args.expect("spacing")?))
|
Ok(Template::Vertical(args.expect("spacing")?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ pub struct StackNode {
|
|||||||
|
|
||||||
#[class]
|
#[class]
|
||||||
impl StackNode {
|
impl StackNode {
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
Ok(Template::block(Self {
|
Ok(Template::block(Self {
|
||||||
dir: args.named("dir")?.unwrap_or(Dir::TTB),
|
dir: args.named("dir")?.unwrap_or(Dir::TTB),
|
||||||
spacing: args.named("spacing")?,
|
spacing: args.named("spacing")?,
|
||||||
@ -28,7 +28,7 @@ impl StackNode {
|
|||||||
impl Layout for StackNode {
|
impl Layout for StackNode {
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> Vec<Constrained<Arc<Frame>>> {
|
) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
@ -48,7 +48,7 @@ impl Layout for StackNode {
|
|||||||
layouter.layout_spacing(kind);
|
layouter.layout_spacing(kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
layouter.layout_node(ctx, node, styles);
|
layouter.layout_node(vm, node, styles);
|
||||||
deferred = self.spacing;
|
deferred = self.spacing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,12 +163,7 @@ impl StackLayouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Layout an arbitrary node.
|
/// Layout an arbitrary node.
|
||||||
pub fn layout_node(
|
pub fn layout_node(&mut self, vm: &mut Vm, node: &LayoutNode, styles: StyleChain) {
|
||||||
&mut self,
|
|
||||||
ctx: &mut LayoutContext,
|
|
||||||
node: &LayoutNode,
|
|
||||||
styles: StyleChain,
|
|
||||||
) {
|
|
||||||
if self.regions.is_full() {
|
if self.regions.is_full() {
|
||||||
self.finish_region();
|
self.finish_region();
|
||||||
}
|
}
|
||||||
@ -179,7 +174,7 @@ impl StackLayouter {
|
|||||||
.and_then(|node| node.aligns.get(self.axis))
|
.and_then(|node| node.aligns.get(self.axis))
|
||||||
.unwrap_or(self.dir.start().into());
|
.unwrap_or(self.dir.start().into());
|
||||||
|
|
||||||
let frames = node.layout(ctx, &self.regions, styles);
|
let frames = node.layout(vm, &self.regions, styles);
|
||||||
let len = frames.len();
|
let len = frames.len();
|
||||||
for (i, frame) in frames.into_iter().enumerate() {
|
for (i, frame) in frames.into_iter().enumerate() {
|
||||||
// Grow our size, shrink the region and save the frame for later.
|
// Grow our size, shrink the region and save the frame for later.
|
||||||
|
@ -27,7 +27,7 @@ impl TableNode {
|
|||||||
/// How much to pad the cells's content.
|
/// How much to pad the cells's content.
|
||||||
pub const PADDING: Linear = Length::pt(5.0).into();
|
pub const PADDING: Linear = Length::pt(5.0).into();
|
||||||
|
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
let columns = args.named("columns")?.unwrap_or_default();
|
let columns = args.named("columns")?.unwrap_or_default();
|
||||||
let rows = args.named("rows")?.unwrap_or_default();
|
let rows = args.named("rows")?.unwrap_or_default();
|
||||||
let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default();
|
let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default();
|
||||||
|
@ -103,7 +103,7 @@ impl TextNode {
|
|||||||
#[skip]
|
#[skip]
|
||||||
pub const LINK: Option<EcoString> = None;
|
pub const LINK: Option<EcoString> = None;
|
||||||
|
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
// The text constructor is special: It doesn't create a text node.
|
// The text constructor is special: It doesn't create a text node.
|
||||||
// Instead, it leaves the passed argument structurally unchanged, but
|
// Instead, it leaves the passed argument structurally unchanged, but
|
||||||
// styles all text in it.
|
// styles all text in it.
|
||||||
@ -117,7 +117,7 @@ pub struct StrongNode(pub Template);
|
|||||||
|
|
||||||
#[class]
|
#[class]
|
||||||
impl StrongNode {
|
impl StrongNode {
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
Ok(Template::show(Self(args.expect("body")?)))
|
Ok(Template::show(Self(args.expect("body")?)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,7 +134,7 @@ pub struct EmphNode(pub Template);
|
|||||||
|
|
||||||
#[class]
|
#[class]
|
||||||
impl EmphNode {
|
impl EmphNode {
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
Ok(Template::show(Self(args.expect("body")?)))
|
Ok(Template::show(Self(args.expect("body")?)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ impl<const T: TransformKind> TransformNode<T> {
|
|||||||
/// The origin of the transformation.
|
/// The origin of the transformation.
|
||||||
pub const ORIGIN: Spec<Option<Align>> = Spec::default();
|
pub const ORIGIN: Spec<Option<Align>> = Spec::default();
|
||||||
|
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Template> {
|
fn construct(_: &mut Vm, args: &mut Args) -> TypResult<Template> {
|
||||||
let transform = match T {
|
let transform = match T {
|
||||||
MOVE => {
|
MOVE => {
|
||||||
let tx = args.named("x")?.unwrap_or_default();
|
let tx = args.named("x")?.unwrap_or_default();
|
||||||
@ -46,12 +46,12 @@ impl<const T: TransformKind> TransformNode<T> {
|
|||||||
impl<const T: TransformKind> Layout for TransformNode<T> {
|
impl<const T: TransformKind> Layout for TransformNode<T> {
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
vm: &mut Vm,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
styles: StyleChain,
|
styles: StyleChain,
|
||||||
) -> Vec<Constrained<Arc<Frame>>> {
|
) -> Vec<Constrained<Arc<Frame>>> {
|
||||||
let origin = styles.get(Self::ORIGIN).unwrap_or(Align::CENTER_HORIZON);
|
let origin = styles.get(Self::ORIGIN).unwrap_or(Align::CENTER_HORIZON);
|
||||||
let mut frames = self.child.layout(ctx, regions, styles);
|
let mut frames = self.child.layout(vm, regions, styles);
|
||||||
|
|
||||||
for Constrained { item: frame, .. } in &mut frames {
|
for Constrained { item: frame, .. } in &mut frames {
|
||||||
let Spec { x, y } = origin.zip(frame.size).map(|(o, s)| o.resolve(s));
|
let Spec { x, y } = origin.zip(frame.size).map(|(o, s)| o.resolve(s));
|
||||||
|
@ -7,7 +7,7 @@ use super::prelude::*;
|
|||||||
use crate::eval::Array;
|
use crate::eval::Array;
|
||||||
|
|
||||||
/// Ensure that a condition is fulfilled.
|
/// Ensure that a condition is fulfilled.
|
||||||
pub fn assert(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn assert(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
let Spanned { v, span } = args.expect::<Spanned<bool>>("condition")?;
|
let Spanned { v, span } = args.expect::<Spanned<bool>>("condition")?;
|
||||||
if !v {
|
if !v {
|
||||||
bail!(span, "assertion failed");
|
bail!(span, "assertion failed");
|
||||||
@ -16,17 +16,17 @@ pub fn assert(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The name of a value's type.
|
/// The name of a value's type.
|
||||||
pub fn type_(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn type_(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
Ok(args.expect::<Value>("value")?.type_name().into())
|
Ok(args.expect::<Value>("value")?.type_name().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The string representation of a value.
|
/// The string representation of a value.
|
||||||
pub fn repr(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn repr(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
Ok(args.expect::<Value>("value")?.repr().into())
|
Ok(args.expect::<Value>("value")?.repr().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Join a sequence of values, optionally interspersing it with another value.
|
/// Join a sequence of values, optionally interspersing it with another value.
|
||||||
pub fn join(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn join(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
let span = args.span;
|
let span = args.span;
|
||||||
let sep = args.named::<Value>("sep")?.unwrap_or(Value::None);
|
let sep = args.named::<Value>("sep")?.unwrap_or(Value::None);
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ pub fn join(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a value to a integer.
|
/// Convert a value to a integer.
|
||||||
pub fn int(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn int(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
let Spanned { v, span } = args.expect("value")?;
|
let Spanned { v, span } = args.expect("value")?;
|
||||||
Ok(Value::Int(match v {
|
Ok(Value::Int(match v {
|
||||||
Value::Bool(v) => v as i64,
|
Value::Bool(v) => v as i64,
|
||||||
@ -61,7 +61,7 @@ pub fn int(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a value to a float.
|
/// Convert a value to a float.
|
||||||
pub fn float(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn float(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
let Spanned { v, span } = args.expect("value")?;
|
let Spanned { v, span } = args.expect("value")?;
|
||||||
Ok(Value::Float(match v {
|
Ok(Value::Float(match v {
|
||||||
Value::Int(v) => v as f64,
|
Value::Int(v) => v as f64,
|
||||||
@ -75,7 +75,7 @@ pub fn float(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Try to convert a value to a string.
|
/// Try to convert a value to a string.
|
||||||
pub fn str(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn str(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
let Spanned { v, span } = args.expect("value")?;
|
let Spanned { v, span } = args.expect("value")?;
|
||||||
Ok(Value::Str(match v {
|
Ok(Value::Str(match v {
|
||||||
Value::Int(v) => format_eco!("{}", v),
|
Value::Int(v) => format_eco!("{}", v),
|
||||||
@ -86,7 +86,7 @@ pub fn str(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create an RGB(A) color.
|
/// Create an RGB(A) color.
|
||||||
pub fn rgb(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn rgb(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
Ok(Value::from(
|
Ok(Value::from(
|
||||||
if let Some(string) = args.find::<Spanned<EcoString>>()? {
|
if let Some(string) = args.find::<Spanned<EcoString>>()? {
|
||||||
match RgbaColor::from_str(&string.v) {
|
match RgbaColor::from_str(&string.v) {
|
||||||
@ -120,7 +120,7 @@ pub fn rgb(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a CMYK color.
|
/// Create a CMYK color.
|
||||||
pub fn cmyk(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn cmyk(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
struct Component(u8);
|
struct Component(u8);
|
||||||
|
|
||||||
castable! {
|
castable! {
|
||||||
@ -141,7 +141,7 @@ pub fn cmyk(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The absolute value of a numeric value.
|
/// The absolute value of a numeric value.
|
||||||
pub fn abs(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn abs(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
let Spanned { v, span } = args.expect("numeric value")?;
|
let Spanned { v, span } = args.expect("numeric value")?;
|
||||||
Ok(match v {
|
Ok(match v {
|
||||||
Value::Int(v) => Value::Int(v.abs()),
|
Value::Int(v) => Value::Int(v.abs()),
|
||||||
@ -156,27 +156,27 @@ pub fn abs(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The minimum of a sequence of values.
|
/// The minimum of a sequence of values.
|
||||||
pub fn min(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn min(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
minmax(args, Ordering::Less)
|
minmax(args, Ordering::Less)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The maximum of a sequence of values.
|
/// The maximum of a sequence of values.
|
||||||
pub fn max(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn max(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
minmax(args, Ordering::Greater)
|
minmax(args, Ordering::Greater)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether an integer is even.
|
/// Whether an integer is even.
|
||||||
pub fn even(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn even(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
Ok(Value::Bool(args.expect::<i64>("integer")? % 2 == 0))
|
Ok(Value::Bool(args.expect::<i64>("integer")? % 2 == 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether an integer is odd.
|
/// Whether an integer is odd.
|
||||||
pub fn odd(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn odd(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
Ok(Value::Bool(args.expect::<i64>("integer")? % 2 != 0))
|
Ok(Value::Bool(args.expect::<i64>("integer")? % 2 != 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The modulo of two numbers.
|
/// The modulo of two numbers.
|
||||||
pub fn modulo(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn modulo(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
let Spanned { v: v1, span: span1 } = args.expect("integer or float")?;
|
let Spanned { v: v1, span: span1 } = args.expect("integer or float")?;
|
||||||
let Spanned { v: v2, span: span2 } = args.expect("integer or float")?;
|
let Spanned { v: v2, span: span2 } = args.expect("integer or float")?;
|
||||||
|
|
||||||
@ -227,7 +227,7 @@ fn minmax(args: &mut Args, goal: Ordering) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a sequence of numbers.
|
/// Create a sequence of numbers.
|
||||||
pub fn range(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn range(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
let first = args.expect::<i64>("end")?;
|
let first = args.expect::<i64>("end")?;
|
||||||
let (start, end) = match args.eat::<i64>()? {
|
let (start, end) = match args.eat::<i64>()? {
|
||||||
Some(second) => (first, second),
|
Some(second) => (first, second),
|
||||||
@ -252,19 +252,19 @@ pub fn range(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a string to lowercase.
|
/// Convert a string to lowercase.
|
||||||
pub fn lower(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn lower(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
Ok(args.expect::<EcoString>("string")?.to_lowercase().into())
|
Ok(args.expect::<EcoString>("string")?.to_lowercase().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a string to uppercase.
|
/// Convert a string to uppercase.
|
||||||
pub fn upper(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn upper(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
Ok(args.expect::<EcoString>("string")?.to_uppercase().into())
|
Ok(args.expect::<EcoString>("string")?.to_uppercase().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts an integer into a roman numeral.
|
/// Converts an integer into a roman numeral.
|
||||||
///
|
///
|
||||||
/// Works for integer between 0 and 3,999,999.
|
/// Works for integer between 0 and 3,999,999.
|
||||||
pub fn roman(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn roman(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
// Adapted from Yann Villessuzanne's roman.rs under the Unlicense, at
|
// Adapted from Yann Villessuzanne's roman.rs under the Unlicense, at
|
||||||
// https://github.com/linfir/roman.rs/
|
// https://github.com/linfir/roman.rs/
|
||||||
static PAIRS: &'static [(&'static str, usize)] = &[
|
static PAIRS: &'static [(&'static str, usize)] = &[
|
||||||
@ -314,7 +314,7 @@ pub fn roman(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a number into a roman numeral.
|
/// Convert a number into a roman numeral.
|
||||||
pub fn symbol(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn symbol(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
static SYMBOLS: &'static [char] = &['*', '†', '‡', '§', '‖', '¶'];
|
static SYMBOLS: &'static [char] = &['*', '†', '‡', '§', '‖', '¶'];
|
||||||
|
|
||||||
let n = args.expect::<usize>("non-negative integer")?;
|
let n = args.expect::<usize>("non-negative integer")?;
|
||||||
@ -327,7 +327,7 @@ pub fn symbol(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The length of a string, an array or a dictionary.
|
/// The length of a string, an array or a dictionary.
|
||||||
pub fn len(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn len(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
let Spanned { v, span } = args.expect("collection")?;
|
let Spanned { v, span } = args.expect("collection")?;
|
||||||
Ok(Value::Int(match v {
|
Ok(Value::Int(match v {
|
||||||
Value::Str(v) => v.len() as i64,
|
Value::Str(v) => v.len() as i64,
|
||||||
@ -342,7 +342,7 @@ pub fn len(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The sorted version of an array.
|
/// The sorted version of an array.
|
||||||
pub fn sorted(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn sorted(_: &mut Vm, args: &mut Args) -> TypResult<Value> {
|
||||||
let Spanned { v, span } = args.expect::<Spanned<Array>>("array")?;
|
let Spanned { v, span } = args.expect::<Spanned<Array>>("array")?;
|
||||||
Ok(Value::Array(v.sorted().at(span)?))
|
Ok(Value::Array(v.sorted().at(span)?))
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ use typst::loading::FsLoader;
|
|||||||
use typst::parse::Scanner;
|
use typst::parse::Scanner;
|
||||||
use typst::source::SourceFile;
|
use typst::source::SourceFile;
|
||||||
use typst::syntax::Span;
|
use typst::syntax::Span;
|
||||||
use typst::Context;
|
use typst::{Context, Vm};
|
||||||
|
|
||||||
#[cfg(feature = "layout-cache")]
|
#[cfg(feature = "layout-cache")]
|
||||||
use {
|
use {
|
||||||
@ -274,13 +274,14 @@ fn test_part(
|
|||||||
|
|
||||||
ok &= test_reparse(ctx.sources.get(id).src(), i, rng);
|
ok &= test_reparse(ctx.sources.get(id).src(), i, rng);
|
||||||
|
|
||||||
let (frames, mut errors) = match ctx.evaluate(id) {
|
let mut vm = Vm::new(ctx);
|
||||||
|
let (frames, mut errors) = match vm.evaluate(id) {
|
||||||
Ok(module) => {
|
Ok(module) => {
|
||||||
if debug {
|
if debug {
|
||||||
println!("Template: {:#?}", module.template);
|
println!("Template: {:#?}", module.template);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut frames = module.template.layout(ctx);
|
let mut frames = module.template.layout(&mut vm);
|
||||||
|
|
||||||
#[cfg(feature = "layout-cache")]
|
#[cfg(feature = "layout-cache")]
|
||||||
(ok &= test_incremental(ctx, i, &module.template, &frames));
|
(ok &= test_incremental(ctx, i, &module.template, &frames));
|
||||||
@ -498,7 +499,7 @@ fn test_incremental(
|
|||||||
|
|
||||||
ctx.layout_cache.turnaround();
|
ctx.layout_cache.turnaround();
|
||||||
|
|
||||||
let cached = silenced(|| template.layout(ctx));
|
let cached = silenced(|| template.layout(&mut Vm::new(ctx)));
|
||||||
let total = reference.levels() - 1;
|
let total = reference.levels() - 1;
|
||||||
let misses = ctx
|
let misses = ctx
|
||||||
.layout_cache
|
.layout_cache
|
||||||
|
Loading…
x
Reference in New Issue
Block a user