diff --git a/src/ast/lexer.rs b/src/ast/lexer.rs index 096631f..384c974 100644 --- a/src/ast/lexer.rs +++ b/src/ast/lexer.rs @@ -1,4 +1,5 @@ use crate::ast::node::Node; +use crate::context::{Context, Contextual}; struct Token { position: usize, @@ -39,16 +40,16 @@ impl Lexer { self.line = 1; } - pub fn peek(&mut self, lookahead: i32) -> Option { + pub fn peek(&mut self, lookahead: i32) -> Option> { let cursor = self.cursor; let line = self.line; - let mut node: Option = None; + let mut node: Option> = None; for _ in 0..=lookahead { node = self.next(); } - + self.cursor = cursor; self.line = line; node @@ -61,7 +62,7 @@ impl Lexer { return true; } - return c.is_whitespace(); + c.is_whitespace() } fn is_sep(&self, pos: usize) -> bool { @@ -85,7 +86,7 @@ impl Lexer { break; } - if !c.is_ascii_alphabetic() && c != '_' + if !c.is_ascii_alphabetic() && c != '_' && !c.is_digit(10) { break; } @@ -300,7 +301,7 @@ impl Lexer { } impl Iterator for Lexer { - type Item = Node; + type Item = Contextual; fn next(&mut self) -> Option { self.skip_spaces(); @@ -308,66 +309,70 @@ impl Iterator for Lexer { if let Some(token) = self.scan_text("+=") { self.cursor = token.position; - return Some(Node::AssignAdd); + return Some(Contextual(Node::AssignAdd, Context(self.line))); } if let Some(token) = self.scan_text("?=") { self.cursor = token.position; - return Some(Node::AssignIf); + return Some(Contextual(Node::AssignIf, Context(self.line))); } if let Some(token) = self.scan_text("=") { self.cursor = token.position; - return Some(Node::Assign); + return Some(Contextual(Node::Assign, Context(self.line))); } if let Some(token) = self.scan_text("[") { self.cursor = token.position; - return Some(Node::OSquare); + return Some(Contextual(Node::OSquare, Context(self.line))) } if let Some(token) = self.scan_text("]") { self.cursor = token.position; - return Some(Node::CSquare); + return Some(Contextual(Node::CSquare, Context(self.line))) } if let Some(token) = self.scan_keyword("true") { self.cursor = token.position; - return Some(Node::Bool(token.value == "true")); + return Some(Contextual(Node::Bool(token.value == "true"), + Context(self.line))) } if let Some(token) = self.scan_keyword("false") { self.cursor = token.position; - return Some(Node::Bool(token.value == "true")); + return Some(Contextual(Node::Bool(token.value == "true"), + Context(self.line))) } if let Some(token) = self.scan_text(";") { self.cursor = token.position; - return Some(Node::Semicolon); + return Some(Contextual(Node::Semicolon, Context(self.line))) } if let Some(token) = self.scan_string() { self.cursor = token.position; - return Some(Node::String(token.value.clone())); + return Some(Contextual(Node::String(token.value.clone()), + Context(self.line))) } if let Some(token) = self.scan_float() { if let Ok(val) = token.value.parse::() { self.cursor = token.position; - return Some(Node::Float(val)); + return Some(Contextual(Node::Float(val), Context(self.line))) } } if let Some(token) = self.scan_int() { if let Ok(val) = token.value.parse::() { self.cursor = token.position; - return Some(Node::Int(val)); + return Some(Contextual(Node::Int(val), Context(self.line))) } } if let Some(token) = self.scan_identifier() { self.cursor = token.position; - return Some(Node::Ident(token.value.clone())); + return Some(Contextual(Node::Ident(token.value.clone()), + Context(self.line))) } None @@ -380,7 +385,8 @@ mod test { use crate::ast::error; use crate::ast::node::Node; - fn lexer_run(lexer: &mut Lexer, text: &str) -> Result, error::AstError> { + fn lexer_run(lexer: &mut Lexer, text: &str) + -> Result>, error::AstError> { lexer.prepare(text); let result = lexer.collect(); @@ -407,8 +413,8 @@ mod test { let mut lex = Lexer::new(); let res = lexer_run(&mut lex, "true false").unwrap(); assert_eq!(2, res.len()); - assert_eq!(Node::Bool(true), *res.get(0).unwrap()); - assert_eq!(Node::Bool(false), *res.get(1).unwrap()); + assert_eq!(Node::Bool(true), res.get(0).unwrap().0); + assert_eq!(Node::Bool(false), res.get(1).unwrap().0); } #[test] @@ -416,8 +422,8 @@ mod test { let mut lex = Lexer::new(); let res = lexer_run(&mut lex, "true;").unwrap(); assert_eq!(2, res.len()); - assert_eq!(Node::Bool(true), *res.get(0).unwrap()); - assert_eq!(Node::Semicolon, *res.get(1).unwrap()); + assert_eq!(Node::Bool(true), res.get(0).unwrap().0); + assert_eq!(Node::Semicolon, res.get(1).unwrap().0); } #[test] @@ -425,8 +431,8 @@ mod test { let mut lex = Lexer::new(); let res = lexer_run(&mut lex, " truea atrue ").unwrap(); assert_eq!(2, res.len()); - assert_eq!(Node::Ident(String::from("truea")), *res.get(0).unwrap()); - assert_eq!(Node::Ident(String::from("atrue")), *res.get(1).unwrap()); + assert_eq!(Node::Ident(String::from("truea")), res.get(0).unwrap().0); + assert_eq!(Node::Ident(String::from("atrue")), res.get(1).unwrap().0); } #[test] @@ -441,8 +447,8 @@ mod test { let mut lex = Lexer::new(); let res = lexer_run(&mut lex, " ;; ")?; assert_eq!(2, res.len()); - assert_eq!(Node::Semicolon, *res.get(0).unwrap()); - assert_eq!(Node::Semicolon, *res.get(1).unwrap()); + assert_eq!(Node::Semicolon, res.get(0).unwrap().0); + assert_eq!(Node::Semicolon, res.get(1).unwrap().0); Ok(()) } @@ -451,9 +457,9 @@ mod test { let mut lex = Lexer::new(); let res = lexer_run(&mut lex, " 4 -2 328")?; assert_eq!(3, res.len()); - assert_eq!(Node::Int(4), *res.get(0).unwrap()); - assert_eq!(Node::Int(-2), *res.get(1).unwrap()); - assert_eq!(Node::Int(328), *res.get(2).unwrap()); + assert_eq!(Node::Int(4), res.get(0).unwrap().0); + assert_eq!(Node::Int(-2), res.get(1).unwrap().0); + assert_eq!(Node::Int(328), res.get(2).unwrap().0); Ok(()) } @@ -463,10 +469,10 @@ mod test { let mut lex = Lexer::new(); let res = lexer_run(&mut lex, " 2.0 .7 5. -3.14 ")?; assert_eq!(4, res.len()); - assert_eq!(Node::Float(2.0), *res.get(0).unwrap()); - assert_eq!(Node::Float(0.7), *res.get(1).unwrap()); - assert_eq!(Node::Float(5.0), *res.get(2).unwrap()); - assert_eq!(Node::Float(-3.14), *res.get(3).unwrap()); + assert_eq!(Node::Float(2.0), res.get(0).unwrap().0); + assert_eq!(Node::Float(0.7), res.get(1).unwrap().0); + assert_eq!(Node::Float(5.0), res.get(2).unwrap().0); + assert_eq!(Node::Float(-3.14), res.get(3).unwrap().0); Ok(()) } @@ -480,7 +486,7 @@ mod test { assert_eq!(1, res.len()); assert_eq!(Node::String(String::from("s\ta\"lut\n")), - *res.get(0).unwrap()); + res.get(0).unwrap().0); Ok(()) } @@ -494,7 +500,7 @@ mod test { assert_eq!(1, res.len()); assert_eq!(Node::Int(4), - *res.get(0).unwrap()); + res.get(0).unwrap().0); Ok(()) } @@ -507,8 +513,8 @@ mod test { " [ ] ")?; assert_eq!(2, res.len()); - assert_eq!(Node::OSquare, *res.get(0).unwrap()); - assert_eq!(Node::CSquare, *res.get(1).unwrap()); + assert_eq!(Node::OSquare, res.get(0).unwrap().0); + assert_eq!(Node::CSquare, res.get(1).unwrap().0); Ok(()) } @@ -521,10 +527,10 @@ mod test { " = ?= += ananas ")?; assert_eq!(4, res.len()); - assert_eq!(Node::Assign, *res.get(0).unwrap()); - assert_eq!(Node::AssignIf, *res.get(1).unwrap()); - assert_eq!(Node::AssignAdd, *res.get(2).unwrap()); - assert_eq!(Node::Ident(String::from("ananas")), *res.get(3).unwrap()); + assert_eq!(Node::Assign, res.get(0).unwrap().0); + assert_eq!(Node::AssignIf, res.get(1).unwrap().0); + assert_eq!(Node::AssignAdd, res.get(2).unwrap().0); + assert_eq!(Node::Ident(String::from("ananas")), res.get(3).unwrap().0); Ok(()) } diff --git a/src/ast/node.rs b/src/ast/node.rs index 10d707c..47df0f8 100644 --- a/src/ast/node.rs +++ b/src/ast/node.rs @@ -1,20 +1,22 @@ +use crate::context::Contextual; + #[derive(Debug)] #[derive(PartialEq)] pub enum Node { - Module(String, Vec), + Module(String, Vec>), Bool(bool), Int(i32), Float(f64), String(String), OSquare, CSquare, - Array(Vec), + Array(Vec>), Assign, AssignIf, AssignAdd, - AssignInstr(Box, Vec), - AssignIfInstr(Box, Vec), - AssignAddInstr(Box, Vec), + AssignInstr(Contextual>, Vec>), + AssignIfInstr(Contextual>, Vec>), + AssignAddInstr(Contextual>, Vec>), Ident(String), Semicolon } diff --git a/src/ast/parser.rs b/src/ast/parser.rs index 1c106e1..2bc8b22 100644 --- a/src/ast/parser.rs +++ b/src/ast/parser.rs @@ -4,12 +4,14 @@ use crate::ast::{ error }; +use crate::context::{Contextual, Context}; + pub struct Parser { module_name: String, lexer: lexer::Lexer } -type ParseResult = Result, error::AstError>; +type ParseResult = Result>, error::AstError>; impl Parser { pub fn new(module_name: &str, lex: lexer::Lexer) -> Self { @@ -24,7 +26,7 @@ impl Parser { } fn parse_module(&mut self) -> ParseResult { - let mut children: Vec = vec![]; + let mut children: Vec> = vec![]; loop { match self.parse_instr() { @@ -42,13 +44,13 @@ impl Parser { } let n = Node::Module(self.module_name.clone(), children); - Ok(Some(n)) + Ok(Some(Contextual(n, Context(self.lexer.line())))) } fn ensure_semicolon(&mut self, result: ParseResult) -> ParseResult { match self.lexer.next() { - Some(Node::Semicolon) => result, + Some(Contextual(Node::Semicolon, _)) => result, _ => Err(error::AstError { msg: String::from("missing semicolon"), line: self.lexer.line()}) @@ -57,17 +59,17 @@ impl Parser { fn parse_instr(&mut self) -> ParseResult { match self.lexer.peek(1) { - Some(Node::Assign) => { + Some(Contextual(Node::Assign, _)) => { let assign = self.parse_assign(); self.ensure_semicolon(assign) }, - Some(Node::AssignIf) => { + Some(Contextual(Node::AssignIf, _)) => { let assign = self.parse_assign_if(); self.ensure_semicolon(assign) }, - Some(Node::AssignAdd) => { + Some(Contextual(Node::AssignAdd, _)) => { let assign = self.parse_assign_add(); self.ensure_semicolon(assign) }, @@ -83,15 +85,15 @@ impl Parser { } fn assign_helper(&mut self) - -> Result<(Box, Vec), error::AstError> { - let mut rhs: Vec = vec![]; + -> Result<(Contextual, Vec>), error::AstError> { + let mut rhs: Vec> = vec![]; - if let Some(Node::Ident(value)) = self.lexer.next() { + if let Some(Contextual(Node::Ident(value), ctx)) = self.lexer.next() { let _assign = self.lexer.next(); loop { match self.lexer.peek(0) { - Some(Node::Semicolon) | None => { + Some(Contextual(Node::Semicolon, _)) | None => { break; }, @@ -99,7 +101,7 @@ impl Parser { } } - Ok((Box::new(Node::Ident(value)), rhs)) + Ok((Contextual(Node::Ident(value), ctx), rhs)) } else { Err(error::AstError { @@ -111,24 +113,33 @@ impl Parser { fn parse_assign(&mut self) -> ParseResult { match self.assign_helper() { - Ok((lhs, rhs)) - => Ok(Some(Node::AssignInstr(lhs, rhs))), + Ok((Contextual(lhs, ctx), rhs)) + => Ok(Some(Contextual( + Node::AssignInstr(Contextual(Box::new(lhs), ctx), rhs), + ctx + ))), Err(err) => Err(err) } } fn parse_assign_if(&mut self) -> ParseResult { match self.assign_helper() { - Ok((lhs, rhs)) - => Ok(Some(Node::AssignIfInstr(lhs, rhs))), + Ok((Contextual(lhs, ctx), rhs)) + => Ok(Some(Contextual( + Node::AssignIfInstr(Contextual(Box::new(lhs), ctx), rhs), + ctx)) + ), Err(err) => Err(err) } } fn parse_assign_add(&mut self) -> ParseResult { match self.assign_helper() { - Ok((lhs, rhs)) - => Ok(Some(Node::AssignAddInstr(lhs, rhs))), + Ok((Contextual(lhs, ctx), rhs)) + => Ok(Some( + Contextual(Node::AssignAddInstr( + Contextual(Box::new(lhs), ctx), + rhs), ctx))), Err(err) => Err(err) } } @@ -139,9 +150,12 @@ impl Parser { fn parse_literal(&mut self) -> ParseResult { match self.lexer.peek(0) { - Some(Node::Ident(id)) - => { self.lexer.next(); Ok(Some(Node::Ident(id))) }, - Some(Node::OSquare) => self.parse_array(), + Some(Contextual(Node::Ident(id), ctx)) + => { + self.lexer.next(); + Ok(Some(Contextual(Node::Ident(id), ctx))) + }, + Some(Contextual(Node::OSquare, _)) => self.parse_array(), Some(_) => self.parse_builtin(), None => { self.lexer.next(); Ok(None) } } @@ -150,18 +164,18 @@ impl Parser { fn parse_builtin(&mut self) -> ParseResult { let node = self.lexer.next().unwrap(); match node { - Node::Int(value) - => Ok(Some(Node::Int(value))), + Contextual(Node::Int(value), ctx) + => Ok(Some(Contextual(Node::Int(value), ctx))), - Node::Float(value) - => Ok(Some(Node::Float(value))), + Contextual(Node::Float(value), ctx) + => Ok(Some(Contextual(Node::Float(value), ctx))), - Node::Bool(value) - => Ok(Some(Node::Bool(value))), - Node::String(value) - => Ok(Some(Node::String(value))), + Contextual(Node::Bool(value), ctx) + => Ok(Some(Contextual(Node::Bool(value), ctx))), + Contextual(Node::String(value), ctx) + => Ok(Some(Contextual(Node::String(value), ctx))), _ => { Err(error::AstError { msg: String::from(format!("unexpected {:?}", node)), @@ -172,7 +186,7 @@ impl Parser { } fn parse_array(&mut self) -> ParseResult { - let mut elements: Vec = vec![]; + let mut elements: Vec> = vec![]; let _osquare = self.lexer.next(); @@ -180,7 +194,12 @@ impl Parser { elements.push(expr); } - Ok(Some(Node::Array(elements))) + let mut ctx = Context(0); + if let Some(Contextual(_, c)) = elements.last() { + ctx.0 = c.0; + } + + Ok(Some(Contextual(Node::Array(elements), ctx))) } } @@ -196,7 +215,7 @@ mod test { let mut parser = Parser::new("mod", lex); match parser.run() { - Ok(Some(root)) => { + Ok(Some(Contextual(root, _))) => { if root == oracle { Ok(()) } else { @@ -225,15 +244,15 @@ mod test { fn simple_booleans() -> TestResult { test_parser( Node::Module("mod".to_owned(), vec![ - Node::Bool(true) + Contextual(Node::Bool(true), Context(0)) ]), " true; " )?; test_parser( Node::Module("mod".to_owned(), vec![ - Node::Bool(true), - Node::Bool(false) + Contextual(Node::Bool(true), Context(0)), + Contextual(Node::Bool(false), Context(0)) ]), " true; false; " )?; @@ -245,14 +264,14 @@ mod test { fn numbers() -> TestResult { test_parser( Node::Module("mod".to_owned(), vec![ - Node::Float(27.3) + Contextual(Node::Float(27.3), Context(0)) ]), " 27.3; " )?; test_parser( Node::Module("mod".to_owned(), vec![ - Node::Int(-27) + Contextual(Node::Int(-27), Context(0)) ]), " -27; " )?; @@ -264,7 +283,7 @@ mod test { fn strings() -> TestResult { test_parser( Node::Module("mod".to_owned(), vec![ - Node::String(String::from("pizza! ")) + Contextual(Node::String(String::from("pizza! ")), Context(0)) ]), " \"pizza! \"; " )?; @@ -276,36 +295,45 @@ mod test { fn assign_variables() -> TestResult { test_parser( Node::Module("mod".to_owned(), vec![ - Node::AssignInstr( - Box::new(Node::Ident(String::from("HELLO"))), - vec![Node::Int(4), Node::Bool(true)] - ) + Contextual(Node::AssignInstr( + Contextual( + Box::new(Node::Ident(String::from("HELLO"))), + Context(0)), + vec![ + Contextual(Node::Int(4), Context(0)), + Contextual(Node::Bool(true), Context(0)) + ] + ), Context(0)) ]), " HELLO = 4 true; " )?; test_parser( Node::Module("mod".to_owned(), vec![ - Node::AssignIfInstr( - Box::new(Node::Ident(String::from("HELLO_2"))), - vec![Node::Int(4)] - ) + Contextual(Node::AssignIfInstr( + Contextual( + Box::new(Node::Ident(String::from("HELLO_2"))), + Context(0) + ), + vec![Contextual(Node::Int(4), Context(0))] + ), Context(0)) ]), " HELLO_2 ?= 4; " )?; test_parser( Node::Module("mod".to_owned(), vec![ - Node::AssignAddInstr( - Box::new(Node::Ident( - String::from("HELLO_WORLD")) + Contextual(Node::AssignAddInstr( + Contextual( + Box::new(Node::Ident(String::from("HELLO_WORLD"))), + Context(0) ), vec![ - Node::Int(4), - Node::Int(1), - Node::Int(2) + Contextual(Node::Int(4), Context(0)), + Contextual(Node::Int(1), Context(0)), + Contextual(Node::Int(2), Context(0)) ] - ) + ), Context(0)) ]), " HELLO_WORLD += 4 1 2; " )?; @@ -315,11 +343,11 @@ mod test { fn arrays() -> TestResult { test_parser( Node::Module("mod".to_owned(), vec![ - Node::Array(vec![ - Node::Int(2), - Node::Float(3.2), - Node::Bool(true) - ]) + Contextual(Node::Array(vec![ + Contextual(Node::Int(2), Context(0)), + Contextual(Node::Float(3.2), Context(0)), + Contextual(Node::Bool(true), Context(0)) + ]), Context(0)) ]), " [2 3.2 true]; " )?; diff --git a/src/context.rs b/src/context.rs new file mode 100644 index 0000000..af66105 --- /dev/null +++ b/src/context.rs @@ -0,0 +1,14 @@ +#[derive(Debug)] +#[derive(PartialEq)] +#[derive(Clone)] +#[derive(Copy)] +pub struct Context(pub i32); + +#[derive(Debug)] +pub struct Contextual(pub T, pub Context); + +impl PartialEq> for Contextual { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} diff --git a/src/eval/evaluator.rs b/src/eval/evaluator.rs index 6fe5532..3f09987 100644 --- a/src/eval/evaluator.rs +++ b/src/eval/evaluator.rs @@ -1,4 +1,5 @@ use crate::{ + context::Contextual, ast::node::Node, eval::{ value::Value, @@ -20,37 +21,37 @@ impl Evaluator { } } - pub fn run(&mut self, root: &Node) -> EvalResult { - match root { + pub fn run(&mut self, root: &Contextual) -> EvalResult { + match &root.0 { Node::Module(_, nodes) => { let mut res = None; for node in nodes.iter() { - res = self.run(&node)? + res = self.run(node)? } Ok(res) }, Node::Ident(name) => { - match self.table.get(name) { + match self.table.get(&name) { Some(val) => { Ok(Some(val)) }, None => Err(EvalError { msg: format!("cannot find <{}>", name), - line: 0 + line: root.1.0 }) } }, Node::AssignAddInstr(target, values) => { - match &**target { + match &*target.0 { Node::Ident(name) => { let mut val_array: Vec = vec![]; - match self.table.get(name) { + match self.table.get(&name) { Some(Value::Array(existing_arr)) => { val_array = existing_arr; }, @@ -62,14 +63,14 @@ impl Evaluator { } for node_val in values { - let val = self.run(node_val)?; + let val = self.run(&node_val)?; if let Some(v) = val { val_array.push(v); } } let value = Value::Array(val_array); - self.table.set(name, value); + self.table.set(&name, value); }, _ => { return Err(EvalError { @@ -77,7 +78,7 @@ impl Evaluator { "cannot assign to target <{:?}>", target ), - line: 0 + line: root.1.0 }); } } @@ -86,14 +87,14 @@ impl Evaluator { }, Node::AssignIfInstr(target, values) => { - match &**target { + match &*target.0 { Node::Ident(name) => { - match self.table.get(name) { + match self.table.get(&name) { Some(_) => {}, None => { if let Some(value) - = self.nodes_to_value(values)? { - self.table.set(name, value); + = self.nodes_to_value(&values)? { + self.table.set(&name, value); } } } @@ -104,7 +105,8 @@ impl Evaluator { "cannot assign to target <{:?}>", target ), - line: 0 + line: root.1.0 + }); } } @@ -113,10 +115,10 @@ impl Evaluator { }, Node::AssignInstr(target, values) => { - match &**target { + match &*target.0 { Node::Ident(name) => { - if let Some(value) = self.nodes_to_value(values)? { - self.table.set(name, value); + if let Some(value) = self.nodes_to_value(&values)? { + self.table.set(&name, value); } }, _ => { @@ -125,7 +127,8 @@ impl Evaluator { "cannot assign to target <{:?}>", target ), - line: 0 + line: root.1.0 + }); } } @@ -142,7 +145,7 @@ impl Evaluator { let mut values: Vec = vec![]; for node in nodes { - match self.run(node) { + match self.run(&node) { Ok(Some(value)) => { values.push(value); }, @@ -150,7 +153,8 @@ impl Evaluator { _ => { return Err(EvalError { msg: String::from("invalid array element"), - line: 0 + line: root.1.0 + }); } } @@ -163,11 +167,11 @@ impl Evaluator { } } - fn nodes_to_value(&mut self, nodes: &Vec) -> EvalResult { + fn nodes_to_value(&mut self, nodes: &Vec>) -> EvalResult { let mut val_array: Vec = vec![]; for node in nodes { - match self.run(node) { + match self.run(&node) { Ok(Some(val)) => val_array.push(val), Ok(None) => {}, Err(err) => { return Err(err); } @@ -209,7 +213,8 @@ mod test { if val != value { Err(Box::new(EvalError { msg: format!("expected: {:?}, got: {:?}", value, val), - line: 0 + line: root.1.0 + })) } else { Ok(()) @@ -217,7 +222,8 @@ mod test { } else { Err(Box::new(EvalError { msg: format!("unexpected: {:?}", value), - line: 0 + line: root.1.0 + })) } }, @@ -238,7 +244,8 @@ mod test { Err(_) => Ok(()), _ => Err(Box::new(EvalError { msg: format!("\"{}\" should fail", source), - line: 0 + line: root.1.0 + })) } } diff --git a/src/main.rs b/src/main.rs index 8506845..b019526 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ use std::fs; mod ast; mod eval; +mod context; fn main() -> Result<(), Box> { let args: Vec = std::env::args().collect();