Skip to content

Commit

Permalink
feat: add resolver
Browse files Browse the repository at this point in the history
If I had access to a rage room, I would've definitely used it now - this
was such a pain to debug, implement, and test. I absolutely hate it. I
also absolutely love that it's done. The misery ends here :')

Signed-off-by: Prajwal S N <prajwalnadig21@gmail.com>
  • Loading branch information
snprajwal committed Dec 27, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent fe517c7 commit 6fc5bf1
Showing 14 changed files with 711 additions and 294 deletions.
55 changes: 39 additions & 16 deletions lost_compile/src/environment.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use std::{cell::RefCell, collections::HashMap, rc::Rc};

use log::debug;
use lost_syntax::ast::Literal;

use crate::{
error::{make, ErrorMsg, Exception},
error::{runtime_error, ErrorMsg, Exception},
stdlib,
types::Type,
};
@@ -18,7 +17,7 @@ pub struct Env {
impl Env {
pub fn new() -> Rc<RefCell<Self>> {
let mut env = Self::default();
stdlib::init_io(&mut env);
stdlib::init(&mut env);
Rc::new(RefCell::new(env))
}

@@ -29,10 +28,9 @@ impl Env {
}))
}

pub fn set(&mut self, name: String, value: Type) -> Type {
pub fn set(&mut self, name: String, value: Type) {
debug!("Set {name} -> {value:?}");
self.values.insert(name, value.clone());
value
}

pub fn get(&self, name: String) -> Result<Type, Exception> {
@@ -44,10 +42,10 @@ impl Env {
debug!("Get {name} from parent");
return parent.borrow().get(name);
}
Err(make(ErrorMsg::UndefinedVar, name))
Err(runtime_error(ErrorMsg::UndefinedVar, name))
}

pub fn assign(&mut self, name: String, value: Type) -> Result<Type, Exception> {
pub fn assign(&mut self, name: String, value: Type) -> Result<(), Exception> {
debug!("Assign {name} -> {value:?})");
if self.values.contains_key(&name) {
return Ok(self.set(name, value));
@@ -56,16 +54,41 @@ impl Env {
debug!("Assign {name} in parent");
return parent.borrow_mut().assign(name, value);
}
Err(make(ErrorMsg::UndefinedVar, name))
Err(runtime_error(ErrorMsg::UndefinedVar, name))
}

pub fn from_literal(&self, value: Literal) -> Result<Type, Exception> {
Ok(match value {
Literal::Str(s) => Type::Str(s),
Literal::Number(n) => Type::Number(n),
Literal::Boolean(b) => Type::Boolean(b),
Literal::Ident(name) => return self.get(name),
Literal::Null => Type::Null,
})
pub fn get_at_depth(&self, name: String, depth: usize) -> Result<Type, Exception> {
debug!("Get {name} at depth {depth}");
if depth == 0 {
if let Some(value) = self.values.get(&name) {
return Ok(value.clone());
}
return Err(runtime_error(ErrorMsg::MisresolvedVar, name));
}
self.parent
.as_ref()
.expect("depth exceeds maximum environment depth")
.borrow()
.get_at_depth(name, depth - 1)
}

pub fn assign_at_depth(
&mut self,
name: String,
value: Type,
depth: usize,
) -> Result<(), Exception> {
debug!("Set {name} -> {value} at depth {depth}");
if depth == 0 {
if self.values.contains_key(&name) {
return Ok(self.set(name, value));
}
return Err(runtime_error(ErrorMsg::MisresolvedVar, name));
}
self.parent
.as_ref()
.expect("depth exceeds maximum environment depth")
.borrow_mut()
.assign_at_depth(name, value, depth - 1)
}
}
22 changes: 20 additions & 2 deletions lost_compile/src/error.rs
Original file line number Diff line number Diff line change
@@ -29,9 +29,14 @@ pub enum ErrorMsg {
TooManyArgs,
TooFewArgs,
GetConstructor,
// Memory errors
// Resolution errors
NoScope,
UndefinedVar,
MisresolvedVar,
UndefinedMember,
SelfIntialiser,
ReturnOutsideFunction,
ThisOutsideMethod,
}

impl Display for ErrorMsg {
@@ -46,12 +51,25 @@ impl Display for ErrorMsg {
Self::TooManyArgs => "too many arguments in function call",
Self::TooFewArgs => "too few arguments in function call",
Self::GetConstructor => "illegal to get constructor of class",
Self::NoScope => "no scope present to resolve",
Self::UndefinedVar => "undefined variable",
Self::MisresolvedVar => "misresolved variable",
Self::UndefinedMember => "undefined object member",
Self::SelfIntialiser => "cannot use self to initialise",
Self::ReturnOutsideFunction => "cannot return from outside a function",
Self::ThisOutsideMethod => "cannot use `this` variable outside class methods",
})
}
}

pub fn make(msg: ErrorMsg, val: String) -> Exception {
pub fn runtime_error(msg: ErrorMsg, val: String) -> Exception {
Exception::Error(format!("Runtime error: {} {}", msg, val))
}

pub fn resolution_error(msg: ErrorMsg, val: String) -> Exception {
Exception::Error(
format!("Resolution error: {} {}", msg, val)
.trim()
.to_string(),
)
}
Loading

0 comments on commit 6fc5bf1

Please sign in to comment.