diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-01-30 10:24:51 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-01-30 10:24:51 +0100 |
| commit | ac24075469f171fe83a976b9a97b9b1ea078a7e3 (patch) | |
| tree | e89155de4670efa636b71f4a9a5e5f422c76214d /src/eval/capture.rs | |
| parent | 2036663ed25b5885a87eb3a80caec3fa2e258d77 (diff) | |
Moves captures visitor into separate file 🚚
Diffstat (limited to 'src/eval/capture.rs')
| -rw-r--r-- | src/eval/capture.rs | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/src/eval/capture.rs b/src/eval/capture.rs new file mode 100644 index 00000000..b7052c70 --- /dev/null +++ b/src/eval/capture.rs @@ -0,0 +1,44 @@ +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); + } + } +} |
