Move route from context to VM

This commit is contained in:
Laurenz 2022-05-25 13:50:33 +02:00
parent 6935cf8dfe
commit c010cbc17d
45 changed files with 266 additions and 280 deletions

View File

@ -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))
}

View File

@ -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<Item = Value>) -> Self {
pub fn new(span: Span, values: impl IntoIterator<Item = Value>) -> Self {
let items = values
.into_iter()
.map(|value| Arg {

View File

@ -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<Func>) -> TypResult<Self> {
pub fn map(&self, vm: &mut Machine, f: Spanned<Func>) -> TypResult<Self> {
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::<TypResult<_>>()?)
}
/// Return a new array with only those elements for which the function
/// return true.
pub fn filter(&self, ctx: &mut Context, f: Spanned<Func>) -> TypResult<Self> {
pub fn filter(&self, vm: &mut Machine, f: Spanned<Func>) -> TypResult<Self> {
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::<bool>()
.at(f.span)?
{

View File

@ -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<Func>) -> TypResult<Array> {
pub fn map(&self, vm: &mut Machine, f: Spanned<Func>) -> TypResult<Array> {
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::<TypResult<_>>()?)
}

View File

@ -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<Value>,
func: fn(&mut Machine, &mut Args) -> TypResult<Value>,
) -> 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<Value> {
pub fn call(&self, vm: &mut Machine, mut args: Args) -> TypResult<Value> {
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<Value> {
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<StyleMap> {
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<Value>,
pub func: fn(&mut Machine, &mut Args) -> TypResult<Value>,
/// The set rule.
pub set: Option<fn(&mut Args) -> TypResult<StyleMap>>,
/// 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<Content>;
fn construct(vm: &mut Machine, args: &mut Args) -> TypResult<Content>;
/// 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<Value> {
pub fn call(&self, vm: &mut Machine, args: &mut Args) -> TypResult<Value> {
// Don't leak the scopes from the call site. Instead, we use the
// scope of captured variables we collected earlier.
let 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())?,

View File

@ -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<SourceId>,
/// 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<SourceId>, 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<PathBuf> {
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());
}
}

View File

@ -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()?,
},

View File

@ -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<SourceId>,
) -> TypResult<Module> {
// 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<Self::Output>;
// 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<Self::Output>;
}
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<Self::Output> {
let span = self.path().span();
let path = self.path().eval(vm)?.cast::<EcoString>().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<Self::Output> {
let span = self.path().span();
let path = self.path().eval(vm)?.cast::<EcoString>().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<Module> {
fn import(vm: &mut Machine, path: &str, span: Span) -> TypResult<Module> {
// 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<Module> {
})?;
// 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)
}

View File

@ -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<RwLock<Value>>;
@ -89,7 +88,7 @@ impl Scope {
pub fn def_fn(
&mut self,
name: &'static str,
func: fn(&mut Context, &mut Args) -> TypResult<Value>,
func: fn(&mut Machine, &mut Args) -> TypResult<Value>,
) {
self.def_const(name, Func::from_fn(name, func));
}

View File

@ -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<()> {

View File

@ -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<Vec<Arc<Frame>>> {
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<SourceId, Module>,
/// The stack of imported files that led to evaluation of the current file.
route: Vec<SourceId>,
/// 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<Module> {
// 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<Vec<Arc<Frame>>> {
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<PathBuf> {
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.

View File

@ -6,7 +6,7 @@ pub struct HideNode(pub LayoutNode);
#[node]
impl HideNode {
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
Ok(Content::inline(Self(args.expect("body")?)))
}
}

View File

@ -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<Content> {
fn construct(vm: &mut Machine, args: &mut Args) -> TypResult<Content> {
let Spanned { v: path, span } =
args.expect::<Spanned<EcoString>>("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())
}

View File

@ -15,7 +15,7 @@ impl LineNode {
#[property(resolve, fold)]
pub const STROKE: RawStroke = RawStroke::default();
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
let origin = args.named("origin")?.unwrap_or_default();
let delta = match args.named::<Spec<Relative<RawLength>>>("to")? {

View File

@ -37,7 +37,7 @@ impl<const S: ShapeKind> ShapeNode<S> {
#[property(skip, resolve, fold)]
pub const RADIUS: Sides<Option<Relative<RawLength>>> = Sides::splat(Relative::zero());
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
let size = match S {
SQUARE => args.named::<RawLength>("size")?.map(Relative::from),
CIRCLE => args.named::<RawLength>("radius")?.map(|r| 2.0 * Relative::from(r)),

View File

@ -12,7 +12,7 @@ pub struct MoveNode {
#[node]
impl MoveNode {
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
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<const T: TransformKind> TransformNode<T> {
#[property(resolve)]
pub const ORIGIN: Spec<Option<RawAlign>> = Spec::default();
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
let transform = match T {
ROTATE => {
let angle = args.named_or_find("angle")?.unwrap_or_default();

View File

@ -12,7 +12,7 @@ pub struct AlignNode {
#[node]
impl AlignNode {
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
let aligns: Spec<Option<RawAlign>> = args.find()?.unwrap_or_default();
let body: Content = args.expect("body")?;
Ok(match (body, aligns) {

View File

@ -17,7 +17,7 @@ impl ColumnsNode {
#[property(resolve)]
pub const GUTTER: Relative<RawLength> = Ratio::new(0.04).into();
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
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<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
let weak = args.named("weak")?.unwrap_or(false);
Ok(Content::Colbreak { weak })
}

View File

@ -5,7 +5,7 @@ pub struct BoxNode;
#[node]
impl BoxNode {
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
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<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
Ok(Content::Block(args.eat()?.unwrap_or_default()))
}
}

View File

@ -13,7 +13,7 @@ pub struct GridNode {
#[node]
impl GridNode {
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
let columns = args.named("columns")?.unwrap_or_default();
let rows = args.named("rows")?.unwrap_or_default();
let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default();

View File

@ -11,7 +11,7 @@ pub struct PadNode {
#[node]
impl PadNode {
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
let all = args.named("rest")?.or(args.find()?);
let x = args.named("x")?;
let y = args.named("y")?;

View File

@ -35,7 +35,7 @@ impl PageNode {
#[property(referenced)]
pub const FOOTER: Marginal = Marginal::None;
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
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<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
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())
}
})
}

View File

@ -7,7 +7,7 @@ pub struct PlaceNode(pub LayoutNode);
#[node]
impl PlaceNode {
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
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();

View File

@ -8,7 +8,7 @@ pub struct HNode;
#[node]
impl HNode {
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
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<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
let amount = args.expect("spacing")?;
let weak = args.named("weak")?.unwrap_or(false);
Ok(Content::Vertical { amount, weak, generated: false })

View File

@ -15,7 +15,7 @@ pub struct StackNode {
#[node]
impl StackNode {
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
Ok(Content::block(Self {
dir: args.named("dir")?.unwrap_or(Dir::TTB),
spacing: args.named("spacing")?,

View File

@ -28,7 +28,7 @@ impl MathNode {
#[property(resolve, shorthand(around))]
pub const BELOW: Option<BlockSpacing> = Some(Ratio::one().into());
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
Ok(Content::show(Self {
formula: args.expect("formula")?,
display: args.named("display")?.unwrap_or(false),

View File

@ -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::*;

View File

@ -55,7 +55,7 @@ impl HeadingNode {
pub const BELOW: Leveled<Option<BlockSpacing>> =
Leveled::Value(Some(Ratio::new(0.55).into()));
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
Ok(Content::show(Self {
body: args.expect("body")?,
level: args.named("level")?.unwrap_or(NonZeroUsize::new(1).unwrap()),
@ -142,8 +142,8 @@ impl<T: Cast + Clone> Leveled<T> {
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)?
}
})
}

View File

@ -56,7 +56,7 @@ impl<const L: ListKind> ListNode<L> {
#[property(resolve)]
pub const SPACING: BlockSpacing = Ratio::one().into();
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
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()
}
})
}

View File

@ -30,7 +30,7 @@ impl TableNode {
#[property(resolve, shorthand(around))]
pub const BELOW: Option<BlockSpacing> = Some(Ratio::one().into());
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
let columns = args.named("columns")?.unwrap_or_default();
let rows = args.named("rows")?.unwrap_or_default();
let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default();
@ -128,11 +128,8 @@ impl<T: Cast + Clone> Celled<T> {
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)?
}
})
}

View File

@ -35,7 +35,7 @@ impl<const L: DecoLine> DecoNode<L> {
/// with the glyphs. Does not apply to strikethrough.
pub const EVADE: bool = true;
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
Ok(Content::show(Self(args.expect("body")?)))
}
}

View File

@ -19,7 +19,7 @@ impl LinkNode {
/// Whether to underline link.
pub const UNDERLINE: bool = true;
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
Ok(Content::show(Self {
url: args.expect::<EcoString>("url")?,
body: args.eat()?,

View File

@ -127,7 +127,7 @@ impl TextNode {
#[property(skip, fold)]
pub const DECO: Decoration = vec![];
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
// 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<Value> {
pub fn lower(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
case(Case::Lower, args)
}
/// Convert text to uppercase.
pub fn upper(_: &mut Context, args: &mut Args) -> TypResult<Value> {
pub fn upper(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
case(Case::Upper, args)
}
@ -482,7 +482,7 @@ impl Case {
}
/// Display text in small capitals.
pub fn smallcaps(_: &mut Context, args: &mut Args) -> TypResult<Value> {
pub fn smallcaps(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
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<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
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<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
Ok(Content::show(Self(args.expect("body")?)))
}
}

View File

@ -51,7 +51,7 @@ impl ParNode {
#[property(resolve)]
pub const LINEBREAKS: Smart<Linebreaks> = Smart::Auto;
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
// 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<Content> {
fn construct(_: &mut Machine, _: &mut Args) -> TypResult<Content> {
Ok(Content::Parbreak)
}
}
@ -182,7 +182,7 @@ pub struct LinebreakNode;
#[node]
impl LinebreakNode {
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
let justified = args.named("justified")?.unwrap_or(false);
Ok(Content::Linebreak { justified })
}

View File

@ -35,7 +35,7 @@ impl RawNode {
#[property(resolve, shorthand(around))]
pub const BELOW: Option<BlockSpacing> = Some(Ratio::one().into());
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
Ok(Content::show(Self {
text: args.expect("text")?,
block: args.named("block")?.unwrap_or(false),

View File

@ -6,7 +6,7 @@ pub struct RepeatNode(pub LayoutNode);
#[node]
impl RepeatNode {
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
Ok(Content::inline(Self(args.expect("body")?)))
}
}

View File

@ -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<Value> {
pub fn rgb(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
Ok(Value::from(
if let Some(string) = args.find::<Spanned<EcoString>>()? {
match RgbaColor::from_str(&string.v) {
@ -37,7 +37,7 @@ pub fn rgb(_: &mut Context, args: &mut Args) -> TypResult<Value> {
}
/// Create a CMYK color.
pub fn cmyk(_: &mut Context, args: &mut Args) -> TypResult<Value> {
pub fn cmyk(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
struct Component(u8);
castable! {

View File

@ -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<Value> {
pub fn int(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
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<Value> {
}
/// Convert a value to a float.
pub fn float(_: &mut Context, args: &mut Args) -> TypResult<Value> {
pub fn float(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
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<Value> {
}
/// The absolute value of a numeric value.
pub fn abs(_: &mut Context, args: &mut Args) -> TypResult<Value> {
pub fn abs(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
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<Value> {
}
/// The minimum of a sequence of values.
pub fn min(_: &mut Context, args: &mut Args) -> TypResult<Value> {
pub fn min(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
minmax(args, Ordering::Less)
}
/// The maximum of a sequence of values.
pub fn max(_: &mut Context, args: &mut Args) -> TypResult<Value> {
pub fn max(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
minmax(args, Ordering::Greater)
}
@ -79,17 +79,17 @@ fn minmax(args: &mut Args, goal: Ordering) -> TypResult<Value> {
}
/// Whether an integer is even.
pub fn even(_: &mut Context, args: &mut Args) -> TypResult<Value> {
pub fn even(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
Ok(Value::Bool(args.expect::<i64>("integer")? % 2 == 0))
}
/// Whether an integer is odd.
pub fn odd(_: &mut Context, args: &mut Args) -> TypResult<Value> {
pub fn odd(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
Ok(Value::Bool(args.expect::<i64>("integer")? % 2 != 0))
}
/// The modulo of two numbers.
pub fn mod_(_: &mut Context, args: &mut Args) -> TypResult<Value> {
pub fn mod_(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
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<Value> {
}
/// Create a sequence of numbers.
pub fn range(_: &mut Context, args: &mut Args) -> TypResult<Value> {
pub fn range(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
let first = args.expect::<i64>("end")?;
let (start, end) = match args.eat::<i64>()? {
Some(second) => (first, second),

View File

@ -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<Value> {
pub fn type_(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
Ok(args.expect::<Value>("value")?.type_name().into())
}
/// Ensure that a condition is fulfilled.
pub fn assert(_: &mut Context, args: &mut Args) -> TypResult<Value> {
pub fn assert(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
let Spanned { v, span } = args.expect::<Spanned<bool>>("condition")?;
if !v {
bail!(span, "assertion failed");
@ -29,28 +27,21 @@ pub fn assert(_: &mut Context, args: &mut Args) -> TypResult<Value> {
}
/// Evaluate a string as Typst markup.
pub fn eval(ctx: &mut Context, args: &mut Args) -> TypResult<Value> {
pub fn eval(vm: &mut Machine, args: &mut Args) -> TypResult<Value> {
let Spanned { v: src, span } = args.expect::<Spanned<String>>("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());
}

View File

@ -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<Value> {
pub fn repr(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
Ok(args.expect::<Value>("value")?.repr().into())
}
/// Cconvert a value to a string.
pub fn str(_: &mut Context, args: &mut Args) -> TypResult<Value> {
pub fn str(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
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<Value> {
}
/// Create blind text.
pub fn lorem(_: &mut Context, args: &mut Args) -> TypResult<Value> {
pub fn lorem(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
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<Value> {
pub fn regex(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
let Spanned { v, span } = args.expect::<Spanned<EcoString>>("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<Value> {
pub fn letter(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
convert(Numbering::Letter, args)
}
/// Converts an integer into a roman numeral.
pub fn roman(_: &mut Context, args: &mut Args) -> TypResult<Value> {
pub fn roman(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
convert(Numbering::Roman, args)
}
/// Convert a number into a symbol.
pub fn symbol(_: &mut Context, args: &mut Args) -> TypResult<Value> {
pub fn symbol(_: &mut Machine, args: &mut Args) -> TypResult<Value> {
convert(Numbering::Symbol, args)
}

View File

@ -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);

View File

@ -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<Vec<Arc<Frame>>> {
let copy = ctx.config.styles.clone();
let styles = StyleChain::with_root(&copy);
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<Vec<Arc<Frame>>> {
let copy = ctx.config.styles.clone();
let styles = StyleChain::with_root(&copy);
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 {

View File

@ -1,4 +1,4 @@
//! Structured representation of styled content.
//! Styled and structured representation of layoutable content.
#[macro_use]
mod styles;

View File

@ -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.

View File

@ -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),
};