Skip to content
This repository has been archived by the owner on Mar 4, 2024. It is now read-only.

Commit

Permalink
rewrite enviroments
Browse files Browse the repository at this point in the history
  • Loading branch information
Thepigcat76 committed Nov 17, 2023
1 parent 04e72b6 commit 9811e27
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 145 deletions.
107 changes: 82 additions & 25 deletions src/evaluator/enviroment.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,103 @@
use std::collections::HashMap;

use crate::evaluator::object::Object;
use super::object::Object;

type OptionalEnvObj = Option<Box<EnvObj>>;

#[derive(Debug)]
pub enum EnvObj {
OBJ(Obj),
SCOPE(Scope),
}

#[derive(Debug, Clone)]
pub struct EnvObj {
pub struct Obj {
pub obj: Box<Object>,
pub is_const: bool,
pub is_local: bool,
pub obj: Object,
}

#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct Scope {
objs: HashMap<String, OptionalEnvObj>,
}

impl Scope {
pub fn set(&mut self, name: String, obj: Obj) {
match self.objs.insert(format!("$var_{}", name), Some(Box::from(EnvObj::OBJ(obj)))) {
Some(_) => (),
None => todo!(),
}
}

pub fn get(&mut self, name: String) -> Result<Obj, ()> {
match self.objs.get(&format!("$var_{}", name)) {
Some(obj) => match obj {
Some(val) => match &**val {
EnvObj::OBJ(val) => Ok(val.to_owned()),
EnvObj::SCOPE(_) => todo!(),
},
None => todo!(),
},
None => Err(()),
}
}
}

#[derive(Debug)]
pub struct Environment {
store: HashMap<String, EnvObj>,
scope_id: i64,
objs: HashMap<String, EnvObj>,
}

