summaryrefslogtreecommitdiffstats
path: root/crates
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2024-05-03 20:42:06 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2024-05-03 20:42:06 +0200
commit9b83e404faffeff5eba6a2b6d9e3335973c2cb18 (patch)
treec4cceca92b66175f191b46f213dbbb56d1e43fef /crates
parent09aba6fa33d9cd6918a73462aa23e13919326dc7 (diff)
downloadrebel-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.rs51
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"))
}
}