45 lines
1.2 KiB
Rust
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);
|
|
}
|
|
}
|
|
}
|