Protect Vm

This commit is contained in:
Laurenz 2022-11-24 17:39:08 +01:00
parent 5ae81971f2
commit 8d3c68a1de
38 changed files with 101 additions and 93 deletions

View File

@ -3,7 +3,7 @@ use std::cmp::Ordering;
use crate::prelude::*;
/// Convert a value to an integer.
pub fn int(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn int(_: &Vm, args: &mut Args) -> SourceResult<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 Vm, args: &mut Args) -> SourceResult<Value> {
}
/// Convert a value to a float.
pub fn float(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn float(_: &Vm, args: &mut Args) -> SourceResult<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 Vm, args: &mut Args) -> SourceResult<Value> {
}
/// The absolute value of a numeric value.
pub fn abs(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn abs(_: &Vm, args: &mut Args) -> SourceResult<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 Vm, args: &mut Args) -> SourceResult<Value> {
}
/// The minimum of a sequence of values.
pub fn min(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn min(_: &Vm, args: &mut Args) -> SourceResult<Value> {
minmax(args, Ordering::Less)
}
/// The maximum of a sequence of values.
pub fn max(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn max(_: &Vm, args: &mut Args) -> SourceResult<Value> {
minmax(args, Ordering::Greater)
}
@ -79,17 +79,17 @@ fn minmax(args: &mut Args, goal: Ordering) -> SourceResult<Value> {
}
/// Whether an integer is even.
pub fn even(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn even(_: &Vm, args: &mut Args) -> SourceResult<Value> {
Ok(Value::Bool(args.expect::<i64>("integer")? % 2 == 0))
}
/// Whether an integer is odd.
pub fn odd(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn odd(_: &Vm, args: &mut Args) -> SourceResult<Value> {
Ok(Value::Bool(args.expect::<i64>("integer")? % 2 != 0))
}
/// The modulo of two numbers.
pub fn mod_(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn mod_(_: &Vm, args: &mut Args) -> SourceResult<Value> {
let Spanned { v: v1, span: span1 } = args.expect("integer or float")?;
let Spanned { v: v2, span: span2 } = args.expect("integer or float")?;
@ -117,7 +117,7 @@ pub fn mod_(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
}
/// Create a sequence of numbers.
pub fn range(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn range(_: &Vm, args: &mut Args) -> SourceResult<Value> {
let first = args.expect::<i64>("end")?;
let (start, end) = match args.eat::<i64>()? {
Some(second) => (first, second),

View File

@ -3,13 +3,13 @@ use std::str::FromStr;
use crate::prelude::*;
/// Create a grayscale color.
pub fn luma(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn luma(_: &Vm, args: &mut Args) -> SourceResult<Value> {
let Component(luma) = args.expect("gray component")?;
Ok(Value::Color(LumaColor::new(luma).into()))
}
/// Create an RGB(A) color.
pub fn rgb(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn rgb(_: &Vm, args: &mut Args) -> SourceResult<Value> {
Ok(Value::Color(if let Some(string) = args.find::<Spanned<EcoString>>()? {
match RgbaColor::from_str(&string.v) {
Ok(color) => color.into(),
@ -25,7 +25,7 @@ pub fn rgb(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
}
/// Create a CMYK color.
pub fn cmyk(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn cmyk(_: &Vm, args: &mut Args) -> SourceResult<Value> {
let RatioComponent(c) = args.expect("cyan component")?;
let RatioComponent(m) = args.expect("magenta component")?;
let RatioComponent(y) = args.expect("yellow component")?;

View File

@ -5,12 +5,12 @@ use typst::diag::{format_xml_like_error, FileError};
use crate::prelude::*;
/// Read structured data from a CSV file.
pub fn csv(vm: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn csv(vm: &Vm, args: &mut Args) -> SourceResult<Value> {
let Spanned { v: path, span } =
args.expect::<Spanned<EcoString>>("path to csv file")?;
let path = vm.locate(&path).at(span)?;
let data = vm.world.file(&path).at(span)?;
let data = vm.world().file(&path).at(span)?;
let mut builder = csv::ReaderBuilder::new();
builder.has_headers(false);
@ -45,12 +45,12 @@ fn format_csv_error(error: csv::Error) -> String {
}
/// Read structured data from a JSON file.
pub fn json(vm: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn json(vm: &Vm, args: &mut Args) -> SourceResult<Value> {
let Spanned { v: path, span } =
args.expect::<Spanned<EcoString>>("path to json file")?;
let path = vm.locate(&path).at(span)?;
let data = vm.world.file(&path).at(span)?;
let data = vm.world().file(&path).at(span)?;
let value: serde_json::Value =
serde_json::from_slice(&data).map_err(format_json_error).at(span)?;
@ -85,12 +85,12 @@ fn format_json_error(error: serde_json::Error) -> String {
}
/// Read structured data from an XML file.
pub fn xml(vm: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn xml(vm: &Vm, args: &mut Args) -> SourceResult<Value> {
let Spanned { v: path, span } =
args.expect::<Spanned<EcoString>>("path to xml file")?;
let path = vm.locate(&path).at(span)?;
let data = vm.world.file(&path).at(span)?;
let data = vm.world().file(&path).at(span)?;
let text = std::str::from_utf8(&data).map_err(FileError::from).at(span)?;
let document = roxmltree::Document::parse(text).map_err(format_xml_error).at(span)?;

View File

@ -17,12 +17,12 @@ use typst::syntax::Source;
use crate::prelude::*;
/// The name of a value's type.
pub fn type_(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn type_(_: &Vm, args: &mut Args) -> SourceResult<Value> {
Ok(args.expect::<Value>("value")?.type_name().into())
}
/// Ensure that a condition is fulfilled.
pub fn assert(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn assert(_: &Vm, args: &mut Args) -> SourceResult<Value> {
let Spanned { v, span } = args.expect::<Spanned<bool>>("condition")?;
if !v {
bail!(span, "assertion failed");
@ -31,10 +31,10 @@ pub fn assert(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
}
/// Evaluate a string as Typst markup.
pub fn eval(vm: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn eval(vm: &Vm, args: &mut Args) -> SourceResult<Value> {
let Spanned { v: text, span } = args.expect::<Spanned<String>>("source")?;
let source = Source::synthesized(text, span);
let route = Route::default();
let module = model::eval(vm.world, route.track(), &source)?;
let module = model::eval(vm.world(), route.track(), &source)?;
Ok(Value::Content(module.content))
}

View File

@ -3,12 +3,12 @@ use typst::model::Regex;
use crate::prelude::*;
/// The string representation of a value.
pub fn repr(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn repr(_: &Vm, args: &mut Args) -> SourceResult<Value> {
Ok(args.expect::<Value>("value")?.repr().into())
}
/// Convert a value to a string.
pub fn str(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn str(_: &Vm, args: &mut Args) -> SourceResult<Value> {
let Spanned { v, span } = args.expect("value")?;
Ok(Value::Str(match v {
Value::Int(v) => format_str!("{}", v),
@ -19,29 +19,29 @@ pub fn str(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
}
/// Create blind text.
pub fn lorem(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn lorem(_: &Vm, args: &mut Args) -> SourceResult<Value> {
let words: usize = args.expect("number of words")?;
Ok(Value::Str(lipsum::lipsum(words).into()))
}
/// Create a regular expression.
pub fn regex(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn regex(_: &Vm, args: &mut Args) -> SourceResult<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 Vm, args: &mut Args) -> SourceResult<Value> {
pub fn letter(_: &Vm, args: &mut Args) -> SourceResult<Value> {
numbered(Numbering::Letter, args)
}
/// Converts an integer into a roman numeral.
pub fn roman(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn roman(_: &Vm, args: &mut Args) -> SourceResult<Value> {
numbered(Numbering::Roman, args)
}
/// Convert a number into a symbol.
pub fn symbol(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn symbol(_: &Vm, args: &mut Args) -> SourceResult<Value> {
numbered(Numbering::Symbol, args)
}

View File

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

View File

@ -14,12 +14,12 @@ impl ImageNode {
/// How the image should adjust itself to a given area.
pub const FIT: ImageFit = ImageFit::Cover;
fn construct(vm: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(vm: &Vm, args: &mut Args) -> SourceResult<Content> {
let Spanned { v: path, span } =
args.expect::<Spanned<EcoString>>("path to image file")?;
let full = vm.locate(&path).at(span)?;
let buffer = vm.world.file(&full).at(span)?;
let buffer = vm.world().file(&full).at(span)?;
let ext = full.extension().and_then(OsStr::to_str).unwrap_or_default();
let format = match ext.to_lowercase().as_str() {
"png" => ImageFormat::Raster(RasterFormat::Png),

View File

@ -15,7 +15,7 @@ impl LineNode {
#[property(resolve, fold)]
pub const STROKE: PartialStroke = PartialStroke::default();
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let origin = args.named("origin")?.unwrap_or_default();
let delta = match args.named::<Axes<Rel<Length>>>("to")? {

View File

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

View File

@ -12,7 +12,7 @@ pub struct AlignNode {
#[node(LayoutBlock)]
impl AlignNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let aligns: Axes<Option<GenAlign>> = args.find()?.unwrap_or_default();
let body: Content = args.expect("body")?;

View File

@ -17,7 +17,7 @@ impl ColumnsNode {
#[property(resolve)]
pub const GUTTER: Rel<Length> = Ratio::new(0.04).into();
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
Ok(Self {
columns: args.expect("column count")?,
child: args.expect("body")?,
@ -106,7 +106,7 @@ pub struct ColbreakNode {
#[node(Behave)]
impl ColbreakNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let weak = args.named("weak")?.unwrap_or(false);
Ok(Self { weak }.pack())
}

View File

@ -12,7 +12,7 @@ pub struct BoxNode {
#[node(LayoutInline)]
impl BoxNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let width = args.named("width")?;
let height = args.named("height")?;
let body = args.eat::<Content>()?.unwrap_or_default();
@ -70,7 +70,7 @@ impl BlockNode {
#[property(skip)]
pub const BELOW: VNode = VNode::block_spacing(Em::new(1.2).into());
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
Ok(Self(args.eat()?.unwrap_or_default()).pack())
}

View File

@ -15,7 +15,7 @@ pub struct GridNode {
#[node(LayoutBlock)]
impl GridNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let TrackSizings(columns) = args.named("columns")?.unwrap_or_default();
let TrackSizings(rows) = args.named("rows")?.unwrap_or_default();
let TrackSizings(base_gutter) = args.named("gutter")?.unwrap_or_default();

View File

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

View File

@ -41,7 +41,7 @@ impl PageNode {
#[property(referenced)]
pub const FOREGROUND: Marginal = Marginal::None;
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
Ok(Self(args.expect("body")?).pack())
}
@ -150,7 +150,7 @@ pub struct PagebreakNode {
#[node]
impl PagebreakNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let weak = args.named("weak")?.unwrap_or(false);
Ok(Self { weak }.pack())
}

View File

@ -7,7 +7,7 @@ pub struct PlaceNode(pub Content);
#[node(LayoutBlock, Behave)]
impl PlaceNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let aligns = args.find()?.unwrap_or(Axes::with_x(Some(GenAlign::Start)));
let dx = args.named("dx")?.unwrap_or_default();
let dy = args.named("dy")?.unwrap_or_default();

View File

@ -13,7 +13,7 @@ pub struct HNode {
#[node(Behave)]
impl HNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let amount = args.expect("spacing")?;
let weak = args.named("weak")?.unwrap_or(false);
Ok(Self { amount, weak }.pack())
@ -60,7 +60,7 @@ pub struct VNode {
#[node(Behave)]
impl VNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let amount = args.expect("spacing")?;
let node = if args.named("weak")?.unwrap_or(false) {
Self::weak(amount)

View File

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

View File

@ -13,7 +13,7 @@ pub struct MoveNode {
#[node(LayoutInline)]
impl MoveNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let dx = args.named("dx")?.unwrap_or_default();
let dy = args.named("dy")?.unwrap_or_default();
Ok(Self {
@ -60,7 +60,7 @@ impl<const T: TransformKind> TransformNode<T> {
#[property(resolve)]
pub const ORIGIN: Axes<Option<GenAlign>> = Axes::default();
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let transform = match T {
ROTATE => {
let angle = args.named_or_find("angle")?.unwrap_or_default();

View File

@ -16,7 +16,7 @@ pub struct HeadingNode {
#[node(Show, Finalize)]
impl HeadingNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
Ok(Self {
body: args.expect("body")?,
level: args.named("level")?.unwrap_or(NonZeroUsize::new(1).unwrap()),

View File

@ -38,7 +38,7 @@ impl<const L: ListKind> ListNode<L> {
/// The spacing between the items of a wide (non-tight) list.
pub const SPACING: Smart<Spacing> = Smart::Auto;
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let items = match L {
LIST => args
.all()?

View File

@ -7,7 +7,7 @@ pub struct RefNode(pub EcoString);
#[node(Show)]
impl RefNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
Ok(Self(args.expect("target")?).pack())
}

View File

@ -23,7 +23,7 @@ impl TableNode {
/// How much to pad the cells's content.
pub const PADDING: Rel<Length> = Abs::pt(5.0).into();
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let TrackSizings(columns) = args.named("columns")?.unwrap_or_default();
let TrackSizings(rows) = args.named("rows")?.unwrap_or_default();
let TrackSizings(base_gutter) = args.named("gutter")?.unwrap_or_default();

View File

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

View File

@ -29,7 +29,7 @@ impl LinkNode {
#[property(skip, referenced)]
pub(crate) const DEST: Option<Destination> = None;
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let dest = args.expect::<Destination>("destination")?;
Ok(match dest {
Destination::Url(url) => match args.eat()? {

View File

@ -128,7 +128,7 @@ impl TextNode {
#[property(skip, fold)]
const DECO: Decoration = vec![];
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<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.
@ -416,7 +416,7 @@ pub struct SpaceNode;
#[node(Unlabellable, Behave)]
impl SpaceNode {
fn construct(_: &mut Vm, _: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, _: &mut Args) -> SourceResult<Content> {
Ok(Self.pack())
}
}
@ -437,7 +437,7 @@ pub struct LinebreakNode {
#[node(Behave)]
impl LinebreakNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let justify = args.named("justify")?.unwrap_or(false);
Ok(Self { justify }.pack())
}
@ -457,19 +457,19 @@ pub struct SmartQuoteNode {
#[node]
impl SmartQuoteNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
let double = args.named("double")?.unwrap_or(true);
Ok(Self { double }.pack())
}
}
/// Convert a string or content to lowercase.
pub fn lower(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn lower(_: &Vm, args: &mut Args) -> SourceResult<Value> {
case(Case::Lower, args)
}
/// Convert a string or content to uppercase.
pub fn upper(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn upper(_: &Vm, args: &mut Args) -> SourceResult<Value> {
case(Case::Upper, args)
}
@ -503,7 +503,7 @@ impl Case {
}
/// Display text in small capitals.
pub fn smallcaps(_: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn smallcaps(_: &Vm, args: &mut Args) -> SourceResult<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(Show)]
impl StrongNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
Ok(Self(args.expect("body")?).pack())
}
@ -538,7 +538,7 @@ pub struct EmphNode(pub Content);
#[node(Show)]
impl EmphNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
Ok(Self(args.expect("body")?).pack())
}

View File

@ -31,7 +31,7 @@ impl ParNode {
/// How to determine line breaks.
pub const LINEBREAKS: Smart<Linebreaks> = Smart::Auto;
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<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.
@ -119,7 +119,7 @@ pub struct ParbreakNode;
#[node(Unlabellable)]
impl ParbreakNode {
fn construct(_: &mut Vm, _: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, _: &mut Args) -> SourceResult<Content> {
Ok(Self.pack())
}
}
@ -132,7 +132,7 @@ pub struct RepeatNode(pub Content);
#[node(LayoutInline)]
impl RepeatNode {
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
Ok(Self(args.expect("body")?).pack())
}
}

View File

@ -25,7 +25,7 @@ impl RawNode {
#[property(referenced)]
pub const LANG: Option<EcoString> = None;
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
Ok(Self {
text: args.expect("text")?,
block: args.named("block")?.unwrap_or(false),

View File

@ -30,7 +30,7 @@ impl<const S: ShiftKind> ShiftNode<S> {
/// The font size for synthetic sub- and superscripts.
pub const SIZE: TextSize = TextSize(Em::new(0.6).into());
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
Ok(Self(args.expect("body")?).pack())
}

View File

@ -284,7 +284,7 @@ fn create_node_construct_func(node: &Node) -> syn::ImplItemMethod {
node.construct.clone().unwrap_or_else(|| {
parse_quote! {
fn construct(
_: &mut ::typst::model::Vm,
_: &::typst::model::Vm,
_: &mut ::typst::model::Args,
) -> ::typst::diag::SourceResult<::typst::model::Content> {
unimplemented!()

View File

@ -128,7 +128,7 @@ impl Array {
}
/// Return the first matching element.
pub fn find(&self, vm: &mut Vm, f: Spanned<Func>) -> SourceResult<Option<Value>> {
pub fn find(&self, vm: &Vm, f: Spanned<Func>) -> SourceResult<Option<Value>> {
for item in self.iter() {
let args = Args::new(f.span, [item.clone()]);
if f.v.call(vm, args)?.cast::<bool>().at(f.span)? {
@ -140,7 +140,7 @@ impl Array {
}
/// Return the index of the first matching element.
pub fn position(&self, vm: &mut Vm, f: Spanned<Func>) -> SourceResult<Option<i64>> {
pub fn position(&self, vm: &Vm, f: Spanned<Func>) -> SourceResult<Option<i64>> {
for (i, item) in self.iter().enumerate() {
let args = Args::new(f.span, [item.clone()]);
if f.v.call(vm, args)?.cast::<bool>().at(f.span)? {
@ -153,7 +153,7 @@ impl Array {
/// Return a new array with only those elements for which the function
/// returns true.
pub fn filter(&self, vm: &mut Vm, f: Spanned<Func>) -> SourceResult<Self> {
pub fn filter(&self, vm: &Vm, f: Spanned<Func>) -> SourceResult<Self> {
let mut kept = vec![];
for item in self.iter() {
let args = Args::new(f.span, [item.clone()]);
@ -165,7 +165,7 @@ impl Array {
}
/// Transform each item in the array with a function.
pub fn map(&self, vm: &mut Vm, f: Spanned<Func>) -> SourceResult<Self> {
pub fn map(&self, vm: &Vm, f: Spanned<Func>) -> SourceResult<Self> {
let enumerate = f.v.argc() == Some(2);
self.iter()
.enumerate()
@ -181,7 +181,7 @@ impl Array {
}
/// Whether any element matches.
pub fn any(&self, vm: &mut Vm, f: Spanned<Func>) -> SourceResult<bool> {
pub fn any(&self, vm: &Vm, f: Spanned<Func>) -> SourceResult<bool> {
for item in self.iter() {
let args = Args::new(f.span, [item.clone()]);
if f.v.call(vm, args)?.cast::<bool>().at(f.span)? {
@ -193,7 +193,7 @@ impl Array {
}
/// Whether all elements match.
pub fn all(&self, vm: &mut Vm, f: Spanned<Func>) -> SourceResult<bool> {
pub fn all(&self, vm: &Vm, f: Spanned<Func>) -> SourceResult<bool> {
for item in self.iter() {
let args = Args::new(f.span, [item.clone()]);
if !f.v.call(vm, args)?.cast::<bool>().at(f.span)? {

View File

@ -362,7 +362,7 @@ pub trait Node: 'static + Capable {
///
/// This is passed only the arguments that remain after execution of the
/// node's set rule.
fn construct(vm: &mut Vm, args: &mut Args) -> SourceResult<Content>
fn construct(vm: &Vm, args: &mut Args) -> SourceResult<Content>
where
Self: Sized;

View File

@ -105,7 +105,7 @@ impl Dict {
}
/// Transform each pair in the array with a function.
pub fn map(&self, vm: &mut Vm, f: Spanned<Func>) -> SourceResult<Array> {
pub fn map(&self, vm: &Vm, f: Spanned<Func>) -> SourceResult<Array> {
self.iter()
.map(|(key, value)| {
let args = Args::new(f.span, [Value::Str(key.clone()), value.clone()]);

View File

@ -1030,7 +1030,7 @@ impl Eval for ast::ModuleInclude {
}
/// Process an import of a module relative to the current location.
fn import(vm: &mut Vm, path: &str, span: Span) -> SourceResult<Module> {
fn import(vm: &Vm, path: &str, span: Span) -> SourceResult<Module> {
// Load the source file.
let full = vm.locate(path).at(span)?;
let id = vm.world.resolve(&full).at(span)?;

View File

@ -32,7 +32,7 @@ impl Func {
/// Create a new function from a native rust function.
pub fn from_fn(
name: &'static str,
func: fn(&mut Vm, &mut Args) -> SourceResult<Value>,
func: fn(&Vm, &mut Args) -> SourceResult<Value>,
) -> Self {
Self(Arc::new(Repr::Native(Native { name, func, set: None, node: None })))
}
@ -77,7 +77,7 @@ impl Func {
}
/// Call the function with the given arguments.
pub fn call(&self, vm: &mut Vm, mut args: Args) -> SourceResult<Value> {
pub fn call(&self, vm: &Vm, mut args: Args) -> SourceResult<Value> {
let value = match self.0.as_ref() {
Repr::Native(native) => (native.func)(vm, &mut args)?,
Repr::Closure(closure) => closure.call(vm, &mut args)?,
@ -99,8 +99,8 @@ impl Func {
let route = Route::default();
let id = SourceId::detached();
let scopes = Scopes::new(None);
let mut vm = Vm::new(world, route.track(), id, scopes);
self.call(&mut vm, args)
let vm = Vm::new(world, route.track(), id, scopes);
self.call(&vm, args)
}
/// Apply the given arguments to the function.
@ -160,7 +160,7 @@ struct Native {
/// The name of the function.
pub name: &'static str,
/// The function pointer.
pub func: fn(&mut Vm, &mut Args) -> SourceResult<Value>,
pub func: fn(&Vm, &mut Args) -> SourceResult<Value>,
/// The set rule.
pub set: Option<fn(&mut Args) -> SourceResult<StyleMap>>,
/// The id of the node to customize with this function's show rule.
@ -196,7 +196,7 @@ pub struct Closure {
impl Closure {
/// Call the function in the context with the arguments.
pub fn call(&self, vm: &mut Vm, args: &mut Args) -> SourceResult<Value> {
pub fn call(&self, vm: &Vm, args: &mut Args) -> SourceResult<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);

View File

@ -7,7 +7,7 @@ use crate::util::EcoString;
/// Call a method on a value.
pub fn call(
vm: &mut Vm,
vm: &Vm,
value: Value,
method: &str,
mut args: Args,

View File

@ -78,7 +78,7 @@ impl Scope {
pub fn def_fn(
&mut self,
name: &'static str,
func: fn(&mut Vm, &mut Args) -> SourceResult<Value>,
func: fn(&Vm, &mut Args) -> SourceResult<Value>,
) {
self.define(name, Func::from_fn(name, func));
}

View File

@ -9,19 +9,22 @@ use crate::util::PathExt;
use crate::World;
/// A virtual machine.
///
/// Holds the state needed to evaluate Typst sources. A new virtual machine is
/// created for each module evaluation and function call.
pub struct Vm<'a> {
/// The core context.
pub world: Tracked<'a, dyn World>,
pub(crate) world: Tracked<'a, dyn World>,
/// The route of source ids the VM took to reach its current location.
pub route: Tracked<'a, Route>,
pub(crate) route: Tracked<'a, Route>,
/// The current location.
pub location: SourceId,
pub(crate) location: SourceId,
/// The stack of scopes.
pub scopes: Scopes<'a>,
pub(crate) scopes: Scopes<'a>,
/// A control flow event that is currently happening.
pub flow: Option<Flow>,
pub(crate) flow: Option<Flow>,
/// The language items.
pub items: LangItems,
pub(crate) items: LangItems,
}
impl<'a> Vm<'a> {
@ -42,6 +45,11 @@ impl<'a> Vm<'a> {
}
}
/// Access the underlying world.
pub fn world(&self) -> Tracked<dyn World> {
self.world
}
/// Resolve a user-entered path to be relative to the compilation
/// environment's root.
pub fn locate(&self, path: &str) -> StrResult<PathBuf> {