typst/src/exec/mod.rs
2021-06-29 13:49:50 +02:00

178 lines
5.1 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::eval::{ExprMap, TemplateFunc, TemplateNode, TemplateValue, Value};
use crate::geom::{Dir, Gen};
use crate::layout::{self, StackChild, StackNode};
use crate::pretty::pretty;
use crate::syntax;
/// Execute a template to produce a layout tree.
pub fn exec(template: &TemplateValue, state: State) -> Pass<layout::Tree> {
let mut ctx = ExecContext::new(state);
template.exec(&mut ctx);
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 an expression map that applies to it.
pub trait ExecWithMap {
/// Execute the node.
fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap);
}
impl ExecWithMap for syntax::Tree {
fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) {
for node in self {
node.exec_with_map(ctx, map);
}
}
}
impl ExecWithMap for syntax::Node {
fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) {
match self {
Self::Text(text) => ctx.push_text(text),
Self::Space => ctx.push_word_space(),
Self::Linebreak(_) => ctx.linebreak(),
Self::Parbreak(_) => ctx.parbreak(),
Self::Strong(_) => ctx.state.font_mut().strong ^= true,
Self::Emph(_) => ctx.state.font_mut().emph ^= true,
Self::Raw(n) => n.exec(ctx),
Self::Heading(n) => n.exec_with_map(ctx, map),
Self::List(n) => n.exec_with_map(ctx, map),
Self::Enum(n) => n.exec_with_map(ctx, map),
Self::Expr(n) => map[&(n as *const _)].exec(ctx),
}
}
}
impl Exec for syntax::RawNode {
fn exec(&self, ctx: &mut ExecContext) {
if self.block {
ctx.parbreak();
}
let snapshot = Rc::clone(&ctx.state.font);
ctx.set_monospace();
ctx.push_text(&self.text);
ctx.state.font = snapshot;
if self.block {
ctx.parbreak();
}
}
}
impl ExecWithMap for syntax::HeadingNode {
fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) {
ctx.parbreak();
let snapshot = ctx.state.clone();
let font = ctx.state.font_mut();
let upscale = 1.6 - 0.1 * self.level as f64;
font.size *= upscale;
font.strong = true;
self.body.exec_with_map(ctx, map);
ctx.state = snapshot;
ctx.parbreak();
}
}
impl ExecWithMap for syntax::ListItem {
fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) {
exec_item(ctx, "".to_string(), &self.body, map);
}
}
impl ExecWithMap for syntax::EnumItem {
fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) {
let label = self.number.unwrap_or(1).to_string() + ".";
exec_item(ctx, label, &self.body, map);
}
}
fn exec_item(ctx: &mut ExecContext, label: String, body: &syntax::Tree, map: &ExprMap) {
let label = ctx.exec_stack(|ctx| ctx.push_text(label));
let body = ctx.exec_tree_stack(body, map);
let stack = StackNode {
dirs: Gen::new(Dir::TTB, ctx.state.lang.dir),
aspect: None,
children: vec![
StackChild::Any(label.into(), Gen::default()),
StackChild::Spacing(ctx.state.font.size / 2.0),
StackChild::Any(body.into(), Gen::default()),
],
};
ctx.push_into_stack(stack);
}
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),
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_mut().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),
Self::Func(v) => v.exec(ctx),
}
}
}
impl Exec for TemplateFunc {
fn exec(&self, ctx: &mut ExecContext) {
let snapshot = ctx.state.clone();
self(ctx);
ctx.state = snapshot;
}
}