Skip to content

Commit

Permalink
Fail static analysis on this outside of class
Browse files Browse the repository at this point in the history
  • Loading branch information
froth committed Apr 9, 2024
1 parent 4140db0 commit cf13542
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/lox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ impl Lox {
eprintln!("No statement found. Fallback to expression:");
eprintln!("{}", expr);
}
let locals = Resolver::resolve_expression(expr, self.verbose)?;
self.interpreter.add_locals(locals);
let result = self.interpreter.interpret_expr(expr)?;
Ok(Some(result))
}
Expand Down
33 changes: 30 additions & 3 deletions src/resolver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub struct Resolver {
locals: HashMap<NameExpr, usize>,
scopes: Vec<HashMap<Name, bool>>,
current_function: Option<FunctionType>,
current_class: Option<ClassType>,
}

#[derive(Debug)]
Expand All @@ -24,6 +25,11 @@ enum FunctionType {
Method,
}

#[derive(Debug)]
enum ClassType {
Class,
}

type Result<T> = std::result::Result<T, ResolutionError>;

impl Resolver {
Expand All @@ -36,6 +42,18 @@ impl Resolver {
Ok(resolver.locals)
}

pub fn resolve_expression(
expression: &Expr,
verbose: bool,
) -> Result<HashMap<NameExpr, usize>> {
let mut resolver = Resolver::default();
resolver.resolve_expr(expression)?;
if verbose {
eprintln!("{:?}", resolver.locals);
}
Ok(resolver.locals)
}

fn resolve_statements(&mut self, statements: &[Stmt]) -> Result<()> {
statements
.iter()
Expand Down Expand Up @@ -113,6 +131,7 @@ impl Resolver {
}

fn resolve_class(&mut self, name: &Name, methods: &[Function]) -> Result<()> {
let enclosing_class = std::mem::replace(&mut self.current_class, Some(ClassType::Class));
self.declare(name);
self.define(name);
self.begin_scope();
Expand All @@ -122,6 +141,7 @@ impl Resolver {
self.resolve_function(&m.parameters, &m.body, FunctionType::Method)
})?;
self.end_scope();
self.current_class = enclosing_class;
Ok(())
}

Expand Down Expand Up @@ -171,9 +191,16 @@ impl Resolver {
}

fn resolve_this(&mut self, location: SourceSpan, src: &Arc<NamedSource<String>>) -> Result<()> {
let name_expr = NameExpr::this(location, src.clone());
self.resolve_local(&name_expr);
Ok(())
if self.current_class.is_none() {
Err(ResolutionError::InvalidThis {
src: src.clone(),
location,
})
} else {
let name_expr = NameExpr::this(location, src.clone());
self.resolve_local(&name_expr);
Ok(())
}
}

fn declare(&mut self, name: &Name) {
Expand Down
7 changes: 7 additions & 0 deletions src/resolver/resolution_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,11 @@ pub enum ResolutionError {
#[label("here")]
location: SourceSpan,
},
#[error("Can't use 'this' outside of a class.")]
InvalidThis {
#[source_code]
src: Arc<NamedSource<String>>,
#[label("here")]
location: SourceSpan,
},
}
22 changes: 22 additions & 0 deletions tests/resolver_errors/this_outside_of_class.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
error
this;
----
----
{
"causes": [],
"filename": "tests/resolver_errors/this_outside_of_class.lox",
"labels": [
{
"label": "here",
"span": {
"length": 4,
"offset": 0
}
}
],
"message": "Can't use 'this' outside of a class.",
"related": [],
"severity": "error"
}
----
---- (no newline)
2 changes: 1 addition & 1 deletion tests/this.lox
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ var callback = thing.getCallback();
thing.name = "my_thing";
callback();
----
my_thing
my_thing

0 comments on commit cf13542

Please sign in to comment.