mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
Let eval
take code instead of markup
This commit is contained in:
parent
5233b1c50a
commit
17e9805b34
@ -1,9 +1,5 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use comemo::Track;
|
|
||||||
use typst::model;
|
|
||||||
use typst::syntax::Source;
|
|
||||||
|
|
||||||
/// # Type
|
/// # Type
|
||||||
/// Determine a value's type.
|
/// Determine a value's type.
|
||||||
///
|
///
|
||||||
@ -92,32 +88,29 @@ pub fn assert(args: &mut Args) -> SourceResult<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// # Evaluate
|
/// # Evaluate
|
||||||
/// Evaluate a string as Typst markup.
|
/// Evaluate a string as Typst code.
|
||||||
///
|
///
|
||||||
/// You shouldn't typically need this function, but it is there if you do.
|
/// This function should only be used as a last resort.
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```example
|
/// ```example
|
||||||
/// #let markup = "= Heading\n _Emphasis_"
|
/// #eval("1 + 2") \
|
||||||
/// #eval(markup)
|
/// #eval("[*Strong text*]") \
|
||||||
|
/// #eval("(1, 2, 3)").len()
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ## Parameters
|
/// ## Parameters
|
||||||
/// - source: `String` (positional, required)
|
/// - source: `String` (positional, required)
|
||||||
/// A string of Typst markup to evaluate.
|
/// A string of Typst code to evaluate.
|
||||||
///
|
///
|
||||||
/// The markup and code in the string cannot interact with the file system.
|
/// The code in the string cannot interact with the file system.
|
||||||
///
|
///
|
||||||
/// - returns: content
|
/// - returns: any
|
||||||
///
|
///
|
||||||
/// ## Category
|
/// ## Category
|
||||||
/// foundations
|
/// foundations
|
||||||
#[func]
|
#[func]
|
||||||
pub fn eval(vm: &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 Spanned { v: text, span } = args.expect::<Spanned<String>>("source")?;
|
||||||
let source = Source::synthesized(text, span);
|
typst::model::eval_code_str(vm.world(), &text, span)
|
||||||
let route = model::Route::default();
|
|
||||||
let mut tracer = model::Tracer::default();
|
|
||||||
let module = model::eval(vm.world(), route.track(), tracer.track_mut(), &source)?;
|
|
||||||
Ok(Value::Content(module.content()))
|
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,9 @@ use crate::diag::{
|
|||||||
bail, error, At, SourceError, SourceResult, StrResult, Trace, Tracepoint,
|
bail, error, At, SourceError, SourceResult, StrResult, Trace, Tracepoint,
|
||||||
};
|
};
|
||||||
use crate::syntax::ast::AstNode;
|
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::util::PathExt;
|
||||||
use crate::World;
|
use crate::World;
|
||||||
|
|
||||||
@ -63,6 +65,40 @@ pub fn eval(
|
|||||||
Ok(Module::new(name).with_scope(vm.scopes.top).with_content(result?))
|
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.
|
/// A virtual machine.
|
||||||
///
|
///
|
||||||
/// Holds the state needed to [evaluate](eval) Typst sources. A new
|
/// Holds the state needed to [evaluate](eval) Typst sources. A new
|
||||||
|
@ -175,7 +175,7 @@ impl SyntaxNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set a synthetic span for the node and all its descendants.
|
/// Set a synthetic span for the node and all its descendants.
|
||||||
pub(super) fn synthesize(&mut self, span: Span) {
|
pub(crate) fn synthesize(&mut self, span: Span) {
|
||||||
match &mut self.0 {
|
match &mut self.0 {
|
||||||
Repr::Leaf(leaf) => leaf.span = span,
|
Repr::Leaf(leaf) => leaf.span = span,
|
||||||
Repr::Inner(inner) => Arc::make_mut(inner).synthesize(span),
|
Repr::Inner(inner) => Arc::make_mut(inner).synthesize(span),
|
||||||
|
@ -27,14 +27,14 @@
|
|||||||
#test(type(10 / 3), "float")
|
#test(type(10 / 3), "float")
|
||||||
|
|
||||||
---
|
---
|
||||||
#eval("_Hello" + " World!_")
|
#eval("[_Hello" + " World!_]")
|
||||||
|
|
||||||
---
|
---
|
||||||
// Error: 7-13 expected identifier
|
// Error: 7-12 expected identifier
|
||||||
#eval("#let")
|
#eval("let")
|
||||||
|
|
||||||
---
|
---
|
||||||
#show raw: it => text("IBM Plex Sans", eval(it.text))
|
#show raw: it => text("IBM Plex Sans", eval("[" + it.text + "]"))
|
||||||
|
|
||||||
Interacting
|
Interacting
|
||||||
```
|
```
|
||||||
@ -43,28 +43,28 @@ Blue #move(dy: -0.15em)[🌊]
|
|||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
// Error: 7-18 cannot continue outside of loop
|
// Error: 7-17 cannot continue outside of loop
|
||||||
#eval("#continue")
|
#eval("continue")
|
||||||
|
|
||||||
---
|
---
|
||||||
// Error: 7-33 cannot access file system from here
|
// Error: 7-32 cannot access file system from here
|
||||||
#eval("#include \"../coma.typ\"")
|
#eval("include \"../coma.typ\"")
|
||||||
|
|
||||||
---
|
---
|
||||||
// Error: 7-31 cannot access file system from here
|
// Error: 7-30 cannot access file system from here
|
||||||
#eval("#image(\"/tiger.jpg\")")
|
#eval("image(\"/tiger.jpg\")")
|
||||||
|
|
||||||
---
|
---
|
||||||
// Error: 23-30 cannot access file system from here
|
// Error: 23-30 cannot access file system from here
|
||||||
#show raw: it => eval(it.text)
|
#show raw: it => eval(it.text)
|
||||||
|
|
||||||
```
|
```
|
||||||
#image("/tiger.jpg")
|
image("/tiger.jpg")
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
// Error: 23-30 cannot access file system from here
|
// Error: 23-42 cannot access file system from here
|
||||||
#show raw: it => eval(it.text)
|
#show raw: it => eval("[" + it.text + "]")
|
||||||
|
|
||||||
```
|
```
|
||||||
#show emph: _ => image("/giraffe.jpg")
|
#show emph: _ => image("/giraffe.jpg")
|
||||||
@ -72,5 +72,5 @@ _No relative giraffe!_
|
|||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
// Error: 7-15 expected comma
|
// Error: 7-12 expected semicolon or line break
|
||||||
#eval("#(1 2)")
|
#eval("1 2")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user