diff options
author | Matthias Schiffer <mschiffer@universe-factory.net> | 2024-05-03 20:42:06 +0200 |
---|---|---|
committer | Matthias Schiffer <mschiffer@universe-factory.net> | 2024-05-03 20:42:06 +0200 |
commit | 9b83e404faffeff5eba6a2b6d9e3335973c2cb18 (patch) | |
tree | c4cceca92b66175f191b46f213dbbb56d1e43fef /crates | |
parent | 09aba6fa33d9cd6918a73462aa23e13919326dc7 (diff) | |
download | rebel-9b83e404faffeff5eba6a2b6d9e3335973c2cb18.tar rebel-9b83e404faffeff5eba6a2b6d9e3335973c2cb18.zip |
rebel-lang: scope: add support for parent scopes
When looking for a binding, a scope and all its ancestors are scanned.
Diffstat (limited to 'crates')
-rw-r--r-- | crates/rebel-lang/src/scope.rs | 51 |
1 files changed, 35 insertions, 16 deletions
diff --git a/crates/rebel-lang/src/scope.rs b/crates/rebel-lang/src/scope.rs index 6a7eb23..439a4a2 100644 --- a/crates/rebel-lang/src/scope.rs +++ b/crates/rebel-lang/src/scope.rs @@ -14,6 +14,7 @@ pub type MethodMap = HashMap<TypeFamily, HashMap<&'static str, Func>>; pub struct Scope<T> { pub vars: Module<T>, pub types: Module<Type>, + pub parent: Option<Box<Scope<T>>>, } impl<T> Default for Scope<T> { @@ -26,7 +27,11 @@ impl<T> Default for Scope<T> { types.insert("int", Type::Int); types.insert("str", Type::Str); - Self { vars, types } + Self { + vars, + types, + parent: None, + } } } @@ -36,37 +41,51 @@ impl<T> Scope<T> { return Err(Error::lookup("invalid path")); } - if path.components == [ast::Ident { name: "_" }] { - return Err(Error::lookup("_ in evaluated expression")); + let mut lookup_scope = Some(self); + while let Some(scope) = lookup_scope { + if let Some(var) = scope.vars.lookup(&path.components) { + return Ok(var); + } + lookup_scope = scope.parent.as_deref(); } - self.vars - .lookup(&path.components) - .ok_or(Error::lookup("undefined variable")) + Err(Error::lookup("undefined variable")) } - pub fn lookup_type(&self, path: &ast::Path) -> Result<&Type> { + pub fn lookup_var_mut(&mut self, path: &ast::Path) -> Result<&mut T> { if path.root != ast::PathRoot::Relative { return Err(Error::lookup("invalid path")); } - if path.components == [ast::Ident { name: "_" }] { - return Ok(&Type::Free); + let mut lookup_scope = Some(self); + while let Some(scope) = lookup_scope { + if let Some(var) = scope.vars.lookup_mut(&path.components) { + return Ok(var); + } + lookup_scope = scope.parent.as_deref_mut(); } - self.types - .lookup(&path.components) - .ok_or(Error::lookup("undefined type")) + Err(Error::lookup("undefined variable")) } - pub fn lookup_var_mut(&mut self, path: &ast::Path) -> Result<&mut T> { + pub fn lookup_type(&self, path: &ast::Path) -> Result<&Type> { if path.root != ast::PathRoot::Relative { return Err(Error::lookup("invalid path")); } - self.vars - .lookup_mut(&path.components) - .ok_or(Error::lookup("undefined variable")) + if path.components == [ast::Ident { name: "_" }] { + return Ok(&Type::Free); + } + + let mut lookup_scope = Some(self); + while let Some(scope) = lookup_scope { + if let Some(typ) = scope.types.lookup(&path.components) { + return Ok(typ); + } + lookup_scope = scope.parent.as_deref(); + } + + Err(Error::lookup("undefined type")) } } |