mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Move route from context to VM
This commit is contained in:
parent
6935cf8dfe
commit
c010cbc17d
@ -4,10 +4,10 @@ use std::sync::Arc;
|
|||||||
use iai::{black_box, main, Iai};
|
use iai::{black_box, main, Iai};
|
||||||
use unscanny::Scanner;
|
use unscanny::Scanner;
|
||||||
|
|
||||||
|
use typst::eval::evaluate;
|
||||||
use typst::loading::MemLoader;
|
use typst::loading::MemLoader;
|
||||||
use typst::parse::{parse, TokenMode, Tokens};
|
use typst::parse::{TokenMode, Tokens};
|
||||||
use typst::source::SourceId;
|
use typst::source::SourceId;
|
||||||
use typst::syntax::highlight_node;
|
|
||||||
use typst::{Config, Context};
|
use typst::{Config, Context};
|
||||||
|
|
||||||
const SRC: &str = include_str!("bench.typ");
|
const SRC: &str = include_str!("bench.typ");
|
||||||
@ -61,7 +61,7 @@ fn bench_tokenize(iai: &mut Iai) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn bench_parse(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) {
|
fn bench_edit(iai: &mut Iai) {
|
||||||
@ -73,7 +73,7 @@ fn bench_highlight(iai: &mut Iai) {
|
|||||||
let (ctx, id) = context();
|
let (ctx, id) = context();
|
||||||
let source = ctx.sources.get(id);
|
let source = ctx.sources.get(id);
|
||||||
iai.run(|| {
|
iai.run(|| {
|
||||||
highlight_node(
|
typst::syntax::highlight_node(
|
||||||
source.red().as_ref(),
|
source.red().as_ref(),
|
||||||
0 .. source.len_bytes(),
|
0 .. source.len_bytes(),
|
||||||
&mut |_, _| {},
|
&mut |_, _| {},
|
||||||
@ -83,17 +83,17 @@ fn bench_highlight(iai: &mut Iai) {
|
|||||||
|
|
||||||
fn bench_eval(iai: &mut Iai) {
|
fn bench_eval(iai: &mut Iai) {
|
||||||
let (mut ctx, id) = context();
|
let (mut ctx, id) = context();
|
||||||
iai.run(|| ctx.evaluate(id).unwrap());
|
iai.run(|| typst::eval::evaluate(&mut ctx, id, vec![]).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_layout(iai: &mut Iai) {
|
fn bench_layout(iai: &mut Iai) {
|
||||||
let (mut ctx, id) = context();
|
let (mut ctx, id) = context();
|
||||||
let module = ctx.evaluate(id).unwrap();
|
let module = evaluate(&mut ctx, id, vec![]).unwrap();
|
||||||
iai.run(|| module.content.layout(&mut ctx));
|
iai.run(|| typst::model::layout(&mut ctx, &module.content));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench_render(iai: &mut Iai) {
|
fn bench_render(iai: &mut Iai) {
|
||||||
let (mut ctx, id) = context();
|
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))
|
iai.run(|| typst::export::render(&mut ctx, &frames[0], 1.0))
|
||||||
}
|
}
|
||||||
|
@ -26,13 +26,8 @@ pub struct Arg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Args {
|
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.
|
/// 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
|
let items = values
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|value| Arg {
|
.map(|value| Arg {
|
||||||
|
@ -3,11 +3,10 @@ use std::fmt::{self, Debug, Formatter, Write};
|
|||||||
use std::ops::{Add, AddAssign};
|
use std::ops::{Add, AddAssign};
|
||||||
use std::sync::Arc;
|
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::diag::{At, StrResult, TypResult};
|
||||||
use crate::syntax::Spanned;
|
use crate::syntax::Spanned;
|
||||||
use crate::util::ArcExt;
|
use crate::util::ArcExt;
|
||||||
use crate::Context;
|
|
||||||
|
|
||||||
/// Create a new [`Array`] from values.
|
/// Create a new [`Array`] from values.
|
||||||
#[allow(unused_macros)]
|
#[allow(unused_macros)]
|
||||||
@ -120,21 +119,21 @@ impl Array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Transform each item in the array with a function.
|
/// 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
|
Ok(self
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.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<_>>()?)
|
.collect::<TypResult<_>>()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a new array with only those elements for which the function
|
/// Return a new array with only those elements for which the function
|
||||||
/// return true.
|
/// 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![];
|
let mut kept = vec![];
|
||||||
for item in self.iter() {
|
for item in self.iter() {
|
||||||
if f.v
|
if f.v
|
||||||
.call(ctx, Args::from_values(f.span, [item.clone()]))?
|
.call(vm, Args::new(f.span, [item.clone()]))?
|
||||||
.cast::<bool>()
|
.cast::<bool>()
|
||||||
.at(f.span)?
|
.at(f.span)?
|
||||||
{
|
{
|
||||||
|
@ -3,12 +3,11 @@ use std::fmt::{self, Debug, Formatter, Write};
|
|||||||
use std::ops::{Add, AddAssign};
|
use std::ops::{Add, AddAssign};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use super::{Args, Array, Func, Value};
|
use super::{Args, Array, Func, Machine, Value};
|
||||||
use crate::diag::{StrResult, TypResult};
|
use crate::diag::{StrResult, TypResult};
|
||||||
use crate::parse::is_ident;
|
use crate::parse::is_ident;
|
||||||
use crate::syntax::Spanned;
|
use crate::syntax::Spanned;
|
||||||
use crate::util::{ArcExt, EcoString};
|
use crate::util::{ArcExt, EcoString};
|
||||||
use crate::Context;
|
|
||||||
|
|
||||||
/// Create a new [`Dict`] from key-value pairs.
|
/// Create a new [`Dict`] from key-value pairs.
|
||||||
#[allow(unused_macros)]
|
#[allow(unused_macros)]
|
||||||
@ -97,14 +96,12 @@ impl Dict {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Transform each pair in the array with a function.
|
/// 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
|
Ok(self
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(key, value)| {
|
.map(|(key, value)| {
|
||||||
f.v.call(
|
let args = Args::new(f.span, [Value::Str(key.clone()), value.clone()]);
|
||||||
ctx,
|
f.v.call(vm, args)
|
||||||
Args::from_values(f.span, [Value::Str(key.clone()), value.clone()]),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.collect::<TypResult<_>>()?)
|
.collect::<TypResult<_>>()?)
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ impl Func {
|
|||||||
/// Create a new function from a native rust function.
|
/// Create a new function from a native rust function.
|
||||||
pub fn from_fn(
|
pub fn from_fn(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
func: fn(&mut Context, &mut Args) -> TypResult<Value>,
|
func: fn(&mut Machine, &mut Args) -> TypResult<Value>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self(Arc::new(Repr::Native(Native {
|
Self(Arc::new(Repr::Native(Native {
|
||||||
name,
|
name,
|
||||||
@ -86,19 +86,25 @@ impl Func {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Call the function with the given arguments.
|
/// 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() {
|
let value = match self.0.as_ref() {
|
||||||
Repr::Native(native) => (native.func)(ctx, &mut args)?,
|
Repr::Native(native) => (native.func)(vm, &mut args)?,
|
||||||
Repr::Closure(closure) => closure.call(ctx, &mut args)?,
|
Repr::Closure(closure) => closure.call(vm, &mut args)?,
|
||||||
Repr::With(wrapped, applied) => {
|
Repr::With(wrapped, applied) => {
|
||||||
args.items.splice(.. 0, applied.items.iter().cloned());
|
args.items.splice(.. 0, applied.items.iter().cloned());
|
||||||
return wrapped.call(ctx, args);
|
return wrapped.call(vm, args);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
args.finish()?;
|
args.finish()?;
|
||||||
Ok(value)
|
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.
|
/// Execute the function's set rule.
|
||||||
pub fn set(&self, mut args: Args) -> TypResult<StyleMap> {
|
pub fn set(&self, mut args: Args) -> TypResult<StyleMap> {
|
||||||
let styles = match self.0.as_ref() {
|
let styles = match self.0.as_ref() {
|
||||||
@ -138,7 +144,7 @@ struct Native {
|
|||||||
/// The name of the function.
|
/// The name of the function.
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
/// The function pointer.
|
/// The function pointer.
|
||||||
pub func: fn(&mut Context, &mut Args) -> TypResult<Value>,
|
pub func: fn(&mut Machine, &mut Args) -> TypResult<Value>,
|
||||||
/// The set rule.
|
/// The set rule.
|
||||||
pub set: Option<fn(&mut Args) -> TypResult<StyleMap>>,
|
pub set: Option<fn(&mut Args) -> TypResult<StyleMap>>,
|
||||||
/// The id of the node to customize with this function's show rule.
|
/// 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
|
/// This is passed only the arguments that remain after execution of the
|
||||||
/// node's set rule.
|
/// 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.
|
/// Parse the arguments into style properties for this node.
|
||||||
///
|
///
|
||||||
@ -192,7 +198,7 @@ pub struct Closure {
|
|||||||
|
|
||||||
impl Closure {
|
impl Closure {
|
||||||
/// Call the function in the context with the arguments.
|
/// Call the function in the context with the arguments.
|
||||||
pub fn call(&self, ctx: &mut 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
|
// Don't leak the scopes from the call site. Instead, we use the
|
||||||
// scope of captured variables we collected earlier.
|
// scope of captured variables we collected earlier.
|
||||||
let mut scopes = Scopes::new(None);
|
let mut scopes = Scopes::new(None);
|
||||||
@ -213,24 +219,20 @@ impl Closure {
|
|||||||
scopes.top.def_mut(sink, args.take());
|
scopes.top.def_mut(sink, args.take());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the new route if we are detached.
|
// Determine the route inside the closure.
|
||||||
let detached = ctx.route.is_empty();
|
let detached = vm.route.is_empty();
|
||||||
if detached {
|
let route = if detached {
|
||||||
ctx.route = self.location.into_iter().collect();
|
self.location.into_iter().collect()
|
||||||
}
|
} else {
|
||||||
|
vm.route.clone()
|
||||||
|
};
|
||||||
|
|
||||||
// Evaluate the body.
|
// Evaluate the body.
|
||||||
let mut vm = Machine::new(ctx, scopes);
|
let mut sub = Machine::new(vm.ctx, route, scopes);
|
||||||
let result = self.body.eval(&mut vm);
|
let result = self.body.eval(&mut sub);
|
||||||
let flow = vm.flow;
|
|
||||||
|
|
||||||
// Restore the old route.
|
|
||||||
if detached {
|
|
||||||
ctx.route.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle control flow.
|
// Handle control flow.
|
||||||
match flow {
|
match sub.flow {
|
||||||
Some(Flow::Return(_, Some(explicit))) => return Ok(explicit),
|
Some(Flow::Return(_, Some(explicit))) => return Ok(explicit),
|
||||||
Some(Flow::Return(_, None)) => {}
|
Some(Flow::Return(_, None)) => {}
|
||||||
Some(flow) => return Err(flow.forbidden())?,
|
Some(flow) => return Err(flow.forbidden())?,
|
||||||
|
@ -1,12 +1,18 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use super::{Scopes, Value};
|
use super::{Scopes, Value};
|
||||||
use crate::diag::TypError;
|
use crate::diag::{StrResult, TypError};
|
||||||
|
use crate::source::SourceId;
|
||||||
use crate::syntax::Span;
|
use crate::syntax::Span;
|
||||||
|
use crate::util::PathExt;
|
||||||
use crate::Context;
|
use crate::Context;
|
||||||
|
|
||||||
/// A virtual machine.
|
/// A virtual machine.
|
||||||
pub struct Machine<'a> {
|
pub struct Machine<'a> {
|
||||||
/// The core context.
|
/// The core context.
|
||||||
pub ctx: &'a mut 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.
|
/// The stack of scopes.
|
||||||
pub scopes: Scopes<'a>,
|
pub scopes: Scopes<'a>,
|
||||||
/// A control flow event that is currently happening.
|
/// A control flow event that is currently happening.
|
||||||
@ -15,8 +21,24 @@ pub struct Machine<'a> {
|
|||||||
|
|
||||||
impl<'a> Machine<'a> {
|
impl<'a> Machine<'a> {
|
||||||
/// Create a new virtual machine.
|
/// Create a new virtual machine.
|
||||||
pub fn new(ctx: &'a mut Context, scopes: Scopes<'a>) -> Self {
|
pub fn new(ctx: &'a mut Context, route: Vec<SourceId>, scopes: Scopes<'a>) -> Self {
|
||||||
Self { ctx, scopes, flow: None }
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
//! Methods on values.
|
//! Methods on values.
|
||||||
|
|
||||||
use super::{Args, Regex, StrExt, Value};
|
use super::{Args, Machine, Regex, StrExt, Value};
|
||||||
use crate::diag::{At, TypResult};
|
use crate::diag::{At, TypResult};
|
||||||
use crate::syntax::Span;
|
use crate::syntax::Span;
|
||||||
use crate::util::EcoString;
|
use crate::util::EcoString;
|
||||||
use crate::Context;
|
|
||||||
|
|
||||||
/// Call a method on a value.
|
/// Call a method on a value.
|
||||||
pub fn call(
|
pub fn call(
|
||||||
ctx: &mut Context,
|
vm: &mut Machine,
|
||||||
value: Value,
|
value: Value,
|
||||||
method: &str,
|
method: &str,
|
||||||
mut args: Args,
|
mut args: Args,
|
||||||
@ -35,8 +34,8 @@ pub fn call(
|
|||||||
}
|
}
|
||||||
Value::Array(array.slice(start, end).at(span)?)
|
Value::Array(array.slice(start, end).at(span)?)
|
||||||
}
|
}
|
||||||
"map" => Value::Array(array.map(ctx, args.expect("function")?)?),
|
"map" => Value::Array(array.map(vm, args.expect("function")?)?),
|
||||||
"filter" => Value::Array(array.filter(ctx, args.expect("function")?)?),
|
"filter" => Value::Array(array.filter(vm, args.expect("function")?)?),
|
||||||
"flatten" => Value::Array(array.flatten()),
|
"flatten" => Value::Array(array.flatten()),
|
||||||
"find" => array.find(args.expect("value")?).map_or(Value::None, Value::Int),
|
"find" => array.find(args.expect("value")?).map_or(Value::None, Value::Int),
|
||||||
"join" => {
|
"join" => {
|
||||||
@ -52,7 +51,7 @@ pub fn call(
|
|||||||
"len" => Value::Int(dict.len()),
|
"len" => Value::Int(dict.len()),
|
||||||
"keys" => Value::Array(dict.keys()),
|
"keys" => Value::Array(dict.keys()),
|
||||||
"values" => Value::Array(dict.values()),
|
"values" => Value::Array(dict.values()),
|
||||||
"pairs" => Value::Array(dict.map(ctx, args.expect("function")?)?),
|
"pairs" => Value::Array(dict.map(vm, args.expect("function")?)?),
|
||||||
_ => missing()?,
|
_ => missing()?,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -43,13 +43,63 @@ use crate::syntax::{Span, Spanned};
|
|||||||
use crate::util::EcoString;
|
use crate::util::EcoString;
|
||||||
use crate::Context;
|
use crate::Context;
|
||||||
|
|
||||||
/// Evaluate an expression.
|
/// Evaluate a source file and return the resulting module.
|
||||||
pub trait Eval {
|
///
|
||||||
/// The output of evaluating the expression.
|
/// Returns either a module containing a scope with top-level bindings and
|
||||||
type Output;
|
/// 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.
|
// Check whether the module was already evaluated.
|
||||||
fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output>;
|
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.
|
/// 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 {
|
impl Eval for Markup {
|
||||||
type Output = Content;
|
type Output = Content;
|
||||||
|
|
||||||
@ -553,7 +612,7 @@ impl Eval for FuncCall {
|
|||||||
Value::Dict(dict) => dict.get(&args.into_key()?).at(self.span())?.clone(),
|
Value::Dict(dict) => dict.get(&args.into_key()?).at(self.span())?.clone(),
|
||||||
Value::Func(func) => {
|
Value::Func(func) => {
|
||||||
let point = || Tracepoint::Call(func.name().map(ToString::to_string));
|
let point = || Tracepoint::Call(func.name().map(ToString::to_string));
|
||||||
func.call(vm.ctx, args).trace(point, self.span())?
|
func.call(vm, args).trace(point, self.span())?
|
||||||
}
|
}
|
||||||
|
|
||||||
v => bail!(
|
v => bail!(
|
||||||
@ -581,7 +640,7 @@ impl Eval for MethodCall {
|
|||||||
} else {
|
} else {
|
||||||
let value = self.receiver().eval(vm)?;
|
let value = self.receiver().eval(vm)?;
|
||||||
let args = self.args().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.
|
// Define the actual function.
|
||||||
Ok(Value::Func(Func::from_closure(Closure {
|
Ok(Value::Func(Func::from_closure(Closure {
|
||||||
location: vm.ctx.route.last().copied(),
|
location: vm.route.last().copied(),
|
||||||
name,
|
name,
|
||||||
captured,
|
captured,
|
||||||
params,
|
params,
|
||||||
@ -731,7 +790,7 @@ impl Eval for ShowExpr {
|
|||||||
let body = self.body();
|
let body = self.body();
|
||||||
let span = body.span();
|
let span = body.span();
|
||||||
let func = Func::from_closure(Closure {
|
let func = Func::from_closure(Closure {
|
||||||
location: vm.ctx.route.last().copied(),
|
location: vm.route.last().copied(),
|
||||||
name: None,
|
name: None,
|
||||||
captured,
|
captured,
|
||||||
params,
|
params,
|
||||||
@ -875,7 +934,7 @@ impl Eval for ImportExpr {
|
|||||||
fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
|
||||||
let span = self.path().span();
|
let span = self.path().span();
|
||||||
let path = self.path().eval(vm)?.cast::<EcoString>().at(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() {
|
match self.imports() {
|
||||||
Imports::Wildcard => {
|
Imports::Wildcard => {
|
||||||
@ -904,16 +963,16 @@ impl Eval for IncludeExpr {
|
|||||||
fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
|
fn eval(&self, vm: &mut Machine) -> TypResult<Self::Output> {
|
||||||
let span = self.path().span();
|
let span = self.path().span();
|
||||||
let path = self.path().eval(vm)?.cast::<EcoString>().at(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())
|
Ok(module.content.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process an import of a module relative to the current location.
|
/// 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.
|
// Load the source file.
|
||||||
let full = ctx.locate(&path).at(span)?;
|
let full = vm.locate(&path).at(span)?;
|
||||||
let id = ctx.sources.load(&full).map_err(|err| match err.kind() {
|
let id = vm.ctx.sources.load(&full).map_err(|err| match err.kind() {
|
||||||
std::io::ErrorKind::NotFound => {
|
std::io::ErrorKind::NotFound => {
|
||||||
error!(span, "file not found (searched at {})", full.display())
|
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.
|
// Prevent cyclic importing.
|
||||||
if ctx.route.contains(&id) {
|
if vm.route.contains(&id) {
|
||||||
bail!(span, "cyclic import");
|
bail!(span, "cyclic import");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate the file.
|
// Evaluate the file.
|
||||||
let module = ctx.evaluate(id).trace(|| Tracepoint::Import, span)?;
|
let route = vm.route.clone();
|
||||||
ctx.deps.extend(module.deps.iter().cloned());
|
let module = evaluate(vm.ctx, id, route).trace(|| Tracepoint::Import, span)?;
|
||||||
|
vm.ctx.deps.extend(module.deps.iter().cloned());
|
||||||
Ok(module)
|
Ok(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,10 +6,9 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
|
||||||
use super::{Args, Func, Node, Value};
|
use super::{Args, Func, Machine, Node, Value};
|
||||||
use crate::diag::TypResult;
|
use crate::diag::TypResult;
|
||||||
use crate::util::EcoString;
|
use crate::util::EcoString;
|
||||||
use crate::Context;
|
|
||||||
|
|
||||||
/// A slot where a variable is stored.
|
/// A slot where a variable is stored.
|
||||||
pub type Slot = Arc<RwLock<Value>>;
|
pub type Slot = Arc<RwLock<Value>>;
|
||||||
@ -89,7 +88,7 @@ impl Scope {
|
|||||||
pub fn def_fn(
|
pub fn def_fn(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &'static str,
|
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));
|
self.def_const(name, Func::from_fn(name, func));
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ use crate::Context;
|
|||||||
/// In addition to the frame, you need to pass in the context used during
|
/// 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
|
/// compilation so that fonts and images can be rendered and rendering artifacts
|
||||||
/// can be cached.
|
/// 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 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;
|
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,
|
canvas: &mut sk::Pixmap,
|
||||||
ts: sk::Transform,
|
ts: sk::Transform,
|
||||||
mask: Option<&sk::ClipMask>,
|
mask: Option<&sk::ClipMask>,
|
||||||
ctx: &mut Context,
|
ctx: &Context,
|
||||||
frame: &Frame,
|
frame: &Frame,
|
||||||
) {
|
) {
|
||||||
for (pos, element) in &frame.elements {
|
for (pos, element) in &frame.elements {
|
||||||
@ -72,7 +72,7 @@ fn render_group(
|
|||||||
canvas: &mut sk::Pixmap,
|
canvas: &mut sk::Pixmap,
|
||||||
ts: sk::Transform,
|
ts: sk::Transform,
|
||||||
mask: Option<&sk::ClipMask>,
|
mask: Option<&sk::ClipMask>,
|
||||||
ctx: &mut Context,
|
ctx: &Context,
|
||||||
group: &Group,
|
group: &Group,
|
||||||
) {
|
) {
|
||||||
let ts = ts.pre_concat(group.transform.into());
|
let ts = ts.pre_concat(group.transform.into());
|
||||||
@ -114,7 +114,7 @@ fn render_text(
|
|||||||
canvas: &mut sk::Pixmap,
|
canvas: &mut sk::Pixmap,
|
||||||
ts: sk::Transform,
|
ts: sk::Transform,
|
||||||
mask: Option<&sk::ClipMask>,
|
mask: Option<&sk::ClipMask>,
|
||||||
ctx: &mut Context,
|
ctx: &Context,
|
||||||
text: &Text,
|
text: &Text,
|
||||||
) {
|
) {
|
||||||
let mut x = 0.0;
|
let mut x = 0.0;
|
||||||
@ -136,7 +136,7 @@ fn render_svg_glyph(
|
|||||||
canvas: &mut sk::Pixmap,
|
canvas: &mut sk::Pixmap,
|
||||||
ts: sk::Transform,
|
ts: sk::Transform,
|
||||||
_: Option<&sk::ClipMask>,
|
_: Option<&sk::ClipMask>,
|
||||||
ctx: &mut Context,
|
ctx: &Context,
|
||||||
text: &Text,
|
text: &Text,
|
||||||
id: GlyphId,
|
id: GlyphId,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
@ -187,7 +187,7 @@ fn render_bitmap_glyph(
|
|||||||
canvas: &mut sk::Pixmap,
|
canvas: &mut sk::Pixmap,
|
||||||
ts: sk::Transform,
|
ts: sk::Transform,
|
||||||
mask: Option<&sk::ClipMask>,
|
mask: Option<&sk::ClipMask>,
|
||||||
ctx: &mut Context,
|
ctx: &Context,
|
||||||
text: &Text,
|
text: &Text,
|
||||||
id: GlyphId,
|
id: GlyphId,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
@ -213,7 +213,7 @@ fn render_outline_glyph(
|
|||||||
canvas: &mut sk::Pixmap,
|
canvas: &mut sk::Pixmap,
|
||||||
ts: sk::Transform,
|
ts: sk::Transform,
|
||||||
mask: Option<&sk::ClipMask>,
|
mask: Option<&sk::ClipMask>,
|
||||||
ctx: &mut Context,
|
ctx: &Context,
|
||||||
text: &Text,
|
text: &Text,
|
||||||
id: GlyphId,
|
id: GlyphId,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
|
103
src/lib.rs
103
src/lib.rs
@ -21,10 +21,10 @@
|
|||||||
//! [parsed]: parse::parse
|
//! [parsed]: parse::parse
|
||||||
//! [green tree]: syntax::GreenNode
|
//! [green tree]: syntax::GreenNode
|
||||||
//! [AST]: syntax::ast
|
//! [AST]: syntax::ast
|
||||||
//! [evaluate]: eval::Eval
|
//! [evaluate]: eval::evaluate
|
||||||
//! [module]: eval::Module
|
//! [module]: eval::Module
|
||||||
//! [content]: model::Content
|
//! [content]: model::Content
|
||||||
//! [layouted]: model::Content::layout
|
//! [layouted]: model::layout
|
||||||
//! [PDF]: export::pdf
|
//! [PDF]: export::pdf
|
||||||
|
|
||||||
#![allow(clippy::len_without_is_empty)]
|
#![allow(clippy::len_without_is_empty)]
|
||||||
@ -52,19 +52,27 @@ pub mod source;
|
|||||||
pub mod syntax;
|
pub mod syntax;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::mem;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::diag::{StrResult, TypResult};
|
use crate::diag::TypResult;
|
||||||
use crate::eval::{Eval, Machine, Module, Scope, Scopes};
|
use crate::eval::{Module, Scope};
|
||||||
use crate::font::FontStore;
|
use crate::font::FontStore;
|
||||||
use crate::frame::Frame;
|
use crate::frame::Frame;
|
||||||
use crate::image::ImageStore;
|
use crate::image::ImageStore;
|
||||||
use crate::loading::Loader;
|
use crate::loading::Loader;
|
||||||
use crate::model::StyleMap;
|
use crate::model::StyleMap;
|
||||||
use crate::source::{SourceId, SourceStore};
|
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.
|
/// The core context which holds the configuration and stores.
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
@ -78,8 +86,6 @@ pub struct Context {
|
|||||||
pub config: Config,
|
pub config: Config,
|
||||||
/// Cached modules.
|
/// Cached modules.
|
||||||
modules: HashMap<SourceId, Module>,
|
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.
|
/// The dependencies of the current evaluation process.
|
||||||
deps: Vec<(SourceId, usize)>,
|
deps: Vec<(SourceId, usize)>,
|
||||||
}
|
}
|
||||||
@ -93,90 +99,9 @@ impl Context {
|
|||||||
images: ImageStore::new(loader),
|
images: ImageStore::new(loader),
|
||||||
config,
|
config,
|
||||||
modules: HashMap::new(),
|
modules: HashMap::new(),
|
||||||
route: vec![],
|
|
||||||
deps: 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.
|
/// Compilation configuration.
|
||||||
|
@ -6,7 +6,7 @@ pub struct HideNode(pub LayoutNode);
|
|||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl HideNode {
|
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")?)))
|
Ok(Content::inline(Self(args.expect("body")?)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,12 @@ impl ImageNode {
|
|||||||
/// How the image should adjust itself to a given area.
|
/// How the image should adjust itself to a given area.
|
||||||
pub const FIT: ImageFit = ImageFit::Cover;
|
pub const FIT: ImageFit = ImageFit::Cover;
|
||||||
|
|
||||||
fn construct(ctx: &mut Context, args: &mut Args) -> TypResult<Content> {
|
fn construct(vm: &mut Machine, args: &mut Args) -> TypResult<Content> {
|
||||||
let Spanned { v: path, span } =
|
let Spanned { v: path, span } =
|
||||||
args.expect::<Spanned<EcoString>>("path to image file")?;
|
args.expect::<Spanned<EcoString>>("path to image file")?;
|
||||||
|
|
||||||
let full = ctx.locate(&path).at(span)?;
|
let full = vm.locate(&path).at(span)?;
|
||||||
let id = ctx.images.load(&full).map_err(|err| match err.kind() {
|
let id = vm.ctx.images.load(&full).map_err(|err| match err.kind() {
|
||||||
std::io::ErrorKind::NotFound => {
|
std::io::ErrorKind::NotFound => {
|
||||||
error!(span, "file not found (searched at {})", full.display())
|
error!(span, "file not found (searched at {})", full.display())
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ impl LineNode {
|
|||||||
#[property(resolve, fold)]
|
#[property(resolve, fold)]
|
||||||
pub const STROKE: RawStroke = RawStroke::default();
|
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 origin = args.named("origin")?.unwrap_or_default();
|
||||||
|
|
||||||
let delta = match args.named::<Spec<Relative<RawLength>>>("to")? {
|
let delta = match args.named::<Spec<Relative<RawLength>>>("to")? {
|
||||||
|
@ -37,7 +37,7 @@ impl<const S: ShapeKind> ShapeNode<S> {
|
|||||||
#[property(skip, resolve, fold)]
|
#[property(skip, resolve, fold)]
|
||||||
pub const RADIUS: Sides<Option<Relative<RawLength>>> = Sides::splat(Relative::zero());
|
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 {
|
let size = match S {
|
||||||
SQUARE => args.named::<RawLength>("size")?.map(Relative::from),
|
SQUARE => args.named::<RawLength>("size")?.map(Relative::from),
|
||||||
CIRCLE => args.named::<RawLength>("radius")?.map(|r| 2.0 * Relative::from(r)),
|
CIRCLE => args.named::<RawLength>("radius")?.map(|r| 2.0 * Relative::from(r)),
|
||||||
|
@ -12,7 +12,7 @@ pub struct MoveNode {
|
|||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl MoveNode {
|
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 dx = args.named("dx")?.unwrap_or_default();
|
||||||
let dy = args.named("dy")?.unwrap_or_default();
|
let dy = args.named("dy")?.unwrap_or_default();
|
||||||
Ok(Content::inline(Self {
|
Ok(Content::inline(Self {
|
||||||
@ -62,7 +62,7 @@ impl<const T: TransformKind> TransformNode<T> {
|
|||||||
#[property(resolve)]
|
#[property(resolve)]
|
||||||
pub const ORIGIN: Spec<Option<RawAlign>> = Spec::default();
|
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 {
|
let transform = match T {
|
||||||
ROTATE => {
|
ROTATE => {
|
||||||
let angle = args.named_or_find("angle")?.unwrap_or_default();
|
let angle = args.named_or_find("angle")?.unwrap_or_default();
|
||||||
|
@ -12,7 +12,7 @@ pub struct AlignNode {
|
|||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl AlignNode {
|
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 aligns: Spec<Option<RawAlign>> = args.find()?.unwrap_or_default();
|
||||||
let body: Content = args.expect("body")?;
|
let body: Content = args.expect("body")?;
|
||||||
Ok(match (body, aligns) {
|
Ok(match (body, aligns) {
|
||||||
|
@ -17,7 +17,7 @@ impl ColumnsNode {
|
|||||||
#[property(resolve)]
|
#[property(resolve)]
|
||||||
pub const GUTTER: Relative<RawLength> = Ratio::new(0.04).into();
|
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 {
|
Ok(Content::block(Self {
|
||||||
columns: args.expect("column count")?,
|
columns: args.expect("column count")?,
|
||||||
child: args.expect("body")?,
|
child: args.expect("body")?,
|
||||||
@ -106,7 +106,7 @@ pub struct ColbreakNode;
|
|||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl ColbreakNode {
|
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);
|
let weak = args.named("weak")?.unwrap_or(false);
|
||||||
Ok(Content::Colbreak { weak })
|
Ok(Content::Colbreak { weak })
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ pub struct BoxNode;
|
|||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl BoxNode {
|
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 width = args.named("width")?;
|
||||||
let height = args.named("height")?;
|
let height = args.named("height")?;
|
||||||
let body: LayoutNode = args.eat()?.unwrap_or_default();
|
let body: LayoutNode = args.eat()?.unwrap_or_default();
|
||||||
@ -18,7 +18,7 @@ pub struct BlockNode;
|
|||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl BlockNode {
|
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()))
|
Ok(Content::Block(args.eat()?.unwrap_or_default()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ pub struct GridNode {
|
|||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl GridNode {
|
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 columns = args.named("columns")?.unwrap_or_default();
|
||||||
let rows = args.named("rows")?.unwrap_or_default();
|
let rows = args.named("rows")?.unwrap_or_default();
|
||||||
let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default();
|
let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default();
|
||||||
|
@ -11,7 +11,7 @@ pub struct PadNode {
|
|||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl PadNode {
|
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 all = args.named("rest")?.or(args.find()?);
|
||||||
let x = args.named("x")?;
|
let x = args.named("x")?;
|
||||||
let y = args.named("y")?;
|
let y = args.named("y")?;
|
||||||
|
@ -35,7 +35,7 @@ impl PageNode {
|
|||||||
#[property(referenced)]
|
#[property(referenced)]
|
||||||
pub const FOOTER: Marginal = Marginal::None;
|
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")?)))
|
Ok(Content::Page(Self(args.expect("body")?)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ impl PageNode {
|
|||||||
let w = size.x - padding.left - padding.right;
|
let w = size.x - padding.left - padding.right;
|
||||||
let area = Size::new(w, h);
|
let area = Size::new(w, h);
|
||||||
let pod = Regions::one(area, area, area.map(Length::is_finite));
|
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);
|
Arc::make_mut(frame).push_frame(pos, sub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,7 +134,7 @@ pub struct PagebreakNode;
|
|||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl PagebreakNode {
|
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);
|
let weak = args.named("weak")?.unwrap_or(false);
|
||||||
Ok(Content::Pagebreak { weak })
|
Ok(Content::Pagebreak { weak })
|
||||||
}
|
}
|
||||||
@ -158,8 +158,8 @@ impl Marginal {
|
|||||||
Self::None => None,
|
Self::None => None,
|
||||||
Self::Content(content) => Some(content.clone()),
|
Self::Content(content) => Some(content.clone()),
|
||||||
Self::Func(func, span) => {
|
Self::Func(func, span) => {
|
||||||
let args = Args::from_values(*span, [Value::Int(page as i64)]);
|
let args = Args::new(*span, [Value::Int(page as i64)]);
|
||||||
Some(func.call(ctx, args)?.display())
|
Some(func.call_detached(ctx, args)?.display())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ pub struct PlaceNode(pub LayoutNode);
|
|||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl PlaceNode {
|
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 aligns = args.find()?.unwrap_or(Spec::with_x(Some(RawAlign::Start)));
|
||||||
let dx = args.named("dx")?.unwrap_or_default();
|
let dx = args.named("dx")?.unwrap_or_default();
|
||||||
let dy = args.named("dy")?.unwrap_or_default();
|
let dy = args.named("dy")?.unwrap_or_default();
|
||||||
|
@ -8,7 +8,7 @@ pub struct HNode;
|
|||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl HNode {
|
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 amount = args.expect("spacing")?;
|
||||||
let weak = args.named("weak")?.unwrap_or(false);
|
let weak = args.named("weak")?.unwrap_or(false);
|
||||||
Ok(Content::Horizontal { amount, weak })
|
Ok(Content::Horizontal { amount, weak })
|
||||||
@ -20,7 +20,7 @@ pub struct VNode;
|
|||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl VNode {
|
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 amount = args.expect("spacing")?;
|
||||||
let weak = args.named("weak")?.unwrap_or(false);
|
let weak = args.named("weak")?.unwrap_or(false);
|
||||||
Ok(Content::Vertical { amount, weak, generated: false })
|
Ok(Content::Vertical { amount, weak, generated: false })
|
||||||
|
@ -15,7 +15,7 @@ pub struct StackNode {
|
|||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl StackNode {
|
impl StackNode {
|
||||||
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
|
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
|
||||||
Ok(Content::block(Self {
|
Ok(Content::block(Self {
|
||||||
dir: args.named("dir")?.unwrap_or(Dir::TTB),
|
dir: args.named("dir")?.unwrap_or(Dir::TTB),
|
||||||
spacing: args.named("spacing")?,
|
spacing: args.named("spacing")?,
|
||||||
|
@ -28,7 +28,7 @@ impl MathNode {
|
|||||||
#[property(resolve, shorthand(around))]
|
#[property(resolve, shorthand(around))]
|
||||||
pub const BELOW: Option<BlockSpacing> = Some(Ratio::one().into());
|
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 {
|
Ok(Content::show(Self {
|
||||||
formula: args.expect("formula")?,
|
formula: args.expect("formula")?,
|
||||||
display: args.named("display")?.unwrap_or(false),
|
display: args.named("display")?.unwrap_or(false),
|
||||||
|
@ -9,8 +9,8 @@ pub use typst_macros::node;
|
|||||||
|
|
||||||
pub use crate::diag::{with_alternative, At, Error, StrResult, TypError, TypResult};
|
pub use crate::diag::{with_alternative, At, Error, StrResult, TypError, TypResult};
|
||||||
pub use crate::eval::{
|
pub use crate::eval::{
|
||||||
Arg, Args, Array, Cast, Dict, Func, Node, RawAlign, RawLength, RawStroke, Scope,
|
Arg, Args, Array, Cast, Dict, Func, Machine, Node, RawAlign, RawLength, RawStroke,
|
||||||
Smart, Value,
|
Scope, Smart, Value,
|
||||||
};
|
};
|
||||||
pub use crate::frame::*;
|
pub use crate::frame::*;
|
||||||
pub use crate::geom::*;
|
pub use crate::geom::*;
|
||||||
|
@ -55,7 +55,7 @@ impl HeadingNode {
|
|||||||
pub const BELOW: Leveled<Option<BlockSpacing>> =
|
pub const BELOW: Leveled<Option<BlockSpacing>> =
|
||||||
Leveled::Value(Some(Ratio::new(0.55).into()));
|
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 {
|
Ok(Content::show(Self {
|
||||||
body: args.expect("body")?,
|
body: args.expect("body")?,
|
||||||
level: args.named("level")?.unwrap_or(NonZeroUsize::new(1).unwrap()),
|
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::Value(value) => value.clone(),
|
||||||
Self::Mapping(mapping) => mapping(level),
|
Self::Mapping(mapping) => mapping(level),
|
||||||
Self::Func(func, span) => {
|
Self::Func(func, span) => {
|
||||||
let args = Args::from_values(*span, [Value::Int(level.get() as i64)]);
|
let args = Args::new(*span, [Value::Int(level.get() as i64)]);
|
||||||
func.call(ctx, args)?.cast().at(*span)?
|
func.call_detached(ctx, args)?.cast().at(*span)?
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ impl<const L: ListKind> ListNode<L> {
|
|||||||
#[property(resolve)]
|
#[property(resolve)]
|
||||||
pub const SPACING: BlockSpacing = Ratio::one().into();
|
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 {
|
Ok(Content::show(Self {
|
||||||
start: args.named("start")?.unwrap_or(1),
|
start: args.named("start")?.unwrap_or(1),
|
||||||
tight: args.named("tight")?.unwrap_or(true),
|
tight: args.named("tight")?.unwrap_or(true),
|
||||||
@ -216,8 +216,8 @@ impl Label {
|
|||||||
}
|
}
|
||||||
Self::Content(content) => content.clone(),
|
Self::Content(content) => content.clone(),
|
||||||
Self::Func(func, span) => {
|
Self::Func(func, span) => {
|
||||||
let args = Args::from_values(*span, [Value::Int(number as i64)]);
|
let args = Args::new(*span, [Value::Int(number as i64)]);
|
||||||
func.call(ctx, args)?.display()
|
func.call_detached(ctx, args)?.display()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ impl TableNode {
|
|||||||
#[property(resolve, shorthand(around))]
|
#[property(resolve, shorthand(around))]
|
||||||
pub const BELOW: Option<BlockSpacing> = Some(Ratio::one().into());
|
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 columns = args.named("columns")?.unwrap_or_default();
|
||||||
let rows = args.named("rows")?.unwrap_or_default();
|
let rows = args.named("rows")?.unwrap_or_default();
|
||||||
let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default();
|
let base_gutter: Vec<TrackSizing> = args.named("gutter")?.unwrap_or_default();
|
||||||
@ -128,11 +128,8 @@ impl<T: Cast + Clone> Celled<T> {
|
|||||||
Ok(match self {
|
Ok(match self {
|
||||||
Self::Value(value) => value.clone(),
|
Self::Value(value) => value.clone(),
|
||||||
Self::Func(func, span) => {
|
Self::Func(func, span) => {
|
||||||
let args = Args::from_values(*span, [
|
let args = Args::new(*span, [Value::Int(x as i64), Value::Int(y as i64)]);
|
||||||
Value::Int(x as i64),
|
func.call_detached(ctx, args)?.cast().at(*span)?
|
||||||
Value::Int(y as i64),
|
|
||||||
]);
|
|
||||||
func.call(ctx, args)?.cast().at(*span)?
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ impl<const L: DecoLine> DecoNode<L> {
|
|||||||
/// with the glyphs. Does not apply to strikethrough.
|
/// with the glyphs. Does not apply to strikethrough.
|
||||||
pub const EVADE: bool = true;
|
pub const EVADE: bool = true;
|
||||||
|
|
||||||
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
|
fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> {
|
||||||
Ok(Content::show(Self(args.expect("body")?)))
|
Ok(Content::show(Self(args.expect("body")?)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ impl LinkNode {
|
|||||||
/// Whether to underline link.
|
/// Whether to underline link.
|
||||||
pub const UNDERLINE: bool = true;
|
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 {
|
Ok(Content::show(Self {
|
||||||
url: args.expect::<EcoString>("url")?,
|
url: args.expect::<EcoString>("url")?,
|
||||||
body: args.eat()?,
|
body: args.eat()?,
|
||||||
|
@ -127,7 +127,7 @@ impl TextNode {
|
|||||||
#[property(skip, fold)]
|
#[property(skip, fold)]
|
||||||
pub const DECO: Decoration = vec![];
|
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.
|
// The text constructor is special: It doesn't create a text node.
|
||||||
// Instead, it leaves the passed argument structurally unchanged, but
|
// Instead, it leaves the passed argument structurally unchanged, but
|
||||||
// styles all text in it.
|
// styles all text in it.
|
||||||
@ -443,12 +443,12 @@ impl Fold for Vec<(Tag, u32)> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Convert text to lowercase.
|
/// 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)
|
case(Case::Lower, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert text to uppercase.
|
/// 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)
|
case(Case::Upper, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -482,7 +482,7 @@ impl Case {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Display text in small capitals.
|
/// 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")?;
|
let body: Content = args.expect("content")?;
|
||||||
Ok(Value::Content(body.styled(TextNode::SMALLCAPS, true)))
|
Ok(Value::Content(body.styled(TextNode::SMALLCAPS, true)))
|
||||||
}
|
}
|
||||||
@ -514,7 +514,7 @@ pub struct StrongNode(pub Content);
|
|||||||
|
|
||||||
#[node(showable)]
|
#[node(showable)]
|
||||||
impl StrongNode {
|
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")?)))
|
Ok(Content::show(Self(args.expect("body")?)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -539,7 +539,7 @@ pub struct EmphNode(pub Content);
|
|||||||
|
|
||||||
#[node(showable)]
|
#[node(showable)]
|
||||||
impl EmphNode {
|
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")?)))
|
Ok(Content::show(Self(args.expect("body")?)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ impl ParNode {
|
|||||||
#[property(resolve)]
|
#[property(resolve)]
|
||||||
pub const LINEBREAKS: Smart<Linebreaks> = Smart::Auto;
|
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
|
// The paragraph constructor is special: It doesn't create a paragraph
|
||||||
// node. Instead, it just ensures that the passed content lives is in a
|
// node. Instead, it just ensures that the passed content lives is in a
|
||||||
// separate paragraph and styles it.
|
// separate paragraph and styles it.
|
||||||
@ -172,7 +172,7 @@ pub struct ParbreakNode;
|
|||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl ParbreakNode {
|
impl ParbreakNode {
|
||||||
fn construct(_: &mut Context, _: &mut Args) -> TypResult<Content> {
|
fn construct(_: &mut Machine, _: &mut Args) -> TypResult<Content> {
|
||||||
Ok(Content::Parbreak)
|
Ok(Content::Parbreak)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,7 +182,7 @@ pub struct LinebreakNode;
|
|||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl LinebreakNode {
|
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);
|
let justified = args.named("justified")?.unwrap_or(false);
|
||||||
Ok(Content::Linebreak { justified })
|
Ok(Content::Linebreak { justified })
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ impl RawNode {
|
|||||||
#[property(resolve, shorthand(around))]
|
#[property(resolve, shorthand(around))]
|
||||||
pub const BELOW: Option<BlockSpacing> = Some(Ratio::one().into());
|
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 {
|
Ok(Content::show(Self {
|
||||||
text: args.expect("text")?,
|
text: args.expect("text")?,
|
||||||
block: args.named("block")?.unwrap_or(false),
|
block: args.named("block")?.unwrap_or(false),
|
||||||
|
@ -6,7 +6,7 @@ pub struct RepeatNode(pub LayoutNode);
|
|||||||
|
|
||||||
#[node]
|
#[node]
|
||||||
impl RepeatNode {
|
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")?)))
|
Ok(Content::inline(Self(args.expect("body")?)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use std::str::FromStr;
|
|||||||
use crate::library::prelude::*;
|
use crate::library::prelude::*;
|
||||||
|
|
||||||
/// Create an RGB(A) color.
|
/// 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(
|
Ok(Value::from(
|
||||||
if let Some(string) = args.find::<Spanned<EcoString>>()? {
|
if let Some(string) = args.find::<Spanned<EcoString>>()? {
|
||||||
match RgbaColor::from_str(&string.v) {
|
match RgbaColor::from_str(&string.v) {
|
||||||
@ -37,7 +37,7 @@ pub fn rgb(_: &mut Context, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a CMYK color.
|
/// 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);
|
struct Component(u8);
|
||||||
|
|
||||||
castable! {
|
castable! {
|
||||||
|
@ -3,7 +3,7 @@ use std::cmp::Ordering;
|
|||||||
use crate::library::prelude::*;
|
use crate::library::prelude::*;
|
||||||
|
|
||||||
/// Convert a value to a integer.
|
/// 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")?;
|
let Spanned { v, span } = args.expect("value")?;
|
||||||
Ok(Value::Int(match v {
|
Ok(Value::Int(match v {
|
||||||
Value::Bool(v) => v as i64,
|
Value::Bool(v) => v as i64,
|
||||||
@ -18,7 +18,7 @@ pub fn int(_: &mut Context, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a value to a float.
|
/// 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")?;
|
let Spanned { v, span } = args.expect("value")?;
|
||||||
Ok(Value::Float(match v {
|
Ok(Value::Float(match v {
|
||||||
Value::Int(v) => v as f64,
|
Value::Int(v) => v as f64,
|
||||||
@ -32,7 +32,7 @@ pub fn float(_: &mut Context, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The absolute value of a numeric 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")?;
|
let Spanned { v, span } = args.expect("numeric value")?;
|
||||||
Ok(match v {
|
Ok(match v {
|
||||||
Value::Int(v) => Value::Int(v.abs()),
|
Value::Int(v) => Value::Int(v.abs()),
|
||||||
@ -48,12 +48,12 @@ pub fn abs(_: &mut Context, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The minimum of a sequence of values.
|
/// 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)
|
minmax(args, Ordering::Less)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The maximum of a sequence of values.
|
/// 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)
|
minmax(args, Ordering::Greater)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,17 +79,17 @@ fn minmax(args: &mut Args, goal: Ordering) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Whether an integer is even.
|
/// 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))
|
Ok(Value::Bool(args.expect::<i64>("integer")? % 2 == 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether an integer is odd.
|
/// 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))
|
Ok(Value::Bool(args.expect::<i64>("integer")? % 2 != 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The modulo of two numbers.
|
/// 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: v1, span: span1 } = args.expect("integer or float")?;
|
||||||
let Spanned { v: v2, span: span2 } = args.expect("integer or float")?;
|
let Spanned { v: v2, span: span2 } = args.expect("integer or float")?;
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ pub fn mod_(_: &mut Context, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a sequence of numbers.
|
/// 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 first = args.expect::<i64>("end")?;
|
||||||
let (start, end) = match args.eat::<i64>()? {
|
let (start, end) = match args.eat::<i64>()? {
|
||||||
Some(second) => (first, second),
|
Some(second) => (first, second),
|
||||||
|
@ -8,19 +8,17 @@ pub use color::*;
|
|||||||
pub use math::*;
|
pub use math::*;
|
||||||
pub use string::*;
|
pub use string::*;
|
||||||
|
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
use crate::eval::{Eval, Machine, Scopes};
|
use crate::eval::{Eval, Machine, Scopes};
|
||||||
use crate::library::prelude::*;
|
use crate::library::prelude::*;
|
||||||
use crate::source::SourceFile;
|
use crate::source::SourceFile;
|
||||||
|
|
||||||
/// The name of a value's type.
|
/// 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())
|
Ok(args.expect::<Value>("value")?.type_name().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensure that a condition is fulfilled.
|
/// 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")?;
|
let Spanned { v, span } = args.expect::<Spanned<bool>>("condition")?;
|
||||||
if !v {
|
if !v {
|
||||||
bail!(span, "assertion failed");
|
bail!(span, "assertion failed");
|
||||||
@ -29,28 +27,21 @@ pub fn assert(_: &mut Context, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a string as Typst markup.
|
/// 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")?;
|
let Spanned { v: src, span } = args.expect::<Spanned<String>>("source")?;
|
||||||
|
|
||||||
// Parse the source and set a synthetic span for all nodes.
|
// Parse the source and set a synthetic span for all nodes.
|
||||||
let source = SourceFile::synthesized(src, span);
|
let source = SourceFile::synthesized(src, span);
|
||||||
let ast = source.ast()?;
|
let ast = source.ast()?;
|
||||||
|
|
||||||
// Save the old route, then detach it.
|
|
||||||
let prev_route = mem::take(&mut ctx.route);
|
|
||||||
|
|
||||||
// Evaluate the source.
|
// Evaluate the source.
|
||||||
let std = ctx.config.std.clone();
|
let std = vm.ctx.config.std.clone();
|
||||||
let scopes = Scopes::new(Some(&std));
|
let scopes = Scopes::new(Some(&std));
|
||||||
let mut vm = Machine::new(ctx, scopes);
|
let mut sub = Machine::new(vm.ctx, vec![], scopes);
|
||||||
let result = ast.eval(&mut vm);
|
let result = ast.eval(&mut sub);
|
||||||
let flow = vm.flow;
|
|
||||||
|
|
||||||
// Restore the old route.
|
|
||||||
ctx.route = prev_route;
|
|
||||||
|
|
||||||
// Handle control flow.
|
// Handle control flow.
|
||||||
if let Some(flow) = flow {
|
if let Some(flow) = sub.flow {
|
||||||
return Err(flow.forbidden());
|
return Err(flow.forbidden());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,12 +4,12 @@ use crate::eval::Regex;
|
|||||||
use crate::library::prelude::*;
|
use crate::library::prelude::*;
|
||||||
|
|
||||||
/// The string representation of a value.
|
/// 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())
|
Ok(args.expect::<Value>("value")?.repr().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cconvert a value to a string.
|
/// 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")?;
|
let Spanned { v, span } = args.expect("value")?;
|
||||||
Ok(Value::Str(match v {
|
Ok(Value::Str(match v {
|
||||||
Value::Int(v) => format_eco!("{}", v),
|
Value::Int(v) => format_eco!("{}", v),
|
||||||
@ -20,29 +20,29 @@ pub fn str(_: &mut Context, args: &mut Args) -> TypResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create blind text.
|
/// 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")?;
|
let words: usize = args.expect("number of words")?;
|
||||||
Ok(Value::Str(lipsum_from_seed(words, 97).into()))
|
Ok(Value::Str(lipsum_from_seed(words, 97).into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a regular expression.
|
/// 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")?;
|
let Spanned { v, span } = args.expect::<Spanned<EcoString>>("regular expression")?;
|
||||||
Ok(Regex::new(&v).at(span)?.into())
|
Ok(Regex::new(&v).at(span)?.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts an integer into one or multiple letters.
|
/// 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)
|
convert(Numbering::Letter, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts an integer into a roman numeral.
|
/// 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(Numbering::Roman, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a number into a symbol.
|
/// 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)
|
convert(Numbering::Symbol, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,7 +214,7 @@ fn typeset(command: TypesetCommand) -> StrResult<()> {
|
|||||||
.map_err(|_| "failed to load source file")?;
|
.map_err(|_| "failed to load source file")?;
|
||||||
|
|
||||||
// Typeset.
|
// Typeset.
|
||||||
match ctx.typeset(id) {
|
match typst::typeset(&mut ctx, id) {
|
||||||
// Export the PDF.
|
// Export the PDF.
|
||||||
Ok(frames) => {
|
Ok(frames) => {
|
||||||
let buffer = export::pdf(&ctx, &frames);
|
let buffer = export::pdf(&ctx, &frames);
|
||||||
|
@ -19,6 +19,19 @@ use crate::library::text::{
|
|||||||
};
|
};
|
||||||
use crate::util::EcoString;
|
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(©);
|
||||||
|
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.
|
/// Composable representation of styled content.
|
||||||
///
|
///
|
||||||
/// This results from:
|
/// This results from:
|
||||||
@ -207,19 +220,6 @@ impl Content {
|
|||||||
|
|
||||||
Self::sequence(seq)
|
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(©);
|
|
||||||
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 {
|
impl Layout for Content {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! Structured representation of styled content.
|
//! Styled and structured representation of layoutable content.
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod styles;
|
mod styles;
|
||||||
|
@ -82,12 +82,12 @@ impl Recipe {
|
|||||||
F: FnOnce() -> Value,
|
F: FnOnce() -> Value,
|
||||||
{
|
{
|
||||||
let args = if self.func.argc() == Some(0) {
|
let args = if self.func.argc() == Some(0) {
|
||||||
Args::new(self.span)
|
Args::new(self.span, [])
|
||||||
} else {
|
} 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.
|
/// What kind of structure the property interrupts.
|
||||||
|
@ -290,7 +290,7 @@ fn test_part(
|
|||||||
|
|
||||||
ok &= test_reparse(ctx.sources.get(id).src(), i, rng);
|
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![]),
|
Ok(frames) => (frames, vec![]),
|
||||||
Err(errors) => (vec![], *errors),
|
Err(errors) => (vec![], *errors),
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user