typst/src/exec/mod.rs

118 lines
3.2 KiB
Rust

//! Execution of syntax trees.
mod context;
mod state;
pub use context::*;
pub use state::*;
use std::rc::Rc;
use crate::diag::Pass;
use crate::env::Env;
use crate::eval::{NodeMap, TemplateFunc, TemplateNode, TemplateValue, Value};
use crate::layout;
use crate::pretty::pretty;
use crate::syntax::*;
/// Execute a syntax tree to produce a layout tree.
///
/// The `map` shall be a node map computed for this tree with
/// [`eval`](crate::eval::eval). Note that `tree` must be the _exact_ same tree
/// as used for evaluation (no cloned version), because the node map depends on
/// the pointers being stable.
///
/// The `state` is the base state that may be updated over the course of
/// execution.
pub fn exec(
env: &mut Env,
tree: &Tree,
map: &NodeMap,
state: State,
) -> Pass<layout::Tree> {
let mut ctx = ExecContext::new(env, state);
tree.exec_with_map(&mut ctx, &map);
ctx.finish()
}
/// Execute a node.
///
/// This manipulates active styling and document state and produces layout
/// nodes. Because syntax nodes and layout nodes do not correspond one-to-one,
/// constructed layout nodes are pushed into the context instead of returned.
/// The context takes care of reshaping the nodes into the correct tree
/// structure.
pub trait Exec {
/// Execute the node.
fn exec(&self, ctx: &mut ExecContext);
}
/// Execute a node with a node map that applies to it.
pub trait ExecWithMap {
/// Execute the node.
fn exec_with_map(&self, ctx: &mut ExecContext, map: &NodeMap);
}
impl ExecWithMap for Tree {
fn exec_with_map(&self, ctx: &mut ExecContext, map: &NodeMap) {
for node in self {
node.exec_with_map(ctx, map);
}
}
}
impl ExecWithMap for Node {
fn exec_with_map(&self, ctx: &mut ExecContext, map: &NodeMap) {
match self {
Node::Text(text) => ctx.push_text(text.clone()),
Node::Space => ctx.push_word_space(),
_ => map[&(self as *const _)].exec(ctx),
}
}
}
impl Exec for Value {
fn exec(&self, ctx: &mut ExecContext) {
match self {
Value::None => {}
Value::Int(v) => ctx.push_text(pretty(v)),
Value::Float(v) => ctx.push_text(pretty(v)),
Value::Str(v) => ctx.push_text(v.clone()),
Value::Template(v) => v.exec(ctx),
Value::Error => {}
other => {
// For values which can't be shown "naturally", we print
// the representation in monospace.
let prev = Rc::clone(&ctx.state.font.families);
ctx.set_monospace();
ctx.push_text(pretty(other));
ctx.state.font.families = prev;
}
}
}
}
impl Exec for TemplateValue {
fn exec(&self, ctx: &mut ExecContext) {
for node in self {
node.exec(ctx);
}
}
}
impl Exec for TemplateNode {
fn exec(&self, ctx: &mut ExecContext) {
match self {
Self::Tree { tree, map } => tree.exec_with_map(ctx, &map),
Self::Str(v) => ctx.push_text(v.clone()),
Self::Func(v) => v.exec(ctx),
}
}
}
impl Exec for TemplateFunc {
fn exec(&self, ctx: &mut ExecContext) {
self(ctx);
}
}