summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--benches/oneshot.rs16
-rw-r--r--src/eval/args.rs7
-rw-r--r--src/eval/array.rs11
-rw-r--r--src/eval/dict.rs11
-rw-r--r--src/eval/func.rs46
-rw-r--r--src/eval/machine.rs28
-rw-r--r--src/eval/methods.rs11
-rw-r--r--src/eval/mod.rs96
-rw-r--r--src/eval/scope.rs5
-rw-r--r--src/export/render.rs14
-rw-r--r--src/lib.rs103
-rw-r--r--src/library/graphics/hide.rs2
-rw-r--r--src/library/graphics/image.rs6
-rw-r--r--src/library/graphics/line.rs2
-rw-r--r--src/library/graphics/shape.rs2
-rw-r--r--src/library/graphics/transform.rs4
-rw-r--r--src/library/layout/align.rs2
-rw-r--r--src/library/layout/columns.rs4
-rw-r--r--src/library/layout/container.rs4
-rw-r--r--src/library/layout/grid.rs2
-rw-r--r--src/library/layout/pad.rs2
-rw-r--r--src/library/layout/page.rs10
-rw-r--r--src/library/layout/place.rs2
-rw-r--r--src/library/layout/spacing.rs4
-rw-r--r--src/library/layout/stack.rs2
-rw-r--r--src/library/math/mod.rs2
-rw-r--r--src/library/prelude.rs4
-rw-r--r--src/library/structure/heading.rs6
-rw-r--r--src/library/structure/list.rs6
-rw-r--r--src/library/structure/table.rs9
-rw-r--r--src/library/text/deco.rs2
-rw-r--r--src/library/text/link.rs2
-rw-r--r--src/library/text/mod.rs12
-rw-r--r--src/library/text/par.rs6
-rw-r--r--src/library/text/raw.rs2
-rw-r--r--src/library/text/repeat.rs2
-rw-r--r--src/library/utility/color.rs4
-rw-r--r--src/library/utility/math.rs18
-rw-r--r--src/library/utility/mod.rs23
-rw-r--r--src/library/utility/string.rs14
-rw-r--r--src/main.rs2
-rw-r--r--src/model/content.rs26
-rw-r--r--src/model/mod.rs2
-rw-r--r--src/model/recipe.rs6
-rw-r--r--tests/typeset.rs2
45 files changed, 266 insertions, 280 deletions
diff --git a/benches/oneshot.rs b/benches/oneshot.rs
index 5c0fc701..fef0e6e1 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 9b21cfa2..69e6aaee 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<Item = Value>) -> Self {
+ pub fn new(span: Span, values: impl IntoIterator<Item = Value>) -> Self {
let items = values
.into_iter()
.map(|value| Arg {
diff --git a/src/eval/array.rs b/src/eval/array.rs
index 86347106..840c0aef 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<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)?
{
diff --git a/src/eval/dict.rs b/src/eval/dict.rs
index 22b73e76..35bd75d5 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<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<_>>()?)
}
diff --git a/src/eval/func.rs b/src/eval/func.rs
index 83171ce7..16575c80 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<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())?,
diff --git a/src/eval/machine.rs b/src/eval/machine.rs
index 168cedcb..14633978 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<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());
}
}
diff --git a/src/eval/methods.rs b/src/eval/methods.rs
index 88f173c7..f6de614f 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 2b853586..702a76b2 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<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)
}
diff --git a/src/eval/scope.rs b/src/eval/scope.rs
index 8acaa431..8a0b8165 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<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));
}
diff --git a/src/export/render.rs b/src/export/render.rs
index 34fb4331..9c37791e 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 ab2128c0..81c4afe6 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<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.
diff --git a/src/library/graphics/hide.rs b/src/library/graphics/hide.rs
index 85971c36..28afe320 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<Content> {
+ fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
Ok(Content::inline(Self(args.expect("body")?)))
}
}
diff --git a/src/library/graphics/image.rs b/src/library/graphics/image.rs
index 6fd465cb..d0bcfa44 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<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())
}
diff --git a/src/library/graphics/line.rs b/src/library/graphics/line.rs
index de2e4aa1..8e5ceae1 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<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")? {
diff --git a/src/library/graphics/shape.rs b/src/library/graphics/shape.rs
index bc768628..9da8d8df 100644
--- a/src/library/graphics/shape.rs
+++ b/src/library/graphics/shape.rs
@@ -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)),
diff --git a/src/library/graphics/transform.rs b/src/library/graphics/transform.rs
index a4aa20db..9fcf7ebb 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<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();
diff --git a/src/library/layout/align.rs b/src/library/layout/align.rs
index c050d2a4..c0a7d16c 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<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) {
diff --git a/src/library/layout/columns.rs b/src/library/layout/columns.rs
index 8e523694..4c842261 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<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 })
}
diff --git a/src/library/layout/container.rs b/src/library/layout/container.rs
index 5264f258..df03ac91 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<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()))
}
}
diff --git a/src/library/layout/grid.rs b/src/library/layout/grid.rs
index 8ecac636..5b621732 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<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();
diff --git a/src/library/layout/pad.rs b/src/library/layout/pad.rs
index aff0e8b0..97b760e1 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<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")?;
diff --git a/src/library/layout/page.rs b/src/library/layout/page.rs
index 8db1329f..7d91aa6d 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<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())
}
})
}
diff --git a/src/library/layout/place.rs b/src/library/layout/place.rs
index e74776db..408ca129 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<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();
diff --git a/src/library/layout/spacing.rs b/src/library/layout/spacing.rs
index 8a96e378..da4a96b6 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<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 })
diff --git a/src/library/layout/stack.rs b/src/library/layout/stack.rs
index bbfeeab0..828ff8e3 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<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")?,
diff --git a/src/library/math/mod.rs b/src/library/math/mod.rs
index b1dabbe5..6ed759b7 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<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),
diff --git a/src/library/prelude.rs b/src/library/prelude.rs
index 99bff51a..371d6776 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 1cfcb6d0..a0973b90 100644
--- a/src/library/structure/heading.rs
+++ b/src/library/structure/heading.rs
@@ -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)?
}
})
}
diff --git a/src/library/structure/list.rs b/src/library/structure/list.rs
index 7686a3f4..84603eb3 100644
--- a/src/library/structure/list.rs
+++ b/src/library/structure/list.rs
@@ -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()
}
})
}
diff --git a/src/library/structure/table.rs b/src/library/structure/table.rs
index f39ea978..cd70db30 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<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)?
}
})
}
diff --git a/src/library/text/deco.rs b/src/library/text/deco.rs
index dedaa6e8..cec4ca9e 100644
--- a/src/library/text/deco.rs
+++ b/src/library/text/deco.rs
@@ -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")?)))
}
}
diff --git a/src/library/text/link.rs b/src/library/text/link.rs
index 284f0b1f..728b594f 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<Content> {
+ fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
Ok(Content::show(Self {
url: args.expect::<EcoString>("url")?,
body: args.eat()?,
diff --git a/src/library/text/mod.rs b/src/library/text/mod.rs
index 1b83b0f4..bbe397ca 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<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")?)))
}
}
diff --git a/src/library/text/par.rs b/src/library/text/par.rs
index 6c274e7e..1269ffed 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<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 })
}
diff --git a/src/library/text/raw.rs b/src/library/text/raw.rs
index f44877ca..fe1f9a99 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<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),
diff --git a/src/library/text/repeat.rs b/src/library/text/repeat.rs
index 68036be7..9ee8286b 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<Content> {
+ fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
Ok(Content::inline(Self(args.expect("body")?)))
}
}
diff --git a/src/library/utility/color.rs b/src/library/utility/color.rs
index 75410380..5857c4c7 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<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! {
diff --git a/src/library/utility/math.rs b/src/library/utility/math.rs
index 63ec5e55..05c706ca 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<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),
diff --git a/src/library/utility/mod.rs b/src/library/utility/mod.rs
index 6f0f9a4c..051f8195 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<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());
}
diff --git a/src/library/utility/string.rs b/src/library/utility/string.rs
index 13a6bbd8..2f80a5cb 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<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)
}
diff --git a/src/main.rs b/src/main.rs
index 2865c67e..821f1008 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 64579747..c09979d5 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<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 {
diff --git a/src/model/mod.rs b/src/model/mod.rs
index a9d1344a..5c8b82c0 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 3404a384..e4417adf 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 caa30d7e..b334ae9a 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),
};