Resolver - Class definitions create a scope that contains "this"
This commit is contained in:
parent
e46b399399
commit
a2986a1342
1 changed files with 36 additions and 11 deletions
|
@ -1,7 +1,7 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{ExprNode, ProgramNode, StmtNode, VariableExpr},
|
ast::{ExprNode, FunDecl, ProgramNode, StmtNode, VariableExpr},
|
||||||
errors::{ErrorKind, SloxError, SloxResult},
|
errors::{ErrorKind, SloxError, SloxResult},
|
||||||
tokens::Token,
|
tokens::Token,
|
||||||
};
|
};
|
||||||
|
@ -38,12 +38,13 @@ enum SymKind {
|
||||||
Variable,
|
Variable,
|
||||||
Function,
|
Function,
|
||||||
Class,
|
Class,
|
||||||
|
This,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// General information about a symbol.
|
/// General information about a symbol.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct SymInfo<'a> {
|
struct SymInfo<'a> {
|
||||||
decl: &'a Token,
|
decl: Option<&'a Token>,
|
||||||
kind: SymKind,
|
kind: SymKind,
|
||||||
state: SymState,
|
state: SymState,
|
||||||
}
|
}
|
||||||
|
@ -77,10 +78,11 @@ impl<'a> ResolverState<'a> {
|
||||||
self.scopes[self.scopes.len() - 1]
|
self.scopes[self.scopes.len() - 1]
|
||||||
.values()
|
.values()
|
||||||
.filter(|v| v.state != SymState::Used)
|
.filter(|v| v.state != SymState::Used)
|
||||||
.find(|v| !v.decl.lexeme.starts_with('_'))
|
.filter(|v| v.decl.is_some())
|
||||||
|
.find(|v| !v.decl.unwrap().lexeme.starts_with('_'))
|
||||||
.map_or(Ok(()), |v| {
|
.map_or(Ok(()), |v| {
|
||||||
self.error(
|
self.error(
|
||||||
v.decl,
|
v.decl.unwrap(),
|
||||||
"unused symbol; prefix its name with '_' to avoid this error",
|
"unused symbol; prefix its name with '_' to avoid this error",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -105,7 +107,7 @@ impl<'a> ResolverState<'a> {
|
||||||
scope.insert(
|
scope.insert(
|
||||||
name.lexeme.clone(),
|
name.lexeme.clone(),
|
||||||
SymInfo {
|
SymInfo {
|
||||||
decl: name,
|
decl: Some(name),
|
||||||
kind,
|
kind,
|
||||||
state: SymState::Declared,
|
state: SymState::Declared,
|
||||||
},
|
},
|
||||||
|
@ -127,6 +129,22 @@ impl<'a> ResolverState<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Declare and define the "this" value for the current scope.
|
||||||
|
fn define_this(&mut self) {
|
||||||
|
assert!(!self.scopes.is_empty());
|
||||||
|
let idx = self.scopes.len() - 1;
|
||||||
|
let scope = &mut self.scopes[idx];
|
||||||
|
assert!(!scope.contains_key("this"));
|
||||||
|
scope.insert(
|
||||||
|
"this".to_owned(),
|
||||||
|
SymInfo {
|
||||||
|
decl: None,
|
||||||
|
kind: SymKind::This,
|
||||||
|
state: SymState::Defined,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Resolve a symbol when it is being used. If the symbol is local,
|
/// Resolve a symbol when it is being used. If the symbol is local,
|
||||||
/// the lookup distance will be stored to the resolution map.
|
/// the lookup distance will be stored to the resolution map.
|
||||||
fn resolve_use(&mut self, expr: &VariableExpr) -> ResolverResult {
|
fn resolve_use(&mut self, expr: &VariableExpr) -> ResolverResult {
|
||||||
|
@ -208,6 +226,18 @@ where
|
||||||
rs.with_scope(|rs| body.resolve(rs))
|
rs.with_scope(|rs| body.resolve(rs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Process all method definitions in a class.
|
||||||
|
fn resolve_class<'a, 'b>(rs: &mut ResolverState<'a>, methods: &'b [FunDecl]) -> ResolverResult
|
||||||
|
where
|
||||||
|
'b: 'a,
|
||||||
|
{
|
||||||
|
rs.define_this();
|
||||||
|
methods
|
||||||
|
.iter()
|
||||||
|
.map(|method| rs.with_scope(|rs| resolve_function(rs, &method.params, &method.body)))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
/// Helper trait used to visit the various AST nodes with the resolver.
|
/// Helper trait used to visit the various AST nodes with the resolver.
|
||||||
trait VarResolver {
|
trait VarResolver {
|
||||||
/// Try to resolve local variables under some AST node.
|
/// Try to resolve local variables under some AST node.
|
||||||
|
@ -265,12 +295,7 @@ impl VarResolver for StmtNode {
|
||||||
StmtNode::ClassDecl(decl) => {
|
StmtNode::ClassDecl(decl) => {
|
||||||
rs.declare(&decl.name, SymKind::Class)?;
|
rs.declare(&decl.name, SymKind::Class)?;
|
||||||
rs.define(&decl.name);
|
rs.define(&decl.name);
|
||||||
decl.methods
|
rs.with_scope(|rs| resolve_class(rs, &decl.methods))
|
||||||
.iter()
|
|
||||||
.map(|method| {
|
|
||||||
rs.with_scope(|rs| resolve_function(rs, &method.params, &method.body))
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StmtNode::If {
|
StmtNode::If {
|
||||||
|
|
Loading…
Reference in a new issue