diff --git a/src/cli-repl.rs b/src/cli-repl.rs index a8c0a8b..0c7d1d0 100644 --- a/src/cli-repl.rs +++ b/src/cli-repl.rs @@ -124,12 +124,12 @@ impl Input { } } - pub fn disable_raw(&mut self) { - self.stdout.suspend_raw_mode(); + pub fn disable_raw(&mut self) -> io::Result<()> { + self.stdout.suspend_raw_mode() } - pub fn enable_raw(&mut self) { - self.stdout.activate_raw_mode(); + pub fn enable_raw(&mut self) -> io::Result<()> { + self.stdout.activate_raw_mode() } } @@ -165,14 +165,11 @@ fn main() -> Result<(), io::Error> { } #[cfg(debug_assertions)] - input.disable_raw(); + input.disable_raw()?; let tokens = tokens_result.unwrap(); let mut parser = Parser::new(tokens, &mut env); - #[cfg(debug_assertions)] - input.enable_raw(); - let nodes = match parser.parse() { Ok(nodes) => nodes, Err(err) => { @@ -196,6 +193,9 @@ fn main() -> Result<(), io::Error> { } } + #[cfg(debug_assertions)] + input.enable_raw()?; + print!("{}", color::Fg(color::Reset)); // println!("\t{}{source}{}", termion::color::Fg(termion::color::Blue), termion::color::Fg(termion::color::Reset)); diff --git a/src/lib/environment.rs b/src/lib/environment.rs index 14af6ed..7066308 100644 --- a/src/lib/environment.rs +++ b/src/lib/environment.rs @@ -7,29 +7,85 @@ pub type EnvironmentInternalSymbolKey = u16; pub struct Environment { map: HashMap>, + stack_depth: usize, + max_stack_depth: usize, + stack: Vec>, symbol_to_id: HashMap, id_to_symbol: HashMap, - unique_keys: EnvironmentInternalSymbolKey + unique_keys: EnvironmentInternalSymbolKey, } impl Environment { pub fn new() -> Self { Self { map: HashMap::new(), + stack_depth: 0, + max_stack_depth: 5000, + stack: vec![vec![]], symbol_to_id: HashMap::new(), id_to_symbol: HashMap::new(), - unique_keys: 0 + unique_keys: 0, } } + pub fn push_stack(&mut self) -> Result<(), String> { + debug_assert!(self.stack_depth == self.stack.len() - 1); + + if self.stack_depth == self.max_stack_depth { + self.unwind_stack(); + return Err("Max Stack depth exceeded".to_owned()); + } + + self.stack_depth += 1; + self.stack.push(vec![]); + + debug_assert!(self.stack_depth == self.stack.len() - 1); + + Ok(()) + } + + pub fn pop_stack(&mut self) -> Result<(), String> { + debug_assert!( + self.stack_depth == self.stack.len() - 1, + "Expected stack len: {}, stack_depth: {}", + self.stack.len(), + self.stack_depth + ); + + if self.stack_depth == 0 { + return Err("Trying to pop empty stack".to_owned()); + } + + self.stack_depth -= 1; + + for item in self.stack.pop().unwrap() { + self.map.remove(&item); + } + + debug_assert!(self.stack_depth == self.stack.len() - 1); + + Ok(()) + } + + fn unwind_stack(&mut self) { + for stack in &self.stack { + for item in stack { + self.map.remove(&item); + } + } + + self.stack = vec![vec![]]; + } + pub fn get(&self, key: &EnvironmentInternalSymbolKey) -> Option<&Rc> { self.map.get(key) } pub fn insert(&mut self, key: EnvironmentInternalSymbolKey, value: Rc) { self.map.insert(key, value); + unsafe { self.stack.get_unchecked_mut(self.stack_depth).push(key) } } pub fn str_to_id(&self, value: &String) -> Option<&EnvironmentInternalSymbolKey> { diff --git a/src/lib/node/call.rs b/src/lib/node/call.rs index b919882..55c4b6e 100644 --- a/src/lib/node/call.rs +++ b/src/lib/node/call.rs @@ -50,15 +50,15 @@ impl Node for Call { // Pass arguments to native function FunctionType::Native(_name, native_function) => native_function(&arguments), FunctionType::UserFunction(node_enum) => { - // TODO: Push scope + env.push_stack()?; // Define variables fargs.iter().zip(arguments).for_each(|(symbol, value)| { env.insert(symbol.get_value(), value.clone()); }); - let ev = node_enum.evaluate(env); - // TODO: Pop scope + let ev = node_enum.evaluate(env)?; + env.pop_stack()?; // Return evaluated return value for function - ev + Ok(ev) } } } diff --git a/src/lib/node/empty.rs b/src/lib/node/empty.rs index dc87d8e..565ba9a 100644 --- a/src/lib/node/empty.rs +++ b/src/lib/node/empty.rs @@ -15,7 +15,7 @@ impl Node for Empty { fn as_string(&self, _: Option<&Environment>) -> String { match &self.message { Some(m) => m.clone(), - None => String::from("{{#VOID}}"), + None => String::from("{{#EMPTY}}"), } } diff --git a/src/lib/node/if_else.rs b/src/lib/node/if_else.rs index 07e7495..20eab5d 100644 --- a/src/lib/node/if_else.rs +++ b/src/lib/node/if_else.rs @@ -1,5 +1,7 @@ use std::rc::Rc; +use crate::node::empty::Empty; + use super::{Environment, Node, NodeEnum, Precedence}; #[derive(Clone, Debug, PartialEq, PartialOrd)] @@ -28,8 +30,9 @@ impl Node for Bool { #[derive(Clone, Debug, PartialEq, PartialOrd)] pub enum ElseBranchEnum { - ElseIf(Rc), + ElseIf(Rc), Block(Vec>), + None, } #[derive(Clone, Debug, PartialEq, PartialOrd)] @@ -56,16 +59,17 @@ impl Node for IfElse { block: &Vec>, env: &mut Environment, ) -> Result, String> { - // TODO: Push new scope - if let Some((last, to_evaluate)) = block.split_last() { + env.push_stack()?; + let ret = if let Some((last, to_evaluate)) = block.split_last() { for expr in to_evaluate { expr.evaluate(env)?; } last.evaluate(env) } else { - Err("Empty if statemenent true branch")? - } - // TODO: Pop scope + Ok(Empty::EMPTY.clone()) + }; + env.pop_stack()?; + ret } match condition { @@ -73,28 +77,32 @@ impl Node for IfElse { Bool::False => match &self.else_branch { ElseBranchEnum::ElseIf(if_else) => if_else.evaluate(env), ElseBranchEnum::Block(node_enums) => evaluate_block(node_enums, env), + ElseBranchEnum::None => Ok(Empty::EMPTY.clone()), }, } } fn as_string(&self, env: Option<&Environment>) -> String { format!( - "if {} then\n{}\nelse\n{}", + "if {} then {} {}", self.condition.as_string(env), self.true_branch .iter() .map(|x| x.as_string(env)) - .reduce(|a, b| a + "\n" + &b) + .reduce(|a, b| a + " " + &b) .unwrap() .as_str(), match &self.else_branch { ElseBranchEnum::ElseIf(if_else) => if_else.as_string(env), ElseBranchEnum::Block(vec) => - vec.iter() - .map(|x| x.as_string(env)) - .reduce(|a, b| a + "\n" + &b) - .unwrap() - + "\nend", + "else ".to_owned() + + &vec + .iter() + .map(|x| x.as_string(env)) + .reduce(|a, b| a + "\n" + &b) + .unwrap() + + "end", + ElseBranchEnum::None => "end".to_owned(), } .as_str() ) @@ -104,3 +112,20 @@ impl Node for IfElse { Precedence::Primary } } + +impl IfElse { + pub fn new( + condition: Rc, + true_branch: Vec>, + else_branch: ElseBranchEnum, + ) -> Rc { + Rc::new( + Self { + condition, + true_branch, + else_branch, + } + .into(), + ) + } +} diff --git a/src/lib/node/symbol.rs b/src/lib/node/symbol.rs index 5ac0a8d..bb961fe 100644 --- a/src/lib/node/symbol.rs +++ b/src/lib/node/symbol.rs @@ -25,8 +25,8 @@ impl Node for Symbol { fn as_string(&self, env: Option<&Environment>) -> String { if let Some(env) = env { - if let Some(value) = env.get(&self.value) { - value.as_string(Some(env)) + if let Some(str) = env.id_to_str(&self.value) { + str.clone() } else { env.id_to_str(&self.value) .cloned() diff --git a/src/lib/parser/mod.rs b/src/lib/parser/mod.rs index e202386..bb0d069 100644 --- a/src/lib/parser/mod.rs +++ b/src/lib/parser/mod.rs @@ -3,18 +3,7 @@ use std::{collections::HashMap, iter::Peekable, rc::Rc, slice::Iter, str::Chars, use crate::{ environment::Environment, node::{ - NodeEnum, - add::Add, - assign::Assign, - call::Call, - constant::{Constant, ConstantValue}, - divide::Divide, - equals::Equals, - function::{Function, FunctionType}, - multiply::Multiply, - set::Set, - subtract::Subtract, - symbol::Symbol, + add::Add, assign::Assign, call::Call, constant::{Constant, ConstantValue}, divide::Divide, equals::Equals, function::{Function, FunctionType}, if_else::{Bool, ElseBranchEnum, IfElse}, multiply::Multiply, set::Set, subtract::Subtract, symbol::Symbol, NodeEnum }, }; @@ -45,6 +34,9 @@ pub enum TokenType { Then, Else, End, + + True, + False } impl TokenType { @@ -70,6 +62,9 @@ impl TokenType { TokenType::Then => 4, TokenType::Else => 4, TokenType::End => 3, + + TokenType::True => 4, + TokenType::False => 5, } } } @@ -205,6 +200,10 @@ impl<'a> Lexer<'a> { "then" => TokenType::Then, "else" => TokenType::Else, "end" => TokenType::End, + + "true" => TokenType::True, + "false" => TokenType::False, + _ => TokenType::Identifier(identifier), }, )) @@ -222,7 +221,7 @@ pub enum ParserError { pub struct Parser<'a> { tokens: Peekable>, environment: &'a mut Environment, - previous: Option<&'a Token>, + previous: Option, } type Tokens<'a> = Peekable>; @@ -249,15 +248,31 @@ impl<'a> Parser<'a> { Ok(expressions) } + #[inline] + fn consume<'b>(&'b mut self) -> &'b Option { + self.previous = self.tokens.next(); + &self.previous + } + + #[inline] + fn is_at_end(&mut self) -> bool { + if self.tokens.peek().is_none() { + return true; + } + + false + } + + /// Checks if the next token is `t`, if it is then consume it and return true. Otherwise does + /// nothing and returns false. #[inline] fn matchType<'b>(&'b mut self, t: TokenType) -> bool { if let Some(Token(_, token_type)) = self.tokens.peek() { if *token_type == t { - self.tokens.next(); + self.consume(); return true; } } - false } @@ -290,7 +305,7 @@ impl<'a> Parser<'a> { let expr = self.equality(); if let Some(Token(_, TokenType::ColonEquals)) = self.tokens.peek() { - self.tokens.next(); + self.consume(); return Ok(Rc::new(Assign::new(expr?, self.equality()?).into())); } @@ -316,7 +331,7 @@ impl<'a> Parser<'a> { if self.matchType(TokenType::Plus) { Ok(Rc::new(Add::new(expr, self.comparison()?).into())) } else if let Some(Token(_, TokenType::Minus)) = self.tokens.peek() { - self.tokens.next(); + self.consume(); Ok(Rc::new(Subtract::new(expr, self.comparison()?).into())) } else { Ok(expr) @@ -326,10 +341,10 @@ impl<'a> Parser<'a> { fn factor(&mut self) -> Result, ParserError> { let expr = self.unary()?; if let Some(Token(_, TokenType::Star)) = self.tokens.peek() { - self.tokens.next(); + self.consume(); Ok(Rc::new(Multiply::new(expr, self.comparison()?).into())) } else if let Some(Token(_, TokenType::Slash)) = self.tokens.peek() { - self.tokens.next(); + self.consume(); Ok(Rc::new(Divide::new(expr, self.comparison()?).into())) } else { Ok(expr) @@ -366,7 +381,7 @@ impl<'a> Parser<'a> { Set::new(vec![potential_parameters]) }; - expr = Ok(Call::new(expr?, parameters)); + expr = Ok(Call::new(expr?, parameters)); } else { break; } @@ -382,7 +397,7 @@ impl<'a> Parser<'a> { 0 }; - let expr = self.primary()?; + let expr = self.if_else()?; if self.matchType(TokenType::LeftArrow) { let right = self.equality()?; @@ -397,6 +412,8 @@ impl<'a> Parser<'a> { let mut symbols = vec![]; for (i, value) in set.get_values().into_iter().enumerate() { match value.as_ref() { + NodeEnum::Symbol(symbol) => symbols.push(symbol.clone()), + _ => { return Err(ParserError::UnexpectedNode( error_loc, @@ -405,8 +422,6 @@ impl<'a> Parser<'a> { ), )); } - - NodeEnum::Symbol(symbol) => symbols.push(symbol.clone()), } } @@ -424,6 +439,54 @@ impl<'a> Parser<'a> { Ok(expr) } + fn if_else(&mut self) -> Result, ParserError> { + if self.matchType(TokenType::If) { + let condition = self.equality()?; + + let _ = self.matchOrErr(TokenType::Then)?; + + let mut expressions = vec![]; + + while !(self.matchType(TokenType::End) || self.matchType(TokenType::Else)) { + if self.is_at_end() { + return Err(ParserError::UnexpectedEndOfTokens( + "Expected an else or end here".to_owned(), + )); + } + expressions.push(self.expression()?); + } + + // Safe to unwrap since the while loop would terminate if previous was none (it didnt + // find an End or Else before running out of tokens) + let else_branch = match self.previous.as_ref().unwrap() { + Token(_, TokenType::End) => ElseBranchEnum::None, + Token(_, TokenType::Else) => { + if let Some(Token(_, TokenType::If)) = self.tokens.peek() { + ElseBranchEnum::ElseIf(self.if_else()?) + } else { + let mut expressions = vec![]; + while !self.matchType(TokenType::End) { + if self.is_at_end() { + return Err(ParserError::UnexpectedEndOfTokens( + "Expected an end here".to_owned(), + )); + } + expressions.push(self.expression()?); + } + + ElseBranchEnum::Block(expressions) + } + } + + _ => panic!("Not possible"), + }; + + return Ok(IfElse::new(condition, expressions, else_branch)); + } + + self.primary() + } + fn primary(&mut self) -> Result, ParserError> { let (i, token) = if let Some(Token(i, token)) = self.tokens.next() { (i, token) @@ -438,6 +501,9 @@ impl<'a> Parser<'a> { TokenType::Identifier(string) => Ok(Rc::new( Symbol::new_from_str(string, self.environment).into(), )), + TokenType::True => Ok(Rc::new(Bool::True.into())), + TokenType::False => Ok(Rc::new(Bool::False.into())), + TokenType::LParen => { let expr = self.expression()?; let (i, t) = if let Some(Token(i, x)) = self.tokens.peek() { @@ -450,14 +516,14 @@ impl<'a> Parser<'a> { match t { TokenType::RParen => { - self.tokens.next(); + self.consume(); Ok(expr) } TokenType::Comma => { let mut values = vec![expr]; while { if let Some(Token(_, TokenType::RParen)) = self.tokens.peek() { - self.tokens.next(); + self.consume(); false } else { true @@ -472,7 +538,7 @@ impl<'a> Parser<'a> { }; if *token == TokenType::Comma { - self.tokens.next(); + self.consume(); } else { return Err(ParserError::UnexpectedToken( *i,