diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-05-16 19:13:39 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-05-16 20:22:48 +0200 |
| commit | 242b01549a472d4eeca1404b8f63427e23224253 (patch) | |
| tree | 7d44ef801ce857469912a75233a1e7a1603e405e /src/library | |
| parent | a741bd6b83d1e374c8218b5439e26522499cc4ae (diff) | |
Safe `eval` function
Diffstat (limited to 'src/library')
| -rw-r--r-- | src/library/mod.rs | 1 | ||||
| -rw-r--r-- | src/library/utility/mod.rs | 31 |
2 files changed, 32 insertions, 0 deletions
diff --git a/src/library/mod.rs b/src/library/mod.rs index 6a30badf..ac0cbb92 100644 --- a/src/library/mod.rs +++ b/src/library/mod.rs @@ -73,6 +73,7 @@ pub fn new() -> Scope { // Utility. std.def_fn("type", utility::type_); std.def_fn("assert", utility::assert); + std.def_fn("eval", utility::eval); std.def_fn("int", utility::int); std.def_fn("float", utility::float); std.def_fn("abs", utility::abs); diff --git a/src/library/utility/mod.rs b/src/library/utility/mod.rs index 13220242..355315e4 100644 --- a/src/library/utility/mod.rs +++ b/src/library/utility/mod.rs @@ -8,7 +8,11 @@ pub use color::*; pub use math::*; pub use string::*; +use std::mem; + +use crate::eval::{Eval, Scopes}; use crate::library::prelude::*; +use crate::source::SourceFile; /// The name of a value's type. pub fn type_(_: &mut Context, args: &mut Args) -> TypResult<Value> { @@ -23,3 +27,30 @@ pub fn assert(_: &mut Context, args: &mut Args) -> TypResult<Value> { } Ok(Value::None) } + +/// Evaluate a string as Typst markup. +pub fn eval(ctx: &mut Context, args: &mut Args) -> TypResult<Value> { + let Spanned { v: src, span } = args.expect::<Spanned<String>>("source")?; + + // Parse the source and set a synthetic span for all nodes. + let mut source = SourceFile::detached(src); + source.synthesize(span); + let ast = source.ast()?; + + // Save the old context, then detach it. + let prev_flow = ctx.flow.take(); + let prev_route = mem::take(&mut ctx.route); + + // Evaluate the source. + let std = ctx.std.clone(); + let mut scp = Scopes::new(Some(&std)); + let result = ast.eval(ctx, &mut scp); + + // Restore the old context and handle control flow. + ctx.route = prev_route; + if let Some(flow) = mem::replace(&mut ctx.flow, prev_flow) { + return Err(flow.forbidden()); + } + + Ok(Value::Content(result?)) +} |
