diff --git a/benches/oneshot.rs b/benches/oneshot.rs index 5c0fc701e..fef0e6e13 100644 --- a/benches/oneshot.rs +++ b/benches/oneshot.rs @@ -4,10 +4,10 @@ use std::sync::Arc; use iai::{black_box, main, Iai}; use unscanny::Scanner; +use typst::eval::evaluate; use typst::loading::MemLoader; -use typst::parse::{parse, TokenMode, Tokens}; +use typst::parse::{TokenMode, Tokens}; use typst::source::SourceId; -use typst::syntax::highlight_node; use typst::{Config, Context}; const SRC: &str = include_str!("bench.typ"); @@ -61,7 +61,7 @@ fn bench_tokenize(iai: &mut Iai) { } fn bench_parse(iai: &mut Iai) { - iai.run(|| parse(SRC)); + iai.run(|| typst::parse::parse(SRC)); } fn bench_edit(iai: &mut Iai) { @@ -73,7 +73,7 @@ fn bench_highlight(iai: &mut Iai) { let (ctx, id) = context(); let source = ctx.sources.get(id); iai.run(|| { - highlight_node( + typst::syntax::highlight_node( source.red().as_ref(), 0 .. source.len_bytes(), &mut |_, _| {}, @@ -83,17 +83,17 @@ fn bench_highlight(iai: &mut Iai) { fn bench_eval(iai: &mut Iai) { let (mut ctx, id) = context(); - iai.run(|| ctx.evaluate(id).unwrap()); + iai.run(|| typst::eval::evaluate(&mut ctx, id, vec![]).unwrap()); } fn bench_layout(iai: &mut Iai) { let (mut ctx, id) = context(); - let module = ctx.evaluate(id).unwrap(); - iai.run(|| module.content.layout(&mut ctx)); + let module = evaluate(&mut ctx, id, vec![]).unwrap(); + iai.run(|| typst::model::layout(&mut ctx, &module.content)); } fn bench_render(iai: &mut Iai) { let (mut ctx, id) = context(); - let frames = ctx.typeset(id).unwrap(); + let frames = typst::typeset(&mut ctx, id).unwrap(); iai.run(|| typst::export::render(&mut ctx, &frames[0], 1.0)) } diff --git a/src/eval/args.rs b/src/eval/args.rs index 9b21cfa2b..69e6aaee5 100644 --- a/src/eval/args.rs +++ b/src/eval/args.rs @@ -26,13 +26,8 @@ pub struct Arg { } impl Args { - /// Create empty arguments from a span. - pub fn new(span: Span) -> Self { - Self { span, items: vec![] } - } - /// Create positional arguments from a span and values. - pub fn from_values(span: Span, values: impl IntoIterator) -> Self { + pub fn new(span: Span, values: impl IntoIterator) -> Self { let items = values .into_iter() .map(|value| Arg { diff --git a/src/eval/array.rs b/src/eval/array.rs index 86347106b..840c0aef6 100644 --- a/src/eval/array.rs +++ b/src/eval/array.rs @@ -3,11 +3,10 @@ use std::fmt::{self, Debug, Formatter, Write}; use std::ops::{Add, AddAssign}; use std::sync::Arc; -use super::{ops, Args, Func, Value}; +use super::{ops, Args, Func, Machine, Value}; use crate::diag::{At, StrResult, TypResult}; use crate::syntax::Spanned; use crate::util::ArcExt; -use crate::Context; /// Create a new [`Array`] from values. #[allow(unused_macros)] @@ -120,21 +119,21 @@ impl Array { } /// Transform each item in the array with a function. - pub fn map(&self, ctx: &mut Context, f: Spanned) -> TypResult { + pub fn map(&self, vm: &mut Machine, f: Spanned) -> TypResult { Ok(self .iter() .cloned() - .map(|item| f.v.call(ctx, Args::from_values(f.span, [item]))) + .map(|item| f.v.call(vm, Args::new(f.span, [item]))) .collect::>()?) } /// Return a new array with only those elements for which the function /// return true. - pub fn filter(&self, ctx: &mut Context, f: Spanned) -> TypResult { + pub fn filter(&self, vm: &mut Machine, f: Spanned) -> TypResult { let mut kept = vec![]; for item in self.iter() { if f.v - .call(ctx, Args::from_values(f.span, [item.clone()]))? + .call(vm, Args::new(f.span, [item.clone()]))? .cast::() .at(f.span)? { diff --git a/src/eval/dict.rs b/src/eval/dict.rs index 22b73e769..35bd75d5f 100644 --- a/src/eval/dict.rs +++ b/src/eval/dict.rs @@ -3,12 +3,11 @@ use std::fmt::{self, Debug, Formatter, Write}; use std::ops::{Add, AddAssign}; use std::sync::Arc; -use super::{Args, Array, Func, Value}; +use super::{Args, Array, Func, Machine, Value}; use crate::diag::{StrResult, TypResult}; use crate::parse::is_ident; use crate::syntax::Spanned; use crate::util::{ArcExt, EcoString}; -use crate::Context; /// Create a new [`Dict`] from key-value pairs. #[allow(unused_macros)] @@ -97,14 +96,12 @@ impl Dict { } /// Transform each pair in the array with a function. - pub fn map(&self, ctx: &mut Context, f: Spanned) -> TypResult { + pub fn map(&self, vm: &mut Machine, f: Spanned) -> TypResult { Ok(self .iter() .map(|(key, value)| { - f.v.call( - ctx, - Args::from_values(f.span, [Value::Str(key.clone()), value.clone()]), - ) + let args = Args::new(f.span, [Value::Str(key.clone()), value.clone()]); + f.v.call(vm, args) }) .collect::>()?) } diff --git a/src/eval/func.rs b/src/eval/func.rs index 83171ce70..16575c80a 100644 --- a/src/eval/func.rs +++ b/src/eval/func.rs @@ -29,7 +29,7 @@ impl Func { /// Create a new function from a native rust function. pub fn from_fn( name: &'static str, - func: fn(&mut Context, &mut Args) -> TypResult, + func: fn(&mut Machine, &mut Args) -> TypResult, ) -> Self { Self(Arc::new(Repr::Native(Native { name, @@ -86,19 +86,25 @@ impl Func { } /// Call the function with the given arguments. - pub fn call(&self, ctx: &mut Context, mut args: Args) -> TypResult { + pub fn call(&self, vm: &mut Machine, mut args: Args) -> TypResult { let value = match self.0.as_ref() { - Repr::Native(native) => (native.func)(ctx, &mut args)?, - Repr::Closure(closure) => closure.call(ctx, &mut args)?, + Repr::Native(native) => (native.func)(vm, &mut args)?, + Repr::Closure(closure) => closure.call(vm, &mut args)?, Repr::With(wrapped, applied) => { args.items.splice(.. 0, applied.items.iter().cloned()); - return wrapped.call(ctx, args); + return wrapped.call(vm, args); } }; args.finish()?; Ok(value) } + /// Call the function without an existing virtual machine. + pub fn call_detached(&self, ctx: &mut Context, args: Args) -> TypResult { + let mut vm = Machine::new(ctx, vec![], Scopes::new(None)); + self.call(&mut vm, args) + } + /// Execute the function's set rule. pub fn set(&self, mut args: Args) -> TypResult { let styles = match self.0.as_ref() { @@ -138,7 +144,7 @@ struct Native { /// The name of the function. pub name: &'static str, /// The function pointer. - pub func: fn(&mut Context, &mut Args) -> TypResult, + pub func: fn(&mut Machine, &mut Args) -> TypResult, /// The set rule. pub set: Option TypResult>, /// The id of the node to customize with this function's show rule. @@ -163,7 +169,7 @@ pub trait Node: 'static { /// /// This is passed only the arguments that remain after execution of the /// node's set rule. - fn construct(ctx: &mut Context, args: &mut Args) -> TypResult; + fn construct(vm: &mut Machine, args: &mut Args) -> TypResult; /// Parse the arguments into style properties for this node. /// @@ -192,7 +198,7 @@ pub struct Closure { impl Closure { /// Call the function in the context with the arguments. - pub fn call(&self, ctx: &mut Context, args: &mut Args) -> TypResult { + pub fn call(&self, vm: &mut Machine, args: &mut Args) -> TypResult { // Don't leak the scopes from the call site. Instead, we use the // scope of captured variables we collected earlier. let mut scopes = Scopes::new(None); @@ -213,24 +219,20 @@ impl Closure { scopes.top.def_mut(sink, args.take()); } - // Set the new route if we are detached. - let detached = ctx.route.is_empty(); - if detached { - ctx.route = self.location.into_iter().collect(); - } + // Determine the route inside the closure. + let detached = vm.route.is_empty(); + let route = if detached { + self.location.into_iter().collect() + } else { + vm.route.clone() + }; // Evaluate the body. - let mut vm = Machine::new(ctx, scopes); - let result = self.body.eval(&mut vm); - let flow = vm.flow; - - // Restore the old route. - if detached { - ctx.route.clear(); - } + let mut sub = Machine::new(vm.ctx, route, scopes); + let result = self.body.eval(&mut sub); // Handle control flow. - match flow { + match sub.flow { Some(Flow::Return(_, Some(explicit))) => return Ok(explicit), Some(Flow::Return(_, None)) => {} Some(flow) => return Err(flow.forbidden())?, diff --git a/src/eval/machine.rs b/src/eval/machine.rs index 168cedcbc..146339788 100644 --- a/src/eval/machine.rs +++ b/src/eval/machine.rs @@ -1,12 +1,18 @@ +use std::path::PathBuf; + use super::{Scopes, Value}; -use crate::diag::TypError; +use crate::diag::{StrResult, TypError}; +use crate::source::SourceId; use crate::syntax::Span; +use crate::util::PathExt; use crate::Context; /// A virtual machine. pub struct Machine<'a> { /// The core context. pub ctx: &'a mut Context, + /// The route of source ids at which the machine is located. + pub route: Vec, /// The stack of scopes. pub scopes: Scopes<'a>, /// A control flow event that is currently happening. @@ -15,8 +21,24 @@ pub struct Machine<'a> { impl<'a> Machine<'a> { /// Create a new virtual machine. - pub fn new(ctx: &'a mut Context, scopes: Scopes<'a>) -> Self { - Self { ctx, scopes, flow: None } + pub fn new(ctx: &'a mut Context, route: Vec, scopes: Scopes<'a>) -> Self { + Self { ctx, route, scopes, flow: None } + } + + /// Resolve a user-entered path to be relative to the compilation + /// environment's root. + pub fn locate(&self, path: &str) -> StrResult { + if let Some(&id) = self.route.last() { + if let Some(path) = path.strip_prefix('/') { + return Ok(self.ctx.config.root.join(path).normalize()); + } + + if let Some(dir) = self.ctx.sources.get(id).path().parent() { + return Ok(dir.join(path).normalize()); + } + } + + return Err("cannot access file system from here".into()); } } diff --git a/src/eval/methods.rs b/src/eval/methods.rs index 88f173c70..f6de614f2 100644 --- a/src/eval/methods.rs +++ b/src/eval/methods.rs @@ -1,14 +1,13 @@ //! Methods on values. -use super::{Args, Regex, StrExt, Value}; +use super::{Args, Machine, Regex, StrExt, Value}; use crate::diag::{At, TypResult}; use crate::syntax::Span; use crate::util::EcoString; -use crate::Context; /// Call a method on a value. pub fn call( - ctx: &mut Context, + vm: &mut Machine, value: Value, method: &str, mut args: Args, @@ -35,8 +34,8 @@ pub fn call( } Value::Array(array.slice(start, end).at(span)?) } - "map" => Value::Array(array.map(ctx, args.expect("function")?)?), - "filter" => Value::Array(array.filter(ctx, args.expect("function")?)?), + "map" => Value::Array(array.map(vm, args.expect("function")?)?), + "filter" => Value::Array(array.filter(vm, args.expect("function")?)?), "flatten" => Value::Array(array.flatten()), "find" => array.find(args.expect("value")?).map_or(Value::None, Value::Int), "join" => { @@ -52,7 +51,7 @@ pub fn call( "len" => Value::Int(dict.len()), "keys" => Value::Array(dict.keys()), "values" => Value::Array(dict.values()), - "pairs" => Value::Array(dict.map(ctx, args.expect("function")?)?), + "pairs" => Value::Array(dict.map(vm, args.expect("function")?)?), _ => missing()?, }, diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 2b853586a..702a76b2f 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -43,13 +43,63 @@ use crate::syntax::{Span, Spanned}; use crate::util::EcoString; use crate::Context; -/// Evaluate an expression. -pub trait Eval { - /// The output of evaluating the expression. - type Output; +/// Evaluate a source file and return the resulting module. +/// +/// Returns either a module containing a scope with top-level bindings and +/// layoutable contents or diagnostics in the form of a vector of error +/// messages with file and span information. +pub fn evaluate( + ctx: &mut Context, + id: SourceId, + mut route: Vec, +) -> TypResult { + // Prevent cyclic evaluation. + if route.contains(&id) { + let path = ctx.sources.get(id).path().display(); + panic!("Tried to cyclicly evaluate {}", path); + } - /// Evaluate the expression to the output value. - fn eval(&self, vm: &mut Machine) -> TypResult; + // Check whether the module was already evaluated. + if let Some(module) = ctx.modules.get(&id) { + if module.valid(&ctx.sources) { + return Ok(module.clone()); + } else { + ctx.modules.remove(&id); + } + } + + route.push(id); + + // Parse the file. + let source = ctx.sources.get(id); + let ast = source.ast()?; + + // Save the old dependencies. + let prev_deps = std::mem::replace(&mut ctx.deps, vec![(id, source.rev())]); + + // Evaluate the module. + let std = ctx.config.std.clone(); + let scopes = Scopes::new(Some(&std)); + let mut vm = Machine::new(ctx, route, scopes); + let result = ast.eval(&mut vm); + let scope = vm.scopes.top; + let flow = vm.flow; + + // Restore the and dependencies. + let deps = std::mem::replace(&mut ctx.deps, prev_deps); + + // Handle control flow. + if let Some(flow) = flow { + return Err(flow.forbidden()); + } + + // Assemble the module. + let module = Module { scope, content: result?, deps }; + + // Save the evaluated module. + ctx.modules.insert(id, module.clone()); + + Ok(module) } /// An evaluated module, ready for importing or layouting. @@ -70,6 +120,15 @@ impl Module { } } +/// Evaluate an expression. +pub trait Eval { + /// The output of evaluating the expression. + type Output; + + /// Evaluate the expression to the output value. + fn eval(&self, vm: &mut Machine) -> TypResult; +} + impl Eval for Markup { type Output = Content; @@ -553,7 +612,7 @@ impl Eval for FuncCall { Value::Dict(dict) => dict.get(&args.into_key()?).at(self.span())?.clone(), Value::Func(func) => { let point = || Tracepoint::Call(func.name().map(ToString::to_string)); - func.call(vm.ctx, args).trace(point, self.span())? + func.call(vm, args).trace(point, self.span())? } v => bail!( @@ -581,7 +640,7 @@ impl Eval for MethodCall { } else { let value = self.receiver().eval(vm)?; let args = self.args().eval(vm)?; - methods::call(vm.ctx, value, &method, args, span).trace(point, span)? + methods::call(vm, value, &method, args, span).trace(point, span)? }) } } @@ -672,7 +731,7 @@ impl Eval for ClosureExpr { // Define the actual function. Ok(Value::Func(Func::from_closure(Closure { - location: vm.ctx.route.last().copied(), + location: vm.route.last().copied(), name, captured, params, @@ -731,7 +790,7 @@ impl Eval for ShowExpr { let body = self.body(); let span = body.span(); let func = Func::from_closure(Closure { - location: vm.ctx.route.last().copied(), + location: vm.route.last().copied(), name: None, captured, params, @@ -875,7 +934,7 @@ impl Eval for ImportExpr { fn eval(&self, vm: &mut Machine) -> TypResult { let span = self.path().span(); let path = self.path().eval(vm)?.cast::().at(span)?; - let module = import(vm.ctx, &path, span)?; + let module = import(vm, &path, span)?; match self.imports() { Imports::Wildcard => { @@ -904,16 +963,16 @@ impl Eval for IncludeExpr { fn eval(&self, vm: &mut Machine) -> TypResult { let span = self.path().span(); let path = self.path().eval(vm)?.cast::().at(span)?; - let module = import(vm.ctx, &path, span)?; + let module = import(vm, &path, span)?; Ok(module.content.clone()) } } /// Process an import of a module relative to the current location. -fn import(ctx: &mut Context, path: &str, span: Span) -> TypResult { +fn import(vm: &mut Machine, path: &str, span: Span) -> TypResult { // Load the source file. - let full = ctx.locate(&path).at(span)?; - let id = ctx.sources.load(&full).map_err(|err| match err.kind() { + let full = vm.locate(&path).at(span)?; + let id = vm.ctx.sources.load(&full).map_err(|err| match err.kind() { std::io::ErrorKind::NotFound => { error!(span, "file not found (searched at {})", full.display()) } @@ -921,13 +980,14 @@ fn import(ctx: &mut Context, path: &str, span: Span) -> TypResult { })?; // Prevent cyclic importing. - if ctx.route.contains(&id) { + if vm.route.contains(&id) { bail!(span, "cyclic import"); } // Evaluate the file. - let module = ctx.evaluate(id).trace(|| Tracepoint::Import, span)?; - ctx.deps.extend(module.deps.iter().cloned()); + let route = vm.route.clone(); + let module = evaluate(vm.ctx, id, route).trace(|| Tracepoint::Import, span)?; + vm.ctx.deps.extend(module.deps.iter().cloned()); Ok(module) } diff --git a/src/eval/scope.rs b/src/eval/scope.rs index 8acaa4314..8a0b81659 100644 --- a/src/eval/scope.rs +++ b/src/eval/scope.rs @@ -6,10 +6,9 @@ use std::sync::Arc; use parking_lot::RwLock; -use super::{Args, Func, Node, Value}; +use super::{Args, Func, Machine, Node, Value}; use crate::diag::TypResult; use crate::util::EcoString; -use crate::Context; /// A slot where a variable is stored. pub type Slot = Arc>; @@ -89,7 +88,7 @@ impl Scope { pub fn def_fn( &mut self, name: &'static str, - func: fn(&mut Context, &mut Args) -> TypResult, + func: fn(&mut Machine, &mut Args) -> TypResult, ) { self.def_const(name, Func::from_fn(name, func)); } diff --git a/src/export/render.rs b/src/export/render.rs index 34fb43317..9c37791e1 100644 --- a/src/export/render.rs +++ b/src/export/render.rs @@ -23,7 +23,7 @@ use crate::Context; /// In addition to the frame, you need to pass in the context used during /// compilation so that fonts and images can be rendered and rendering artifacts /// can be cached. -pub fn render(ctx: &mut Context, frame: &Frame, pixel_per_pt: f32) -> sk::Pixmap { +pub fn render(ctx: &Context, frame: &Frame, pixel_per_pt: f32) -> sk::Pixmap { let pxw = (pixel_per_pt * frame.size.x.to_f32()).round().max(1.0) as u32; let pxh = (pixel_per_pt * frame.size.y.to_f32()).round().max(1.0) as u32; @@ -41,7 +41,7 @@ fn render_frame( canvas: &mut sk::Pixmap, ts: sk::Transform, mask: Option<&sk::ClipMask>, - ctx: &mut Context, + ctx: &Context, frame: &Frame, ) { for (pos, element) in &frame.elements { @@ -72,7 +72,7 @@ fn render_group( canvas: &mut sk::Pixmap, ts: sk::Transform, mask: Option<&sk::ClipMask>, - ctx: &mut Context, + ctx: &Context, group: &Group, ) { let ts = ts.pre_concat(group.transform.into()); @@ -114,7 +114,7 @@ fn render_text( canvas: &mut sk::Pixmap, ts: sk::Transform, mask: Option<&sk::ClipMask>, - ctx: &mut Context, + ctx: &Context, text: &Text, ) { let mut x = 0.0; @@ -136,7 +136,7 @@ fn render_svg_glyph( canvas: &mut sk::Pixmap, ts: sk::Transform, _: Option<&sk::ClipMask>, - ctx: &mut Context, + ctx: &Context, text: &Text, id: GlyphId, ) -> Option<()> { @@ -187,7 +187,7 @@ fn render_bitmap_glyph( canvas: &mut sk::Pixmap, ts: sk::Transform, mask: Option<&sk::ClipMask>, - ctx: &mut Context, + ctx: &Context, text: &Text, id: GlyphId, ) -> Option<()> { @@ -213,7 +213,7 @@ fn render_outline_glyph( canvas: &mut sk::Pixmap, ts: sk::Transform, mask: Option<&sk::ClipMask>, - ctx: &mut Context, + ctx: &Context, text: &Text, id: GlyphId, ) -> Option<()> { diff --git a/src/lib.rs b/src/lib.rs index ab2128c00..81c4afe69 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,10 +21,10 @@ //! [parsed]: parse::parse //! [green tree]: syntax::GreenNode //! [AST]: syntax::ast -//! [evaluate]: eval::Eval +//! [evaluate]: eval::evaluate //! [module]: eval::Module //! [content]: model::Content -//! [layouted]: model::Content::layout +//! [layouted]: model::layout //! [PDF]: export::pdf #![allow(clippy::len_without_is_empty)] @@ -52,19 +52,27 @@ pub mod source; pub mod syntax; use std::collections::HashMap; -use std::mem; use std::path::PathBuf; use std::sync::Arc; -use crate::diag::{StrResult, TypResult}; -use crate::eval::{Eval, Machine, Module, Scope, Scopes}; +use crate::diag::TypResult; +use crate::eval::{Module, Scope}; use crate::font::FontStore; use crate::frame::Frame; use crate::image::ImageStore; use crate::loading::Loader; use crate::model::StyleMap; use crate::source::{SourceId, SourceStore}; -use crate::util::PathExt; + +/// 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(ctx: &mut Context, id: SourceId) -> TypResult>> { + let module = eval::evaluate(ctx, id, vec![])?; + model::layout(ctx, &module.content) +} /// The core context which holds the configuration and stores. pub struct Context { @@ -78,8 +86,6 @@ pub struct Context { pub config: Config, /// Cached modules. modules: HashMap, - /// The stack of imported files that led to evaluation of the current file. - route: Vec, /// The dependencies of the current evaluation process. deps: Vec<(SourceId, usize)>, } @@ -93,90 +99,9 @@ impl Context { images: ImageStore::new(loader), config, modules: HashMap::new(), - route: vec![], deps: vec![], } } - - /// Evaluate a source file and return the resulting module. - /// - /// Returns either a module containing a scope with top-level bindings and - /// layoutable contents or diagnostics in the form of a vector of error - /// messages with file and span information. - pub fn evaluate(&mut self, id: SourceId) -> TypResult { - // Prevent cyclic evaluation. - if self.route.contains(&id) { - let path = self.sources.get(id).path().display(); - panic!("Tried to cyclicly evaluate {}", path); - } - - // Check whether the module was already evaluated. - if let Some(module) = self.modules.get(&id) { - if module.valid(&self.sources) { - return Ok(module.clone()); - } else { - self.modules.remove(&id); - } - } - - // Parse the file. - let source = self.sources.get(id); - let ast = source.ast()?; - - // Save the old dependencies and update the route. - let prev_deps = mem::replace(&mut self.deps, vec![(id, source.rev())]); - self.route.push(id); - - // Evaluate the module. - let std = self.config.std.clone(); - let scopes = Scopes::new(Some(&std)); - let mut vm = Machine::new(self, scopes); - let result = ast.eval(&mut vm); - let scope = vm.scopes.top; - let flow = vm.flow; - - // Restore the old route and dependencies. - self.route.pop().unwrap(); - let deps = mem::replace(&mut self.deps, prev_deps); - - // Handle control flow. - if let Some(flow) = flow { - return Err(flow.forbidden()); - } - - // Assemble the module. - let module = Module { scope, content: result?, deps }; - - // Save the evaluated module. - 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>> { - self.evaluate(id)?.content.layout(self) - } - - /// Resolve a user-entered path to be relative to the compilation - /// environment's root. - fn locate(&self, path: &str) -> StrResult { - if let Some(&id) = self.route.last() { - if let Some(path) = path.strip_prefix('/') { - return Ok(self.config.root.join(path).normalize()); - } - - if let Some(dir) = self.sources.get(id).path().parent() { - return Ok(dir.join(path).normalize()); - } - } - - return Err("cannot access file system from here".into()); - } } /// Compilation configuration. diff --git a/src/library/graphics/hide.rs b/src/library/graphics/hide.rs index 85971c36e..28afe3204 100644 --- a/src/library/graphics/hide.rs +++ b/src/library/graphics/hide.rs @@ -6,7 +6,7 @@ pub struct HideNode(pub LayoutNode); #[node] impl HideNode { - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { Ok(Content::inline(Self(args.expect("body")?))) } } diff --git a/src/library/graphics/image.rs b/src/library/graphics/image.rs index 6fd465cbf..d0bcfa446 100644 --- a/src/library/graphics/image.rs +++ b/src/library/graphics/image.rs @@ -11,12 +11,12 @@ impl ImageNode { /// How the image should adjust itself to a given area. pub const FIT: ImageFit = ImageFit::Cover; - fn construct(ctx: &mut Context, args: &mut Args) -> TypResult { + fn construct(vm: &mut Machine, args: &mut Args) -> TypResult { let Spanned { v: path, span } = args.expect::>("path to image file")?; - let full = ctx.locate(&path).at(span)?; - let id = ctx.images.load(&full).map_err(|err| match err.kind() { + let full = vm.locate(&path).at(span)?; + let id = vm.ctx.images.load(&full).map_err(|err| match err.kind() { std::io::ErrorKind::NotFound => { error!(span, "file not found (searched at {})", full.display()) } diff --git a/src/library/graphics/line.rs b/src/library/graphics/line.rs index de2e4aa1d..8e5ceae12 100644 --- a/src/library/graphics/line.rs +++ b/src/library/graphics/line.rs @@ -15,7 +15,7 @@ impl LineNode { #[property(resolve, fold)] pub const STROKE: RawStroke = RawStroke::default(); - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { let origin = args.named("origin")?.unwrap_or_default(); let delta = match args.named::>>("to")? { diff --git a/src/library/graphics/shape.rs b/src/library/graphics/shape.rs index bc768628b..9da8d8df6 100644 --- a/src/library/graphics/shape.rs +++ b/src/library/graphics/shape.rs @@ -37,7 +37,7 @@ impl ShapeNode { #[property(skip, resolve, fold)] pub const RADIUS: Sides>> = Sides::splat(Relative::zero()); - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { let size = match S { SQUARE => args.named::("size")?.map(Relative::from), CIRCLE => args.named::("radius")?.map(|r| 2.0 * Relative::from(r)), diff --git a/src/library/graphics/transform.rs b/src/library/graphics/transform.rs index a4aa20dba..9fcf7ebb4 100644 --- a/src/library/graphics/transform.rs +++ b/src/library/graphics/transform.rs @@ -12,7 +12,7 @@ pub struct MoveNode { #[node] impl MoveNode { - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { let dx = args.named("dx")?.unwrap_or_default(); let dy = args.named("dy")?.unwrap_or_default(); Ok(Content::inline(Self { @@ -62,7 +62,7 @@ impl TransformNode { #[property(resolve)] pub const ORIGIN: Spec> = Spec::default(); - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { let transform = match T { ROTATE => { let angle = args.named_or_find("angle")?.unwrap_or_default(); diff --git a/src/library/layout/align.rs b/src/library/layout/align.rs index c050d2a44..c0a7d16c2 100644 --- a/src/library/layout/align.rs +++ b/src/library/layout/align.rs @@ -12,7 +12,7 @@ pub struct AlignNode { #[node] impl AlignNode { - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { let aligns: Spec> = args.find()?.unwrap_or_default(); let body: Content = args.expect("body")?; Ok(match (body, aligns) { diff --git a/src/library/layout/columns.rs b/src/library/layout/columns.rs index 8e5236946..4c8422612 100644 --- a/src/library/layout/columns.rs +++ b/src/library/layout/columns.rs @@ -17,7 +17,7 @@ impl ColumnsNode { #[property(resolve)] pub const GUTTER: Relative = Ratio::new(0.04).into(); - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { Ok(Content::block(Self { columns: args.expect("column count")?, child: args.expect("body")?, @@ -106,7 +106,7 @@ pub struct ColbreakNode; #[node] impl ColbreakNode { - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { let weak = args.named("weak")?.unwrap_or(false); Ok(Content::Colbreak { weak }) } diff --git a/src/library/layout/container.rs b/src/library/layout/container.rs index 5264f2580..df03ac91e 100644 --- a/src/library/layout/container.rs +++ b/src/library/layout/container.rs @@ -5,7 +5,7 @@ pub struct BoxNode; #[node] impl BoxNode { - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { let width = args.named("width")?; let height = args.named("height")?; let body: LayoutNode = args.eat()?.unwrap_or_default(); @@ -18,7 +18,7 @@ pub struct BlockNode; #[node] impl BlockNode { - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { Ok(Content::Block(args.eat()?.unwrap_or_default())) } } diff --git a/src/library/layout/grid.rs b/src/library/layout/grid.rs index 8ecac636f..5b6217327 100644 --- a/src/library/layout/grid.rs +++ b/src/library/layout/grid.rs @@ -13,7 +13,7 @@ pub struct GridNode { #[node] impl GridNode { - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { let columns = args.named("columns")?.unwrap_or_default(); let rows = args.named("rows")?.unwrap_or_default(); let base_gutter: Vec = args.named("gutter")?.unwrap_or_default(); diff --git a/src/library/layout/pad.rs b/src/library/layout/pad.rs index aff0e8b0b..97b760e18 100644 --- a/src/library/layout/pad.rs +++ b/src/library/layout/pad.rs @@ -11,7 +11,7 @@ pub struct PadNode { #[node] impl PadNode { - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { let all = args.named("rest")?.or(args.find()?); let x = args.named("x")?; let y = args.named("y")?; diff --git a/src/library/layout/page.rs b/src/library/layout/page.rs index 8db1329f2..7d91aa6d0 100644 --- a/src/library/layout/page.rs +++ b/src/library/layout/page.rs @@ -35,7 +35,7 @@ impl PageNode { #[property(referenced)] pub const FOOTER: Marginal = Marginal::None; - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { Ok(Content::Page(Self(args.expect("body")?))) } @@ -109,7 +109,7 @@ impl PageNode { let w = size.x - padding.left - padding.right; let area = Size::new(w, h); let pod = Regions::one(area, area, area.map(Length::is_finite)); - let sub = Layout::layout(&content, ctx, &pod, styles)?.remove(0); + let sub = content.layout(ctx, &pod, styles)?.remove(0); Arc::make_mut(frame).push_frame(pos, sub); } } @@ -134,7 +134,7 @@ pub struct PagebreakNode; #[node] impl PagebreakNode { - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { let weak = args.named("weak")?.unwrap_or(false); Ok(Content::Pagebreak { weak }) } @@ -158,8 +158,8 @@ impl Marginal { Self::None => None, Self::Content(content) => Some(content.clone()), Self::Func(func, span) => { - let args = Args::from_values(*span, [Value::Int(page as i64)]); - Some(func.call(ctx, args)?.display()) + let args = Args::new(*span, [Value::Int(page as i64)]); + Some(func.call_detached(ctx, args)?.display()) } }) } diff --git a/src/library/layout/place.rs b/src/library/layout/place.rs index e74776db4..408ca1290 100644 --- a/src/library/layout/place.rs +++ b/src/library/layout/place.rs @@ -7,7 +7,7 @@ pub struct PlaceNode(pub LayoutNode); #[node] impl PlaceNode { - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { let aligns = args.find()?.unwrap_or(Spec::with_x(Some(RawAlign::Start))); let dx = args.named("dx")?.unwrap_or_default(); let dy = args.named("dy")?.unwrap_or_default(); diff --git a/src/library/layout/spacing.rs b/src/library/layout/spacing.rs index 8a96e3785..da4a96b60 100644 --- a/src/library/layout/spacing.rs +++ b/src/library/layout/spacing.rs @@ -8,7 +8,7 @@ pub struct HNode; #[node] impl HNode { - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { let amount = args.expect("spacing")?; let weak = args.named("weak")?.unwrap_or(false); Ok(Content::Horizontal { amount, weak }) @@ -20,7 +20,7 @@ pub struct VNode; #[node] impl VNode { - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { let amount = args.expect("spacing")?; let weak = args.named("weak")?.unwrap_or(false); Ok(Content::Vertical { amount, weak, generated: false }) diff --git a/src/library/layout/stack.rs b/src/library/layout/stack.rs index bbfeeab04..828ff8e3e 100644 --- a/src/library/layout/stack.rs +++ b/src/library/layout/stack.rs @@ -15,7 +15,7 @@ pub struct StackNode { #[node] impl StackNode { - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { Ok(Content::block(Self { dir: args.named("dir")?.unwrap_or(Dir::TTB), spacing: args.named("spacing")?, diff --git a/src/library/math/mod.rs b/src/library/math/mod.rs index b1dabbe5e..6ed759b7b 100644 --- a/src/library/math/mod.rs +++ b/src/library/math/mod.rs @@ -28,7 +28,7 @@ impl MathNode { #[property(resolve, shorthand(around))] pub const BELOW: Option = Some(Ratio::one().into()); - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { Ok(Content::show(Self { formula: args.expect("formula")?, display: args.named("display")?.unwrap_or(false), diff --git a/src/library/prelude.rs b/src/library/prelude.rs index 99bff51a9..371d67761 100644 --- a/src/library/prelude.rs +++ b/src/library/prelude.rs @@ -9,8 +9,8 @@ pub use typst_macros::node; pub use crate::diag::{with_alternative, At, Error, StrResult, TypError, TypResult}; pub use crate::eval::{ - Arg, Args, Array, Cast, Dict, Func, Node, RawAlign, RawLength, RawStroke, Scope, - Smart, Value, + Arg, Args, Array, Cast, Dict, Func, Machine, Node, RawAlign, RawLength, RawStroke, + Scope, Smart, Value, }; pub use crate::frame::*; pub use crate::geom::*; diff --git a/src/library/structure/heading.rs b/src/library/structure/heading.rs index 1cfcb6d01..a0973b90a 100644 --- a/src/library/structure/heading.rs +++ b/src/library/structure/heading.rs @@ -55,7 +55,7 @@ impl HeadingNode { pub const BELOW: Leveled> = Leveled::Value(Some(Ratio::new(0.55).into())); - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { Ok(Content::show(Self { body: args.expect("body")?, level: args.named("level")?.unwrap_or(NonZeroUsize::new(1).unwrap()), @@ -142,8 +142,8 @@ impl Leveled { Self::Value(value) => value.clone(), Self::Mapping(mapping) => mapping(level), Self::Func(func, span) => { - let args = Args::from_values(*span, [Value::Int(level.get() as i64)]); - func.call(ctx, args)?.cast().at(*span)? + let args = Args::new(*span, [Value::Int(level.get() as i64)]); + func.call_detached(ctx, args)?.cast().at(*span)? } }) } diff --git a/src/library/structure/list.rs b/src/library/structure/list.rs index 7686a3f4a..84603eb3b 100644 --- a/src/library/structure/list.rs +++ b/src/library/structure/list.rs @@ -56,7 +56,7 @@ impl ListNode { #[property(resolve)] pub const SPACING: BlockSpacing = Ratio::one().into(); - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { Ok(Content::show(Self { start: args.named("start")?.unwrap_or(1), tight: args.named("tight")?.unwrap_or(true), @@ -216,8 +216,8 @@ impl Label { } Self::Content(content) => content.clone(), Self::Func(func, span) => { - let args = Args::from_values(*span, [Value::Int(number as i64)]); - func.call(ctx, args)?.display() + let args = Args::new(*span, [Value::Int(number as i64)]); + func.call_detached(ctx, args)?.display() } }) } diff --git a/src/library/structure/table.rs b/src/library/structure/table.rs index f39ea9784..cd70db306 100644 --- a/src/library/structure/table.rs +++ b/src/library/structure/table.rs @@ -30,7 +30,7 @@ impl TableNode { #[property(resolve, shorthand(around))] pub const BELOW: Option = Some(Ratio::one().into()); - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { let columns = args.named("columns")?.unwrap_or_default(); let rows = args.named("rows")?.unwrap_or_default(); let base_gutter: Vec = args.named("gutter")?.unwrap_or_default(); @@ -128,11 +128,8 @@ impl Celled { Ok(match self { Self::Value(value) => value.clone(), Self::Func(func, span) => { - let args = Args::from_values(*span, [ - Value::Int(x as i64), - Value::Int(y as i64), - ]); - func.call(ctx, args)?.cast().at(*span)? + let args = Args::new(*span, [Value::Int(x as i64), Value::Int(y as i64)]); + func.call_detached(ctx, args)?.cast().at(*span)? } }) } diff --git a/src/library/text/deco.rs b/src/library/text/deco.rs index dedaa6e80..cec4ca9ef 100644 --- a/src/library/text/deco.rs +++ b/src/library/text/deco.rs @@ -35,7 +35,7 @@ impl DecoNode { /// with the glyphs. Does not apply to strikethrough. pub const EVADE: bool = true; - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { Ok(Content::show(Self(args.expect("body")?))) } } diff --git a/src/library/text/link.rs b/src/library/text/link.rs index 284f0b1f9..728b594f5 100644 --- a/src/library/text/link.rs +++ b/src/library/text/link.rs @@ -19,7 +19,7 @@ impl LinkNode { /// Whether to underline link. pub const UNDERLINE: bool = true; - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { Ok(Content::show(Self { url: args.expect::("url")?, body: args.eat()?, diff --git a/src/library/text/mod.rs b/src/library/text/mod.rs index 1b83b0f4f..bbe397ca9 100644 --- a/src/library/text/mod.rs +++ b/src/library/text/mod.rs @@ -127,7 +127,7 @@ impl TextNode { #[property(skip, fold)] pub const DECO: Decoration = vec![]; - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { // The text constructor is special: It doesn't create a text node. // Instead, it leaves the passed argument structurally unchanged, but // styles all text in it. @@ -443,12 +443,12 @@ impl Fold for Vec<(Tag, u32)> { } /// Convert text to lowercase. -pub fn lower(_: &mut Context, args: &mut Args) -> TypResult { +pub fn lower(_: &mut Machine, args: &mut Args) -> TypResult { case(Case::Lower, args) } /// Convert text to uppercase. -pub fn upper(_: &mut Context, args: &mut Args) -> TypResult { +pub fn upper(_: &mut Machine, args: &mut Args) -> TypResult { case(Case::Upper, args) } @@ -482,7 +482,7 @@ impl Case { } /// Display text in small capitals. -pub fn smallcaps(_: &mut Context, args: &mut Args) -> TypResult { +pub fn smallcaps(_: &mut Machine, args: &mut Args) -> TypResult { let body: Content = args.expect("content")?; Ok(Value::Content(body.styled(TextNode::SMALLCAPS, true))) } @@ -514,7 +514,7 @@ pub struct StrongNode(pub Content); #[node(showable)] impl StrongNode { - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { Ok(Content::show(Self(args.expect("body")?))) } } @@ -539,7 +539,7 @@ pub struct EmphNode(pub Content); #[node(showable)] impl EmphNode { - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { Ok(Content::show(Self(args.expect("body")?))) } } diff --git a/src/library/text/par.rs b/src/library/text/par.rs index 6c274e7ea..1269ffed5 100644 --- a/src/library/text/par.rs +++ b/src/library/text/par.rs @@ -51,7 +51,7 @@ impl ParNode { #[property(resolve)] pub const LINEBREAKS: Smart = Smart::Auto; - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { // The paragraph constructor is special: It doesn't create a paragraph // node. Instead, it just ensures that the passed content lives is in a // separate paragraph and styles it. @@ -172,7 +172,7 @@ pub struct ParbreakNode; #[node] impl ParbreakNode { - fn construct(_: &mut Context, _: &mut Args) -> TypResult { + fn construct(_: &mut Machine, _: &mut Args) -> TypResult { Ok(Content::Parbreak) } } @@ -182,7 +182,7 @@ pub struct LinebreakNode; #[node] impl LinebreakNode { - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { let justified = args.named("justified")?.unwrap_or(false); Ok(Content::Linebreak { justified }) } diff --git a/src/library/text/raw.rs b/src/library/text/raw.rs index f44877cac..fe1f9a991 100644 --- a/src/library/text/raw.rs +++ b/src/library/text/raw.rs @@ -35,7 +35,7 @@ impl RawNode { #[property(resolve, shorthand(around))] pub const BELOW: Option = Some(Ratio::one().into()); - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { Ok(Content::show(Self { text: args.expect("text")?, block: args.named("block")?.unwrap_or(false), diff --git a/src/library/text/repeat.rs b/src/library/text/repeat.rs index 68036be7e..9ee8286b6 100644 --- a/src/library/text/repeat.rs +++ b/src/library/text/repeat.rs @@ -6,7 +6,7 @@ pub struct RepeatNode(pub LayoutNode); #[node] impl RepeatNode { - fn construct(_: &mut Context, args: &mut Args) -> TypResult { + fn construct(_: &mut Machine, args: &mut Args) -> TypResult { Ok(Content::inline(Self(args.expect("body")?))) } } diff --git a/src/library/utility/color.rs b/src/library/utility/color.rs index 75410380f..5857c4c7f 100644 --- a/src/library/utility/color.rs +++ b/src/library/utility/color.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use crate::library::prelude::*; /// Create an RGB(A) color. -pub fn rgb(_: &mut Context, args: &mut Args) -> TypResult { +pub fn rgb(_: &mut Machine, args: &mut Args) -> TypResult { Ok(Value::from( if let Some(string) = args.find::>()? { match RgbaColor::from_str(&string.v) { @@ -37,7 +37,7 @@ pub fn rgb(_: &mut Context, args: &mut Args) -> TypResult { } /// Create a CMYK color. -pub fn cmyk(_: &mut Context, args: &mut Args) -> TypResult { +pub fn cmyk(_: &mut Machine, args: &mut Args) -> TypResult { struct Component(u8); castable! { diff --git a/src/library/utility/math.rs b/src/library/utility/math.rs index 63ec5e555..05c706ca5 100644 --- a/src/library/utility/math.rs +++ b/src/library/utility/math.rs @@ -3,7 +3,7 @@ use std::cmp::Ordering; use crate::library::prelude::*; /// Convert a value to a integer. -pub fn int(_: &mut Context, args: &mut Args) -> TypResult { +pub fn int(_: &mut Machine, args: &mut Args) -> TypResult { let Spanned { v, span } = args.expect("value")?; Ok(Value::Int(match v { Value::Bool(v) => v as i64, @@ -18,7 +18,7 @@ pub fn int(_: &mut Context, args: &mut Args) -> TypResult { } /// Convert a value to a float. -pub fn float(_: &mut Context, args: &mut Args) -> TypResult { +pub fn float(_: &mut Machine, args: &mut Args) -> TypResult { let Spanned { v, span } = args.expect("value")?; Ok(Value::Float(match v { Value::Int(v) => v as f64, @@ -32,7 +32,7 @@ pub fn float(_: &mut Context, args: &mut Args) -> TypResult { } /// The absolute value of a numeric value. -pub fn abs(_: &mut Context, args: &mut Args) -> TypResult { +pub fn abs(_: &mut Machine, args: &mut Args) -> TypResult { let Spanned { v, span } = args.expect("numeric value")?; Ok(match v { Value::Int(v) => Value::Int(v.abs()), @@ -48,12 +48,12 @@ pub fn abs(_: &mut Context, args: &mut Args) -> TypResult { } /// The minimum of a sequence of values. -pub fn min(_: &mut Context, args: &mut Args) -> TypResult { +pub fn min(_: &mut Machine, args: &mut Args) -> TypResult { minmax(args, Ordering::Less) } /// The maximum of a sequence of values. -pub fn max(_: &mut Context, args: &mut Args) -> TypResult { +pub fn max(_: &mut Machine, args: &mut Args) -> TypResult { minmax(args, Ordering::Greater) } @@ -79,17 +79,17 @@ fn minmax(args: &mut Args, goal: Ordering) -> TypResult { } /// Whether an integer is even. -pub fn even(_: &mut Context, args: &mut Args) -> TypResult { +pub fn even(_: &mut Machine, args: &mut Args) -> TypResult { Ok(Value::Bool(args.expect::("integer")? % 2 == 0)) } /// Whether an integer is odd. -pub fn odd(_: &mut Context, args: &mut Args) -> TypResult { +pub fn odd(_: &mut Machine, args: &mut Args) -> TypResult { Ok(Value::Bool(args.expect::("integer")? % 2 != 0)) } /// The modulo of two numbers. -pub fn mod_(_: &mut Context, args: &mut Args) -> TypResult { +pub fn mod_(_: &mut Machine, args: &mut Args) -> TypResult { let Spanned { v: v1, span: span1 } = args.expect("integer or float")?; let Spanned { v: v2, span: span2 } = args.expect("integer or float")?; @@ -119,7 +119,7 @@ pub fn mod_(_: &mut Context, args: &mut Args) -> TypResult { } /// Create a sequence of numbers. -pub fn range(_: &mut Context, args: &mut Args) -> TypResult { +pub fn range(_: &mut Machine, args: &mut Args) -> TypResult { let first = args.expect::("end")?; let (start, end) = match args.eat::()? { Some(second) => (first, second), diff --git a/src/library/utility/mod.rs b/src/library/utility/mod.rs index 6f0f9a4c6..051f81958 100644 --- a/src/library/utility/mod.rs +++ b/src/library/utility/mod.rs @@ -8,19 +8,17 @@ pub use color::*; pub use math::*; pub use string::*; -use std::mem; - use crate::eval::{Eval, Machine, Scopes}; use crate::library::prelude::*; use crate::source::SourceFile; /// The name of a value's type. -pub fn type_(_: &mut Context, args: &mut Args) -> TypResult { +pub fn type_(_: &mut Machine, args: &mut Args) -> TypResult { Ok(args.expect::("value")?.type_name().into()) } /// Ensure that a condition is fulfilled. -pub fn assert(_: &mut Context, args: &mut Args) -> TypResult { +pub fn assert(_: &mut Machine, args: &mut Args) -> TypResult { let Spanned { v, span } = args.expect::>("condition")?; if !v { bail!(span, "assertion failed"); @@ -29,28 +27,21 @@ pub fn assert(_: &mut Context, args: &mut Args) -> TypResult { } /// Evaluate a string as Typst markup. -pub fn eval(ctx: &mut Context, args: &mut Args) -> TypResult { +pub fn eval(vm: &mut Machine, args: &mut Args) -> TypResult { let Spanned { v: src, span } = args.expect::>("source")?; // Parse the source and set a synthetic span for all nodes. let source = SourceFile::synthesized(src, span); let ast = source.ast()?; - // Save the old route, then detach it. - let prev_route = mem::take(&mut ctx.route); - // Evaluate the source. - let std = ctx.config.std.clone(); + let std = vm.ctx.config.std.clone(); let scopes = Scopes::new(Some(&std)); - let mut vm = Machine::new(ctx, scopes); - let result = ast.eval(&mut vm); - let flow = vm.flow; - - // Restore the old route. - ctx.route = prev_route; + let mut sub = Machine::new(vm.ctx, vec![], scopes); + let result = ast.eval(&mut sub); // Handle control flow. - if let Some(flow) = flow { + if let Some(flow) = sub.flow { return Err(flow.forbidden()); } diff --git a/src/library/utility/string.rs b/src/library/utility/string.rs index 13a6bbd8b..2f80a5cba 100644 --- a/src/library/utility/string.rs +++ b/src/library/utility/string.rs @@ -4,12 +4,12 @@ use crate::eval::Regex; use crate::library::prelude::*; /// The string representation of a value. -pub fn repr(_: &mut Context, args: &mut Args) -> TypResult { +pub fn repr(_: &mut Machine, args: &mut Args) -> TypResult { Ok(args.expect::("value")?.repr().into()) } /// Cconvert a value to a string. -pub fn str(_: &mut Context, args: &mut Args) -> TypResult { +pub fn str(_: &mut Machine, args: &mut Args) -> TypResult { let Spanned { v, span } = args.expect("value")?; Ok(Value::Str(match v { Value::Int(v) => format_eco!("{}", v), @@ -20,29 +20,29 @@ pub fn str(_: &mut Context, args: &mut Args) -> TypResult { } /// Create blind text. -pub fn lorem(_: &mut Context, args: &mut Args) -> TypResult { +pub fn lorem(_: &mut Machine, args: &mut Args) -> TypResult { let words: usize = args.expect("number of words")?; Ok(Value::Str(lipsum_from_seed(words, 97).into())) } /// Create a regular expression. -pub fn regex(_: &mut Context, args: &mut Args) -> TypResult { +pub fn regex(_: &mut Machine, args: &mut Args) -> TypResult { let Spanned { v, span } = args.expect::>("regular expression")?; Ok(Regex::new(&v).at(span)?.into()) } /// Converts an integer into one or multiple letters. -pub fn letter(_: &mut Context, args: &mut Args) -> TypResult { +pub fn letter(_: &mut Machine, args: &mut Args) -> TypResult { convert(Numbering::Letter, args) } /// Converts an integer into a roman numeral. -pub fn roman(_: &mut Context, args: &mut Args) -> TypResult { +pub fn roman(_: &mut Machine, args: &mut Args) -> TypResult { convert(Numbering::Roman, args) } /// Convert a number into a symbol. -pub fn symbol(_: &mut Context, args: &mut Args) -> TypResult { +pub fn symbol(_: &mut Machine, args: &mut Args) -> TypResult { convert(Numbering::Symbol, args) } diff --git a/src/main.rs b/src/main.rs index 2865c67ee..821f10083 100644 --- a/src/main.rs +++ b/src/main.rs @@ -214,7 +214,7 @@ fn typeset(command: TypesetCommand) -> StrResult<()> { .map_err(|_| "failed to load source file")?; // Typeset. - match ctx.typeset(id) { + match typst::typeset(&mut ctx, id) { // Export the PDF. Ok(frames) => { let buffer = export::pdf(&ctx, &frames); diff --git a/src/model/content.rs b/src/model/content.rs index 645797479..c09979d52 100644 --- a/src/model/content.rs +++ b/src/model/content.rs @@ -19,6 +19,19 @@ use crate::library::text::{ }; use crate::util::EcoString; +/// Layout content into a collection of pages. +pub fn layout(ctx: &mut Context, content: &Content) -> TypResult>> { + let copy = ctx.config.styles.clone(); + let styles = StyleChain::with_root(©); + let scratch = Scratch::default(); + + let mut builder = Builder::new(ctx, &scratch, true); + builder.accept(content, styles)?; + + let (doc, shared) = builder.into_doc(styles)?; + doc.layout(ctx, shared) +} + /// Composable representation of styled content. /// /// This results from: @@ -207,19 +220,6 @@ impl Content { Self::sequence(seq) } - - /// Layout this content into a collection of pages. - pub fn layout(&self, ctx: &mut Context) -> TypResult>> { - let copy = ctx.config.styles.clone(); - let styles = StyleChain::with_root(©); - let scratch = Scratch::default(); - - let mut builder = Builder::new(ctx, &scratch, true); - builder.accept(self, styles)?; - - let (doc, shared) = builder.into_doc(styles)?; - doc.layout(ctx, shared) - } } impl Layout for Content { diff --git a/src/model/mod.rs b/src/model/mod.rs index a9d1344a0..5c8b82c0b 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -1,4 +1,4 @@ -//! Structured representation of styled content. +//! Styled and structured representation of layoutable content. #[macro_use] mod styles; diff --git a/src/model/recipe.rs b/src/model/recipe.rs index 3404a3849..e4417adfe 100644 --- a/src/model/recipe.rs +++ b/src/model/recipe.rs @@ -82,12 +82,12 @@ impl Recipe { F: FnOnce() -> Value, { let args = if self.func.argc() == Some(0) { - Args::new(self.span) + Args::new(self.span, []) } else { - Args::from_values(self.span, [arg()]) + Args::new(self.span, [arg()]) }; - Ok(self.func.call(ctx, args)?.display()) + Ok(self.func.call_detached(ctx, args)?.display()) } /// What kind of structure the property interrupts. diff --git a/tests/typeset.rs b/tests/typeset.rs index caa30d7ed..b334ae9a0 100644 --- a/tests/typeset.rs +++ b/tests/typeset.rs @@ -290,7 +290,7 @@ fn test_part( ok &= test_reparse(ctx.sources.get(id).src(), i, rng); - let (mut frames, mut errors) = match ctx.typeset(id) { + let (mut frames, mut errors) = match typst::typeset(ctx, id) { Ok(frames) => (frames, vec![]), Err(errors) => (vec![], *errors), };