typst/src/eval/capture.rs

45 lines
1.2 KiB
Rust

use super::*;
use crate::syntax::visit::*;
/// A visitor that replaces all captured variables with their values.
#[derive(Debug)]
pub struct CapturesVisitor<'a> {
external: &'a Scopes<'a>,
internal: Scopes<'a>,
}
impl<'a> CapturesVisitor<'a> {
/// Create a new visitor for the given external scopes.
pub fn new(external: &'a Scopes) -> Self {
Self { external, internal: Scopes::default() }
}
}
impl<'a> Visitor<'a> for CapturesVisitor<'a> {
fn visit_scope_pre(&mut self) {
self.internal.push();
}
fn visit_scope_post(&mut self) {
self.internal.pop();
}
fn visit_def(&mut self, id: &mut Ident) {
self.internal.define(id.as_str(), Value::None);
}
fn visit_expr(&mut self, expr: &'a mut Expr) {
if let Expr::Ident(ident) = expr {
// Find out whether the identifier is not locally defined, but
// captured, and if so, replace it with its value.
if self.internal.get(ident).is_none() {
if let Some(value) = self.external.get(ident) {
*expr = Expr::CapturedValue(value.clone());
}
}
} else {
walk_expr(self, expr);
}
}
}