summaryrefslogtreecommitdiff
path: root/src/model/eval.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/model/eval.rs')
-rw-r--r--src/model/eval.rs38
1 files changed, 37 insertions, 1 deletions
diff --git a/src/model/eval.rs b/src/model/eval.rs
index 1fbf4125..6e118f8a 100644
--- a/src/model/eval.rs
+++ b/src/model/eval.rs
@@ -16,7 +16,9 @@ use crate::diag::{
bail, error, At, SourceError, SourceResult, StrResult, Trace, Tracepoint,
};
use crate::syntax::ast::AstNode;
-use crate::syntax::{ast, Source, SourceId, Span, Spanned, SyntaxKind, SyntaxNode};
+use crate::syntax::{
+ ast, parse_code, Source, SourceId, Span, Spanned, SyntaxKind, SyntaxNode,
+};
use crate::util::PathExt;
use crate::World;
@@ -63,6 +65,40 @@ pub fn eval(
Ok(Module::new(name).with_scope(vm.scopes.top).with_content(result?))
}
+/// Evaluate a string as code and return the resulting value.
+///
+/// Everything in the output is associated with the given `span`.
+#[comemo::memoize]
+pub fn eval_code_str(
+ world: Tracked<dyn World>,
+ text: &str,
+ span: Span,
+) -> SourceResult<Value> {
+ let mut root = parse_code(text);
+ root.synthesize(span);
+
+ let errors = root.errors();
+ if !errors.is_empty() {
+ return Err(Box::new(errors));
+ }
+
+ let id = SourceId::detached();
+ let library = world.library();
+ let scopes = Scopes::new(Some(library));
+ let route = Route::default();
+ let mut tracer = Tracer::default();
+ let mut vm = Vm::new(world, route.track(), tracer.track_mut(), id, scopes, 0);
+ let code = root.cast::<ast::Code>().unwrap();
+ let result = code.eval(&mut vm);
+
+ // Handle control flow.
+ if let Some(flow) = vm.flow {
+ bail!(flow.forbidden());
+ }
+
+ result
+}
+
/// A virtual machine.
///
/// Holds the state needed to [evaluate](eval) Typst sources. A new