Skip to content

Commit

Permalink
Fix: Fixed Loop Scoping
Browse files Browse the repository at this point in the history
  • Loading branch information
PranavVerma-droid committed Nov 25, 2024
1 parent 0c5dcd4 commit 35b2a4f
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 68 deletions.
116 changes: 52 additions & 64 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ impl fmt::Display for Value {
}

pub struct Environment {
variables: HashMap<String, (Value, bool)>,
scopes: Vec<HashMap<String, (Value, bool)>>,
functions: HashMap<String, Value>,
in_function: bool,
libraries: HashMap<String, Box<dyn Library>>,
Expand All @@ -52,14 +52,13 @@ pub struct Environment {
impl Environment {
pub fn new() -> Self {
let mut env = Environment {
variables: HashMap::new(),
scopes: vec![HashMap::new()],
functions: HashMap::new(),
in_function: false,
libraries: HashMap::new(),
};

let std_lib = StdLib::new();

for (name, _func) in std_lib.get_function_map().iter() {
env.functions.insert(name.clone(), Value::Function(
name.clone(),
Expand All @@ -72,16 +71,36 @@ impl Environment {
env
}

pub fn push_scope(&mut self) {
self.scopes.push(HashMap::new());
}

pub fn pop_scope(&mut self) {
self.scopes.pop();
}

pub fn get(&self, name: &str) -> Option<&(Value, bool)> {
self.variables.get(name)
for scope in self.scopes.iter().rev() {
if let Some(value) = scope.get(name) {
return Some(value);
}
}
None
}

pub fn get_mut(&mut self, name: &str) -> Option<&mut (Value, bool)> {
self.variables.get_mut(name)
for scope in self.scopes.iter_mut().rev() {
if let Some(value) = scope.get_mut(name) {
return Some(value);
}
}
None
}

pub fn insert_var(&mut self, name: String, value: Value, mutable: bool) {
self.variables.insert(name, (value, mutable));
if let Some(scope) = self.scopes.last_mut() {
scope.insert(name, (value, mutable));
}
}

pub fn insert_function(&mut self, name: String, value: Value) {
Expand Down Expand Up @@ -323,7 +342,9 @@ fn interpret_node(node: &ASTNode, env: &mut Environment, is_verbose: bool, in_lo
if is_verbose {
println!("delete variable '{}'", name);
}
env.variables.remove(name);
if let Some(scope) = env.scopes.last_mut() {
scope.remove(name);
}
Ok(Value::Null)
} else {
Err(Error::TypeError("del() requires a variable name".to_string()))
Expand Down Expand Up @@ -534,9 +555,7 @@ fn interpret_node(node: &ASTNode, env: &mut Environment, is_verbose: bool, in_lo
_ => Err(Error::TypeError(format!("Invalid indexing operation"))),
}
},


ASTNode::FunctionCall(name, args) => {
ASTNode::FunctionCall(name, args) => {
let mut evaluated_args = Vec::new();
for arg in args {
evaluated_args.push(interpret_node(arg, env, is_verbose, in_loop)?);
Expand Down Expand Up @@ -648,44 +667,30 @@ fn interpret_node(node: &ASTNode, env: &mut Environment, is_verbose: bool, in_lo
}
},
ASTNode::While(condition, body) => {
if is_verbose {
println!("entering while loop");
}
loop {
if is_verbose {
println!("checking while loop condition");
}
env.push_scope();

let mut result = Value::Null;
'outer: loop {
let cond_value = interpret_node(condition, env, is_verbose, true)?;
if let Value::Boolean(false) = cond_value {
if is_verbose {
println!("while loop condition false, exiting loop");
}
break;
}

if is_verbose {
println!("executing while loop body");
}
for stmt in body {
let result = interpret_node(stmt, env, is_verbose, true)?;
match result {
match interpret_node(stmt, env, is_verbose, true)? {
Value::Break => {
if is_verbose {
println!("break encountered, exiting while loop");
}
return Ok(Value::Null);
break 'outer;
},
Value::Continue => {
if is_verbose {
println!("continue encountered, skipping to next iteration");
}
break;
continue 'outer;
},
_ => {}
val => result = val,
}
}
}
Ok(Value::Null)

env.pop_scope();
Ok(result)
},
ASTNode::Var(name, expr, is_mutable) => {
let value = if let Some(expr) = expr {
Expand Down Expand Up @@ -869,52 +874,35 @@ fn interpret_node(node: &ASTNode, env: &mut Environment, is_verbose: bool, in_lo
}
Ok(Value::Null)
},
ASTNode::For(init, condition, update, body) => {
if is_verbose {
println!("initializing for loop");
}
ASTNode::For(init, condition, update, body) => {
env.push_scope(); // Create new scope for the loop

interpret_node(init, env, is_verbose, true)?;

loop {
if is_verbose {
println!("checking for loop condition");
}
let mut result = Value::Null;
'outer: loop {
let cond_value = interpret_node(condition, env, is_verbose, true)?;
if let Value::Boolean(false) = cond_value {
if is_verbose {
println!("for loop condition false, exiting loop");
}
break;
}

if is_verbose {
println!("executing for loop body");
}
for stmt in body {
let result = interpret_node(stmt, env, is_verbose, true)?;
match result {
match interpret_node(stmt, env, is_verbose, true)? {
Value::Break => {
if is_verbose {
println!("break encountered, exiting for loop");
}
return Ok(Value::Null);
break 'outer;
},
Value::Continue => {
if is_verbose {
println!("continue encountered, skipping to next iteration");
}
break;
continue 'outer;
},
_ => {}
val => result = val,
}
}

if is_verbose {
println!("executing for loop update");
}
interpret_node(update, env, is_verbose, true)?;
}
Ok(Value::Null)

env.pop_scope();
Ok(result)
},
ASTNode::Break => {
if !in_loop {
Expand Down
23 changes: 19 additions & 4 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ pub enum ASTNode {
struct Scope {
variables: HashMap<String, bool>,
is_function: bool,
is_block: bool,
}

pub struct Parser<'a> {
Expand All @@ -101,7 +102,7 @@ impl<'a> Parser<'a> {
current_token,
scopes: Vec::new(),
};
parser.push_scope(false);
parser.push_scope(false, false);
parser
}

Expand Down Expand Up @@ -159,10 +160,11 @@ impl<'a> Parser<'a> {
Ok(ASTNode::LibraryAccess(lib_name, item_name))
} */

fn push_scope(&mut self, is_function: bool) {
fn push_scope(&mut self, is_function: bool, is_block: bool) {
self.scopes.push(Scope {
variables: HashMap::new(),
is_function,
is_block,
});
}

Expand All @@ -185,14 +187,17 @@ impl<'a> Parser<'a> {
}

fn is_variable_declared(&self, name: &str) -> bool {
if self.current_scope().is_function {
if self.current_scope().is_block {
return self.current_scope().variables.contains_key(name);
}

for scope in self.scopes.iter().rev() {
if scope.variables.contains_key(name) {
return true;
}
if scope.is_function {
break;
}
}
false
}
Expand Down Expand Up @@ -248,7 +253,7 @@ impl<'a> Parser<'a> {
self.eat(Token::RParen)?;
self.eat(Token::LBrace)?;

self.push_scope(true);
self.push_scope(true, false);

let mut body = Vec::new();
while self.current_token != Token::RBrace {
Expand Down Expand Up @@ -447,9 +452,14 @@ impl<'a> Parser<'a> {
self.eat(Token::LParen)?;
let condition = self.parse_expr()?;
self.eat(Token::RParen)?;

self.push_scope(false, true);

self.eat(Token::LBrace)?;
let body = self.parse_block()?;
self.eat(Token::RBrace)?;

self.pop_scope();

Ok(ASTNode::While(Box::new(condition), body))
}
Expand Down Expand Up @@ -491,6 +501,8 @@ impl<'a> Parser<'a> {
self.eat(Token::For)?;
self.eat(Token::LParen)?;

self.push_scope(false, true);

let init = if let Token::Var | Token::NoVar = self.current_token {
self.parse_var_decl()?
} else {
Expand All @@ -507,6 +519,8 @@ impl<'a> Parser<'a> {
let body = self.parse_block()?;
self.eat(Token::RBrace)?;

self.pop_scope();

Ok(ASTNode::For(Box::new(init), Box::new(condition), Box::new(update), body))
}

Expand Down Expand Up @@ -924,3 +938,4 @@ impl<'a> Parser<'a> {
Ok(ASTNode::Print(Box::new(expr)))
}
}

0 comments on commit 35b2a4f

Please sign in to comment.