Support different modes for eval

This commit is contained in:
Laurenz 2023-07-18 21:18:35 +02:00
parent f5953887c9
commit f52c39c388
2 changed files with 43 additions and 8 deletions

View File

@ -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<String>,
/// 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<Value> {
let Spanned { v: text, span } = source;
typst::eval::eval_string(vm.world(), &text, span)
typst::eval::eval_string(vm.world(), &text, mode, span)
}

View File

@ -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<dyn World + '_>,
code: &str,
string: &str,
mode: EvalMode,
span: Span,
) -> SourceResult<Value> {
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::<ast::Code>().unwrap();
let result = code.eval(&mut vm);
let result = match mode {
EvalMode::Code => root.cast::<ast::Code>().unwrap().eval(&mut vm),
EvalMode::Markup => {
root.cast::<ast::Markup>().unwrap().eval(&mut vm).map(Value::Content)
}
EvalMode::Math => {
root.cast::<ast::Math>().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