impl Environment {
pub fn new() -> Self {
let s = HashMap::new();
Environment { store: s}
Self {
scope_id: 0,
objs: HashMap::new(),
}
}

pub fn set_global(&mut self, name: &String, obj: Obj) {
match self.objs.insert(format!("$var_{}", name), EnvObj::OBJ(obj)) {
Some(_) => (),
None => (),
}
println!("{:?}", self.get_global(name))
}

pub fn get(&self, name: &String) -> Result<EnvObj, ()> {
let obj = match self.store.get(name) {
Some(val) => Ok(val.clone()),
None => {
Err(()) // Return an error if the key is not found
}
};
obj
pub fn get_global(&self, name: &String) -> Result<Obj, ()> {
match self.objs.get(&format!("$var_{}", name)) {
Some(obj) => match &obj {
EnvObj::OBJ(val) => Ok(val.to_owned()),
EnvObj::SCOPE(_) => todo!(),
},
None => Err(()),
}
}

pub fn set(&mut self, name: &String, val: &Object, is_local: bool, is_const: bool) -> Object {
self.store.insert(name.to_string(), EnvObj { is_const, is_local, obj: val.to_owned() });
val.clone()
pub fn modify_global(&mut self, name: &String, new_val: Object) {
match self.objs.get_mut(&format!("$var_{}", name)) {
Some(val) => match val {
EnvObj::OBJ(obj) => if !obj.is_const {
obj.obj = Box::new(new_val)
} else {
todo!("Cannot modify a constant variable")
}
EnvObj::SCOPE(_) => todo!(),
},
None => todo!(),
}
}

pub fn modify(&mut self, name: &String, new_val: Object) {
match self.store.get_mut(name) {
Some(val) => if !val.is_const {
val.obj = new_val
} else {
todo!("Cannot modify a constant variable")
pub fn create_scope(&mut self) -> Scope {
self.scope_id += 1;
match self.objs.insert(
format!("#scope_{}", self.scope_id),
EnvObj::SCOPE(Scope { objs: HashMap::new() }),
) {
Some(obj) => match obj {
EnvObj::OBJ(_) => todo!(),
EnvObj::SCOPE(scope) => scope,
},
None => todo!(),
}
Expand Down
183 changes: 68 additions & 115 deletions src/evaluator/evaluator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@ use crate::{
};

use super::{
enviroment::Environment,
enviroment::{EnvObj, Environment, Obj, Scope},
object::{self, *},
};

pub struct Evaluator {
env: Environment,
/// When scope is None we are in the global scope
cur_scope: Option<Scope>,
}

impl Evaluator {
pub fn new() -> Self {
Self {
env: Environment::new(),
cur_scope: None,
}
}

Expand All @@ -38,18 +41,36 @@ impl Evaluator {
fn eval_statement(&mut self, statement: &Statement, is_local: bool) -> Object {
match statement {
Statement::VAR(var) => {
let val = self.eval_expression(&var.value);
self.env.set(&var.name.value, &val, is_local, false);
let val: Object = self.eval_expression(&var.value);
match self.cur_scope {
Some(_) => todo!(),
None => self.env.set_global(
&var.name.value,
Obj {
obj: Box::from(val),
is_const: false,
},
),
}
Object::Var(Var {
value: Box::from(val),
value: Box::from(self.eval_expression(&var.value)),
is_local,
})
}
Statement::CONST(constant) => {
let val = self.eval_expression(&constant.value);
self.env.set(&constant.name.value, &val, is_local, true);
match self.cur_scope {
Some(_) => todo!(),
None => self.env.set_global(
&constant.name.value,
Obj {
obj: Box::from(val),
is_const: true,
},
),
}
Object::Var(Var {
value: Box::from(val),
value: Box::from(self.eval_expression(&constant.value)),
is_local,
})
}
Expand Down Expand Up @@ -99,23 +120,26 @@ impl Evaluator {
}

fn eval_identifier(&mut self, ident: &Identifier) -> Object {
match self.env.get(&ident.value) {
Ok(obj) => obj.obj,
Err(_) => match &ident.value {
i if i == &BuiltinType::BOOLEAN.literal() => {
Object::Type(object::Type::BUILTIN(BuiltinType::BOOLEAN))
}
i if i == &BuiltinType::NUMBER.literal() => {
Object::Type(object::Type::BUILTIN(BuiltinType::NUMBER))
}
i if i == &BuiltinType::STRING.literal() => {
Object::Type(object::Type::BUILTIN(BuiltinType::STRING))
}
_ => {
let err = Error::new(format!("Cannot find identifier: {}", ident.value));
throw_error(&err);
Object::Error(err)
}
match self.cur_scope {
Some(_) => todo!(),
None => match self.env.get_global(&ident.value) {
Ok(obj) => *obj.obj,
Err(_) => match &ident.value {
i if i == &BuiltinType::BOOLEAN.literal() => {
Object::Type(object::Type::BUILTIN(BuiltinType::BOOLEAN))
}
i if i == &BuiltinType::NUMBER.literal() => {
Object::Type(object::Type::BUILTIN(BuiltinType::NUMBER))
}
i if i == &BuiltinType::STRING.literal() => {
Object::Type(object::Type::BUILTIN(BuiltinType::STRING))
}
_ => {
let err = Error::new(format!("Cannot find identifier: {}", ident.value));
throw_error(&err);
Object::Error(err)
}
},
},
}
}
Expand Down Expand Up @@ -216,20 +240,25 @@ impl Evaluator {
}

fn eval_assign_infix_expression(&mut self, node: &InfixExpression, right: Object) -> Object {
match &*node.left {
Expression::IDENTIFIER(ident) => self.env.modify(&ident.value, right),
_ => todo!(),
}
match self.env.get(
&match &*node.left {
Expression::IDENTIFIER(ident) => ident,
_ => todo!(),
match self.cur_scope {
Some(_) => todo!(),
None => {
match &*node.left {
Expression::IDENTIFIER(ident) => self.env.modify_global(&ident.value, right),
_ => todo!(),
}
match self.env.get_global(
&match &*node.left {
Expression::IDENTIFIER(ident) => ident,
_ => todo!(),
}
.value,
) {
Ok(obj) => return *obj.obj,
Err(_) => todo!(),
};
}
.value,
) {
Ok(obj) => return obj.obj,
Err(_) => todo!(),
};
}
}

fn eval_conversion_infix_expression(&mut self, node: &InfixExpression, left: Object) -> Object {
Expand Down Expand Up @@ -445,11 +474,11 @@ impl Evaluator {
Object::Num(num) => num.value as i32,
_ => todo!(),
};

for _ in left_val..right_val {
self.eval_block_statement(&node.consequence);
}

return self.eval_block_statement(&node.consequence);
}
Object::List(list) => todo!(),
Expand Down Expand Up @@ -533,83 +562,7 @@ impl Evaluator {
builtins::BuiltinFunction::read_input(&func);
Object::BuiltInFunction(func)
}
_ => {
let mut old_env = self.env.clone();
let new_env = &self.env;

self.env = new_env.clone();

let func = match self.env.get(&ident.value) {
Ok(obj) => obj,
Err(_) => {
let err = Error::new(format!(
"Cannot find identifier: {}",
ident.value.as_str()
));
throw_error(&err);
return Object::Error(err);
}
};

let empty_func = Function::empty();

let func_obj = if let Object::Function(ref func) = func.obj {
func
} else {
throw_error(&Error {
message: "Identifier is not a function".to_string(),
});
&empty_func
};

for (index, arg) in func_obj.args.iter().enumerate() {
if index < node.args.len() {
let cur_arg = self.eval_expression(&node.args[index]);
self.env.set(&arg.arg.value, &cur_arg, false, false);
} else {
break;
}
}

for stmt in &func_obj.body.statements {
let obj = self.eval(&stmt);
match obj {
Object::Return(ret) => {
return *ret.value;
}
_ => continue,
}
}

// Update all args cuz of mutability
for (index, arg) in node.args.iter().enumerate() {
let call_arg_name = match arg {
Expression::IDENTIFIER(ident) => Some(&ident.value),
_ => None,
};

let func_arg_name = &func_obj.args[index].arg.value;

match call_arg_name {
Some(arg_name) => {
old_env.modify(
arg_name,
match self.env.get(func_arg_name) {
Ok(env_obj) => env_obj.obj,
Err(_) => todo!(),
},
);
}
None => (),
}

// Take call args and update related vars with values from function
}

self.env = old_env;

func.obj
}
_ => todo!(),
},
_ => todo!("{:?}", node.function),
}
Expand Down
2 changes: 1 addition & 1 deletion src/parser/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,7 @@ impl<'a> Parser<'a> {

let condition = Box::new(self.parse_expression(LOWEST));

if &condition == &Box::new(Expression::EMPTY) {
if *condition == Expression::EMPTY {
self.throw_error(empty_condition(&TokenType::LOOP, &condition), true);
return Expression::EMPTY;
}
Expand Down
8 changes: 4 additions & 4 deletions test/test.nx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
var x = [0, 0]
var x = 1

loop i in 0..10 {
print(i)
}
x = 2

print(x)

0 comments on commit 9811e27

Please sign in to comment.