diff --git a/crates/typst-library/src/compute/foundations.rs b/crates/typst-library/src/compute/foundations.rs index f83d71a08..ecac3ffad 100644 --- a/crates/typst-library/src/compute/foundations.rs +++ b/crates/typst-library/src/compute/foundations.rs @@ -1,3 +1,5 @@ +use typst::eval::EvalMode; + use crate::prelude::*; /// Determines the type of a value. @@ -196,7 +198,7 @@ pub fn assert_ne( /// ```example /// #eval("1 + 1") \ /// #eval("(1, 2, 3, 4)").len() \ -/// #eval("[*Strong text*]") +/// #eval("*Markup!*", mode: "markup") \ /// ``` /// /// Display: Evaluate @@ -207,9 +209,18 @@ pub fn eval( /// /// The code in the string cannot interact with the file system. source: Spanned, + /// The syntactical mode in which the string is parsed. + /// + /// ```example + /// #eval("= Heading", mode: "markup") + /// #eval("1_2^3", mode: "math") + /// ``` + #[named] + #[default(EvalMode::Code)] + mode: EvalMode, /// The virtual machine. vm: &mut Vm, ) -> SourceResult { let Spanned { v: text, span } = source; - typst::eval::eval_string(vm.world(), &text, span) + typst::eval::eval_string(vm.world(), &text, mode, span) } diff --git a/crates/typst/src/eval/mod.rs b/crates/typst/src/eval/mod.rs index 33c5f1a2f..6f684a7bd 100644 --- a/crates/typst/src/eval/mod.rs +++ b/crates/typst/src/eval/mod.rs @@ -74,8 +74,8 @@ use crate::model::{ }; use crate::syntax::ast::{self, AstNode}; use crate::syntax::{ - parse_code, FileId, PackageSpec, PackageVersion, Source, Span, Spanned, SyntaxKind, - SyntaxNode, + parse, parse_code, parse_math, FileId, PackageSpec, PackageVersion, Source, Span, + Spanned, SyntaxKind, SyntaxNode, }; use crate::World; @@ -144,10 +144,16 @@ pub fn eval( #[comemo::memoize] pub fn eval_string( world: Tracked, - code: &str, + string: &str, + mode: EvalMode, span: Span, ) -> SourceResult { - let mut root = parse_code(code); + let mut root = match mode { + EvalMode::Code => parse_code(string), + EvalMode::Markup => parse(string), + EvalMode::Math => parse_math(string), + }; + root.synthesize(span); let errors = root.errors(); @@ -175,8 +181,15 @@ pub fn eval_string( let mut vm = Vm::new(vt, route.track(), id, scopes); // Evaluate the code. - let code = root.cast::().unwrap(); - let result = code.eval(&mut vm); + let result = match mode { + EvalMode::Code => root.cast::().unwrap().eval(&mut vm), + EvalMode::Markup => { + root.cast::().unwrap().eval(&mut vm).map(Value::Content) + } + EvalMode::Math => { + root.cast::().unwrap().eval(&mut vm).map(Value::Content) + } + }; // Handle control flow. if let Some(flow) = vm.flow { @@ -186,6 +199,17 @@ pub fn eval_string( result } +/// In which mode to evaluate a string. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)] +pub enum EvalMode { + /// Evaluate as code, as after a hashtag. + Code, + /// Evaluate as markup, like in a Typst file. + Markup, + /// Evaluate as math, as in an equation. + Math, +} + /// A virtual machine. /// /// Holds the state needed to [evaluate](eval) Typst sources. A new