🐛 line numbers in error messages.

main
bog 2024-03-02 12:42:28 +01:00
parent 3811b2ddb2
commit c45b885dc5
6 changed files with 189 additions and 131 deletions

View File

@ -1,4 +1,5 @@
use crate::ast::node::Node; use crate::ast::node::Node;
use crate::context::{Context, Contextual};
struct Token { struct Token {
position: usize, position: usize,
@ -39,11 +40,11 @@ impl Lexer {
self.line = 1; self.line = 1;
} }
pub fn peek(&mut self, lookahead: i32) -> Option<Node> { pub fn peek(&mut self, lookahead: i32) -> Option<Contextual<Node>> {
let cursor = self.cursor; let cursor = self.cursor;
let line = self.line; let line = self.line;
let mut node: Option<Node> = None; let mut node: Option<Contextual<Node>> = None;
for _ in 0..=lookahead { for _ in 0..=lookahead {
node = self.next(); node = self.next();
@ -61,7 +62,7 @@ impl Lexer {
return true; return true;
} }
return c.is_whitespace(); c.is_whitespace()
} }
fn is_sep(&self, pos: usize) -> bool { fn is_sep(&self, pos: usize) -> bool {
@ -300,7 +301,7 @@ impl Lexer {
} }
impl Iterator for Lexer { impl Iterator for Lexer {
type Item = Node; type Item = Contextual<Node>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.skip_spaces(); self.skip_spaces();
@ -308,66 +309,70 @@ impl Iterator for Lexer {
if let Some(token) = self.scan_text("+=") { if let Some(token) = self.scan_text("+=") {
self.cursor = token.position; self.cursor = token.position;
return Some(Node::AssignAdd); return Some(Contextual(Node::AssignAdd, Context(self.line)));
} }
if let Some(token) = self.scan_text("?=") { if let Some(token) = self.scan_text("?=") {
self.cursor = token.position; self.cursor = token.position;
return Some(Node::AssignIf); return Some(Contextual(Node::AssignIf, Context(self.line)));
} }
if let Some(token) = self.scan_text("=") { if let Some(token) = self.scan_text("=") {
self.cursor = token.position; self.cursor = token.position;
return Some(Node::Assign); return Some(Contextual(Node::Assign, Context(self.line)));
} }
if let Some(token) = self.scan_text("[") { if let Some(token) = self.scan_text("[") {
self.cursor = token.position; self.cursor = token.position;
return Some(Node::OSquare); return Some(Contextual(Node::OSquare, Context(self.line)))
} }
if let Some(token) = self.scan_text("]") { if let Some(token) = self.scan_text("]") {
self.cursor = token.position; self.cursor = token.position;
return Some(Node::CSquare); return Some(Contextual(Node::CSquare, Context(self.line)))
} }
if let Some(token) = self.scan_keyword("true") { if let Some(token) = self.scan_keyword("true") {
self.cursor = token.position; 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") { if let Some(token) = self.scan_keyword("false") {
self.cursor = token.position; 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(";") { if let Some(token) = self.scan_text(";") {
self.cursor = token.position; self.cursor = token.position;
return Some(Node::Semicolon); return Some(Contextual(Node::Semicolon, Context(self.line)))
} }
if let Some(token) = self.scan_string() { if let Some(token) = self.scan_string() {
self.cursor = token.position; 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 Some(token) = self.scan_float() {
if let Ok(val) = token.value.parse::<f64>() { if let Ok(val) = token.value.parse::<f64>() {
self.cursor = token.position; 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 Some(token) = self.scan_int() {
if let Ok(val) = token.value.parse::<i32>() { if let Ok(val) = token.value.parse::<i32>() {
self.cursor = token.position; 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() { if let Some(token) = self.scan_identifier() {
self.cursor = token.position; self.cursor = token.position;
return Some(Node::Ident(token.value.clone())); return Some(Contextual(Node::Ident(token.value.clone()),
Context(self.line)))
} }
None None
@ -380,7 +385,8 @@ mod test {
use crate::ast::error; use crate::ast::error;
use crate::ast::node::Node; use crate::ast::node::Node;
fn lexer_run(lexer: &mut Lexer, text: &str) -> Result<Vec<Node>, error::AstError> { fn lexer_run(lexer: &mut Lexer, text: &str)
-> Result<Vec<Contextual<Node>>, error::AstError> {
lexer.prepare(text); lexer.prepare(text);
let result = lexer.collect(); let result = lexer.collect();
@ -407,8 +413,8 @@ mod test {
let mut lex = Lexer::new(); let mut lex = Lexer::new();
let res = lexer_run(&mut lex, "true false").unwrap(); let res = lexer_run(&mut lex, "true false").unwrap();
assert_eq!(2, res.len()); assert_eq!(2, res.len());
assert_eq!(Node::Bool(true), *res.get(0).unwrap()); assert_eq!(Node::Bool(true), res.get(0).unwrap().0);
assert_eq!(Node::Bool(false), *res.get(1).unwrap()); assert_eq!(Node::Bool(false), res.get(1).unwrap().0);
} }
#[test] #[test]
@ -416,8 +422,8 @@ mod test {
let mut lex = Lexer::new(); let mut lex = Lexer::new();
let res = lexer_run(&mut lex, "true;").unwrap(); let res = lexer_run(&mut lex, "true;").unwrap();
assert_eq!(2, res.len()); assert_eq!(2, res.len());
assert_eq!(Node::Bool(true), *res.get(0).unwrap()); assert_eq!(Node::Bool(true), res.get(0).unwrap().0);
assert_eq!(Node::Semicolon, *res.get(1).unwrap()); assert_eq!(Node::Semicolon, res.get(1).unwrap().0);
} }
#[test] #[test]
@ -425,8 +431,8 @@ mod test {
let mut lex = Lexer::new(); let mut lex = Lexer::new();
let res = lexer_run(&mut lex, " truea atrue ").unwrap(); let res = lexer_run(&mut lex, " truea atrue ").unwrap();
assert_eq!(2, res.len()); assert_eq!(2, res.len());
assert_eq!(Node::Ident(String::from("truea")), *res.get(0).unwrap()); assert_eq!(Node::Ident(String::from("truea")), res.get(0).unwrap().0);
assert_eq!(Node::Ident(String::from("atrue")), *res.get(1).unwrap()); assert_eq!(Node::Ident(String::from("atrue")), res.get(1).unwrap().0);
} }
#[test] #[test]
@ -441,8 +447,8 @@ mod test {
let mut lex = Lexer::new(); let mut lex = Lexer::new();
let res = lexer_run(&mut lex, " ;; ")?; let res = lexer_run(&mut lex, " ;; ")?;
assert_eq!(2, res.len()); assert_eq!(2, res.len());
assert_eq!(Node::Semicolon, *res.get(0).unwrap()); assert_eq!(Node::Semicolon, res.get(0).unwrap().0);
assert_eq!(Node::Semicolon, *res.get(1).unwrap()); assert_eq!(Node::Semicolon, res.get(1).unwrap().0);
Ok(()) Ok(())
} }
@ -451,9 +457,9 @@ mod test {
let mut lex = Lexer::new(); let mut lex = Lexer::new();
let res = lexer_run(&mut lex, " 4 -2 328")?; let res = lexer_run(&mut lex, " 4 -2 328")?;
assert_eq!(3, res.len()); assert_eq!(3, res.len());
assert_eq!(Node::Int(4), *res.get(0).unwrap()); assert_eq!(Node::Int(4), res.get(0).unwrap().0);
assert_eq!(Node::Int(-2), *res.get(1).unwrap()); assert_eq!(Node::Int(-2), res.get(1).unwrap().0);
assert_eq!(Node::Int(328), *res.get(2).unwrap()); assert_eq!(Node::Int(328), res.get(2).unwrap().0);
Ok(()) Ok(())
} }
@ -463,10 +469,10 @@ mod test {
let mut lex = Lexer::new(); let mut lex = Lexer::new();
let res = lexer_run(&mut lex, " 2.0 .7 5. -3.14 ")?; let res = lexer_run(&mut lex, " 2.0 .7 5. -3.14 ")?;
assert_eq!(4, res.len()); assert_eq!(4, res.len());
assert_eq!(Node::Float(2.0), *res.get(0).unwrap()); assert_eq!(Node::Float(2.0), res.get(0).unwrap().0);
assert_eq!(Node::Float(0.7), *res.get(1).unwrap()); assert_eq!(Node::Float(0.7), res.get(1).unwrap().0);
assert_eq!(Node::Float(5.0), *res.get(2).unwrap()); assert_eq!(Node::Float(5.0), res.get(2).unwrap().0);
assert_eq!(Node::Float(-3.14), *res.get(3).unwrap()); assert_eq!(Node::Float(-3.14), res.get(3).unwrap().0);
Ok(()) Ok(())
} }
@ -480,7 +486,7 @@ mod test {
assert_eq!(1, res.len()); assert_eq!(1, res.len());
assert_eq!(Node::String(String::from("s\ta\"lut\n")), assert_eq!(Node::String(String::from("s\ta\"lut\n")),
*res.get(0).unwrap()); res.get(0).unwrap().0);
Ok(()) Ok(())
} }
@ -494,7 +500,7 @@ mod test {
assert_eq!(1, res.len()); assert_eq!(1, res.len());
assert_eq!(Node::Int(4), assert_eq!(Node::Int(4),
*res.get(0).unwrap()); res.get(0).unwrap().0);
Ok(()) Ok(())
} }
@ -507,8 +513,8 @@ mod test {
" [ ] ")?; " [ ] ")?;
assert_eq!(2, res.len()); assert_eq!(2, res.len());
assert_eq!(Node::OSquare, *res.get(0).unwrap()); assert_eq!(Node::OSquare, res.get(0).unwrap().0);
assert_eq!(Node::CSquare, *res.get(1).unwrap()); assert_eq!(Node::CSquare, res.get(1).unwrap().0);
Ok(()) Ok(())
} }
@ -521,10 +527,10 @@ mod test {
" = ?= += ananas ")?; " = ?= += ananas ")?;
assert_eq!(4, res.len()); assert_eq!(4, res.len());
assert_eq!(Node::Assign, *res.get(0).unwrap()); assert_eq!(Node::Assign, res.get(0).unwrap().0);
assert_eq!(Node::AssignIf, *res.get(1).unwrap()); assert_eq!(Node::AssignIf, res.get(1).unwrap().0);
assert_eq!(Node::AssignAdd, *res.get(2).unwrap()); assert_eq!(Node::AssignAdd, res.get(2).unwrap().0);
assert_eq!(Node::Ident(String::from("ananas")), *res.get(3).unwrap()); assert_eq!(Node::Ident(String::from("ananas")), res.get(3).unwrap().0);
Ok(()) Ok(())
} }

View File

@ -1,20 +1,22 @@
use crate::context::Contextual;
#[derive(Debug)] #[derive(Debug)]
#[derive(PartialEq)] #[derive(PartialEq)]
pub enum Node { pub enum Node {
Module(String, Vec<Node>), Module(String, Vec<Contextual<Node>>),
Bool(bool), Bool(bool),
Int(i32), Int(i32),
Float(f64), Float(f64),
String(String), String(String),
OSquare, OSquare,
CSquare, CSquare,
Array(Vec<Node>), Array(Vec<Contextual<Node>>),
Assign, Assign,
AssignIf, AssignIf,
AssignAdd, AssignAdd,
AssignInstr(Box<Node>, Vec<Node>), AssignInstr(Contextual<Box<Node>>, Vec<Contextual<Node>>),
AssignIfInstr(Box<Node>, Vec<Node>), AssignIfInstr(Contextual<Box<Node>>, Vec<Contextual<Node>>),
AssignAddInstr(Box<Node>, Vec<Node>), AssignAddInstr(Contextual<Box<Node>>, Vec<Contextual<Node>>),
Ident(String), Ident(String),
Semicolon Semicolon
} }

View File

@ -4,12 +4,14 @@ use crate::ast::{
error error
}; };
use crate::context::{Contextual, Context};
pub struct Parser { pub struct Parser {
module_name: String, module_name: String,
lexer: lexer::Lexer lexer: lexer::Lexer
} }
type ParseResult = Result<Option<Node>, error::AstError>; type ParseResult = Result<Option<Contextual<Node>>, error::AstError>;
impl Parser { impl Parser {
pub fn new(module_name: &str, lex: lexer::Lexer) -> Self { pub fn new(module_name: &str, lex: lexer::Lexer) -> Self {
@ -24,7 +26,7 @@ impl Parser {
} }
fn parse_module(&mut self) -> ParseResult { fn parse_module(&mut self) -> ParseResult {
let mut children: Vec<Node> = vec![]; let mut children: Vec<Contextual<Node>> = vec![];
loop { loop {
match self.parse_instr() { match self.parse_instr() {
@ -42,13 +44,13 @@ impl Parser {
} }
let n = Node::Module(self.module_name.clone(), children); 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) fn ensure_semicolon(&mut self, result: ParseResult)
-> ParseResult { -> ParseResult {
match self.lexer.next() { match self.lexer.next() {
Some(Node::Semicolon) => result, Some(Contextual(Node::Semicolon, _)) => result,
_ => Err(error::AstError { _ => Err(error::AstError {
msg: String::from("missing semicolon"), msg: String::from("missing semicolon"),
line: self.lexer.line()}) line: self.lexer.line()})
@ -57,17 +59,17 @@ impl Parser {
fn parse_instr(&mut self) -> ParseResult { fn parse_instr(&mut self) -> ParseResult {
match self.lexer.peek(1) { match self.lexer.peek(1) {
Some(Node::Assign) => { Some(Contextual(Node::Assign, _)) => {
let assign = self.parse_assign(); let assign = self.parse_assign();
self.ensure_semicolon(assign) self.ensure_semicolon(assign)
}, },
Some(Node::AssignIf) => { Some(Contextual(Node::AssignIf, _)) => {
let assign = self.parse_assign_if(); let assign = self.parse_assign_if();
self.ensure_semicolon(assign) self.ensure_semicolon(assign)
}, },
Some(Node::AssignAdd) => { Some(Contextual(Node::AssignAdd, _)) => {
let assign = self.parse_assign_add(); let assign = self.parse_assign_add();
self.ensure_semicolon(assign) self.ensure_semicolon(assign)
}, },
@ -83,15 +85,15 @@ impl Parser {
} }
fn assign_helper(&mut self) fn assign_helper(&mut self)
-> Result<(Box<Node>, Vec<Node>), error::AstError> { -> Result<(Contextual<Node>, Vec<Contextual<Node>>), error::AstError> {
let mut rhs: Vec<Node> = vec![]; let mut rhs: Vec<Contextual<Node>> = 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(); let _assign = self.lexer.next();
loop { loop {
match self.lexer.peek(0) { match self.lexer.peek(0) {
Some(Node::Semicolon) | None => { Some(Contextual(Node::Semicolon, _)) | None => {
break; break;
}, },
@ -99,7 +101,7 @@ impl Parser {
} }
} }
Ok((Box::new(Node::Ident(value)), rhs)) Ok((Contextual(Node::Ident(value), ctx), rhs))
} else { } else {
Err(error::AstError { Err(error::AstError {
@ -111,24 +113,33 @@ impl Parser {
fn parse_assign(&mut self) -> ParseResult { fn parse_assign(&mut self) -> ParseResult {
match self.assign_helper() { match self.assign_helper() {
Ok((lhs, rhs)) Ok((Contextual(lhs, ctx), rhs))
=> Ok(Some(Node::AssignInstr(lhs, rhs))), => Ok(Some(Contextual(
Node::AssignInstr(Contextual(Box::new(lhs), ctx), rhs),
ctx
))),
Err(err) => Err(err) Err(err) => Err(err)
} }
} }
fn parse_assign_if(&mut self) -> ParseResult { fn parse_assign_if(&mut self) -> ParseResult {
match self.assign_helper() { match self.assign_helper() {
Ok((lhs, rhs)) Ok((Contextual(lhs, ctx), rhs))
=> Ok(Some(Node::AssignIfInstr(lhs, rhs))), => Ok(Some(Contextual(
Node::AssignIfInstr(Contextual(Box::new(lhs), ctx), rhs),
ctx))
),
Err(err) => Err(err) Err(err) => Err(err)
} }
} }
fn parse_assign_add(&mut self) -> ParseResult { fn parse_assign_add(&mut self) -> ParseResult {
match self.assign_helper() { match self.assign_helper() {
Ok((lhs, rhs)) Ok((Contextual(lhs, ctx), rhs))
=> Ok(Some(Node::AssignAddInstr(lhs, rhs))), => Ok(Some(
Contextual(Node::AssignAddInstr(
Contextual(Box::new(lhs), ctx),
rhs), ctx))),
Err(err) => Err(err) Err(err) => Err(err)
} }
} }
@ -139,9 +150,12 @@ impl Parser {
fn parse_literal(&mut self) -> ParseResult { fn parse_literal(&mut self) -> ParseResult {
match self.lexer.peek(0) { match self.lexer.peek(0) {
Some(Node::Ident(id)) Some(Contextual(Node::Ident(id), ctx))
=> { self.lexer.next(); Ok(Some(Node::Ident(id))) }, => {
Some(Node::OSquare) => self.parse_array(), self.lexer.next();
Ok(Some(Contextual(Node::Ident(id), ctx)))
},
Some(Contextual(Node::OSquare, _)) => self.parse_array(),
Some(_) => self.parse_builtin(), Some(_) => self.parse_builtin(),
None => { self.lexer.next(); Ok(None) } None => { self.lexer.next(); Ok(None) }
} }
@ -150,18 +164,18 @@ impl Parser {
fn parse_builtin(&mut self) -> ParseResult { fn parse_builtin(&mut self) -> ParseResult {
let node = self.lexer.next().unwrap(); let node = self.lexer.next().unwrap();
match node { match node {
Node::Int(value) Contextual(Node::Int(value), ctx)
=> Ok(Some(Node::Int(value))), => Ok(Some(Contextual(Node::Int(value), ctx))),
Node::Float(value) Contextual(Node::Float(value), ctx)
=> Ok(Some(Node::Float(value))), => Ok(Some(Contextual(Node::Float(value), ctx))),
Node::Bool(value)
=> Ok(Some(Node::Bool(value))),
Node::String(value) Contextual(Node::Bool(value), ctx)
=> Ok(Some(Node::String(value))), => Ok(Some(Contextual(Node::Bool(value), ctx))),
Contextual(Node::String(value), ctx)
=> Ok(Some(Contextual(Node::String(value), ctx))),
_ => { _ => {
Err(error::AstError { Err(error::AstError {
msg: String::from(format!("unexpected {:?}", node)), msg: String::from(format!("unexpected {:?}", node)),
@ -172,7 +186,7 @@ impl Parser {
} }
fn parse_array(&mut self) -> ParseResult { fn parse_array(&mut self) -> ParseResult {
let mut elements: Vec<Node> = vec![]; let mut elements: Vec<Contextual<Node>> = vec![];
let _osquare = self.lexer.next(); let _osquare = self.lexer.next();
@ -180,7 +194,12 @@ impl Parser {
elements.push(expr); 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); let mut parser = Parser::new("mod", lex);
match parser.run() { match parser.run() {
Ok(Some(root)) => { Ok(Some(Contextual(root, _))) => {
if root == oracle { if root == oracle {
Ok(()) Ok(())
} else { } else {
@ -225,15 +244,15 @@ mod test {
fn simple_booleans() -> TestResult { fn simple_booleans() -> TestResult {
test_parser( test_parser(
Node::Module("mod".to_owned(), vec![ Node::Module("mod".to_owned(), vec![
Node::Bool(true) Contextual(Node::Bool(true), Context(0))
]), ]),
" true; " " true; "
)?; )?;
test_parser( test_parser(
Node::Module("mod".to_owned(), vec![ Node::Module("mod".to_owned(), vec![
Node::Bool(true), Contextual(Node::Bool(true), Context(0)),
Node::Bool(false) Contextual(Node::Bool(false), Context(0))
]), ]),
" true; false; " " true; false; "
)?; )?;
@ -245,14 +264,14 @@ mod test {
fn numbers() -> TestResult { fn numbers() -> TestResult {
test_parser( test_parser(
Node::Module("mod".to_owned(), vec![ Node::Module("mod".to_owned(), vec![
Node::Float(27.3) Contextual(Node::Float(27.3), Context(0))
]), ]),
" 27.3; " " 27.3; "
)?; )?;
test_parser( test_parser(
Node::Module("mod".to_owned(), vec![ Node::Module("mod".to_owned(), vec![
Node::Int(-27) Contextual(Node::Int(-27), Context(0))
]), ]),
" -27; " " -27; "
)?; )?;
@ -264,7 +283,7 @@ mod test {
fn strings() -> TestResult { fn strings() -> TestResult {
test_parser( test_parser(
Node::Module("mod".to_owned(), vec![ Node::Module("mod".to_owned(), vec![
Node::String(String::from("pizza! ")) Contextual(Node::String(String::from("pizza! ")), Context(0))
]), ]),
" \"pizza! \"; " " \"pizza! \"; "
)?; )?;
@ -276,36 +295,45 @@ mod test {
fn assign_variables() -> TestResult { fn assign_variables() -> TestResult {
test_parser( test_parser(
Node::Module("mod".to_owned(), vec![ Node::Module("mod".to_owned(), vec![
Node::AssignInstr( Contextual(Node::AssignInstr(
Contextual(
Box::new(Node::Ident(String::from("HELLO"))), Box::new(Node::Ident(String::from("HELLO"))),
vec![Node::Int(4), Node::Bool(true)] Context(0)),
) vec![
Contextual(Node::Int(4), Context(0)),
Contextual(Node::Bool(true), Context(0))
]
), Context(0))
]), ]),
" HELLO = 4 true; " " HELLO = 4 true; "
)?; )?;
test_parser( test_parser(
Node::Module("mod".to_owned(), vec![ Node::Module("mod".to_owned(), vec![
Node::AssignIfInstr( Contextual(Node::AssignIfInstr(
Contextual(
Box::new(Node::Ident(String::from("HELLO_2"))), Box::new(Node::Ident(String::from("HELLO_2"))),
vec![Node::Int(4)] Context(0)
) ),
vec![Contextual(Node::Int(4), Context(0))]
), Context(0))
]), ]),
" HELLO_2 ?= 4; " " HELLO_2 ?= 4; "
)?; )?;
test_parser( test_parser(
Node::Module("mod".to_owned(), vec![ Node::Module("mod".to_owned(), vec![
Node::AssignAddInstr( Contextual(Node::AssignAddInstr(
Box::new(Node::Ident( Contextual(
String::from("HELLO_WORLD")) Box::new(Node::Ident(String::from("HELLO_WORLD"))),
Context(0)
), ),
vec![ vec![
Node::Int(4), Contextual(Node::Int(4), Context(0)),
Node::Int(1), Contextual(Node::Int(1), Context(0)),
Node::Int(2) Contextual(Node::Int(2), Context(0))
] ]
) ), Context(0))
]), ]),
" HELLO_WORLD += 4 1 2; " " HELLO_WORLD += 4 1 2; "
)?; )?;
@ -315,11 +343,11 @@ mod test {
fn arrays() -> TestResult { fn arrays() -> TestResult {
test_parser( test_parser(
Node::Module("mod".to_owned(), vec![ Node::Module("mod".to_owned(), vec![
Node::Array(vec![ Contextual(Node::Array(vec![
Node::Int(2), Contextual(Node::Int(2), Context(0)),
Node::Float(3.2), Contextual(Node::Float(3.2), Context(0)),
Node::Bool(true) Contextual(Node::Bool(true), Context(0))
]) ]), Context(0))
]), ]),
" [2 3.2 true]; " " [2 3.2 true]; "
)?; )?;

14
src/context.rs Normal file
View File

@ -0,0 +1,14 @@
#[derive(Debug)]
#[derive(PartialEq)]
#[derive(Clone)]
#[derive(Copy)]
pub struct Context(pub i32);
#[derive(Debug)]
pub struct Contextual<T>(pub T, pub Context);
impl<T: PartialEq> PartialEq<Contextual<T>> for Contextual<T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}

View File

@ -1,4 +1,5 @@
use crate::{ use crate::{
context::Contextual,
ast::node::Node, ast::node::Node,
eval::{ eval::{
value::Value, value::Value,
@ -20,37 +21,37 @@ impl Evaluator {
} }
} }
pub fn run(&mut self, root: &Node) -> EvalResult { pub fn run(&mut self, root: &Contextual<Node>) -> EvalResult {
match root { match &root.0 {
Node::Module(_, nodes) => { Node::Module(_, nodes) => {
let mut res = None; let mut res = None;
for node in nodes.iter() { for node in nodes.iter() {
res = self.run(&node)? res = self.run(node)?
} }
Ok(res) Ok(res)
}, },
Node::Ident(name) => { Node::Ident(name) => {
match self.table.get(name) { match self.table.get(&name) {
Some(val) => { Some(val) => {
Ok(Some(val)) Ok(Some(val))
}, },
None => Err(EvalError { None => Err(EvalError {
msg: format!("cannot find <{}>", name), msg: format!("cannot find <{}>", name),
line: 0 line: root.1.0
}) })
} }
}, },
Node::AssignAddInstr(target, values) => { Node::AssignAddInstr(target, values) => {
match &**target { match &*target.0 {
Node::Ident(name) => { Node::Ident(name) => {
let mut val_array: Vec<Value> = vec![]; let mut val_array: Vec<Value> = vec![];
match self.table.get(name) { match self.table.get(&name) {
Some(Value::Array(existing_arr)) => { Some(Value::Array(existing_arr)) => {
val_array = existing_arr; val_array = existing_arr;
}, },
@ -62,14 +63,14 @@ impl Evaluator {
} }
for node_val in values { for node_val in values {
let val = self.run(node_val)?; let val = self.run(&node_val)?;
if let Some(v) = val { if let Some(v) = val {
val_array.push(v); val_array.push(v);
} }
} }
let value = Value::Array(val_array); let value = Value::Array(val_array);
self.table.set(name, value); self.table.set(&name, value);
}, },
_ => { _ => {
return Err(EvalError { return Err(EvalError {
@ -77,7 +78,7 @@ impl Evaluator {
"cannot assign to target <{:?}>", "cannot assign to target <{:?}>",
target target
), ),
line: 0 line: root.1.0
}); });
} }
} }
@ -86,14 +87,14 @@ impl Evaluator {
}, },
Node::AssignIfInstr(target, values) => { Node::AssignIfInstr(target, values) => {
match &**target { match &*target.0 {
Node::Ident(name) => { Node::Ident(name) => {
match self.table.get(name) { match self.table.get(&name) {
Some(_) => {}, Some(_) => {},
None => { None => {
if let Some(value) if let Some(value)
= self.nodes_to_value(values)? { = self.nodes_to_value(&values)? {
self.table.set(name, value); self.table.set(&name, value);
} }
} }
} }
@ -104,7 +105,8 @@ impl Evaluator {
"cannot assign to target <{:?}>", "cannot assign to target <{:?}>",
target target
), ),
line: 0 line: root.1.0
}); });
} }
} }
@ -113,10 +115,10 @@ impl Evaluator {
}, },
Node::AssignInstr(target, values) => { Node::AssignInstr(target, values) => {
match &**target { match &*target.0 {
Node::Ident(name) => { Node::Ident(name) => {
if let Some(value) = self.nodes_to_value(values)? { if let Some(value) = self.nodes_to_value(&values)? {
self.table.set(name, value); self.table.set(&name, value);
} }
}, },
_ => { _ => {
@ -125,7 +127,8 @@ impl Evaluator {
"cannot assign to target <{:?}>", "cannot assign to target <{:?}>",
target target
), ),
line: 0 line: root.1.0
}); });
} }
} }
@ -142,7 +145,7 @@ impl Evaluator {
let mut values: Vec<Value> = vec![]; let mut values: Vec<Value> = vec![];
for node in nodes { for node in nodes {
match self.run(node) { match self.run(&node) {
Ok(Some(value)) => { Ok(Some(value)) => {
values.push(value); values.push(value);
}, },
@ -150,7 +153,8 @@ impl Evaluator {
_ => { _ => {
return Err(EvalError { return Err(EvalError {
msg: String::from("invalid array element"), 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<Node>) -> EvalResult { fn nodes_to_value(&mut self, nodes: &Vec<Contextual<Node>>) -> EvalResult {
let mut val_array: Vec<Value> = vec![]; let mut val_array: Vec<Value> = vec![];
for node in nodes { for node in nodes {
match self.run(node) { match self.run(&node) {
Ok(Some(val)) => val_array.push(val), Ok(Some(val)) => val_array.push(val),
Ok(None) => {}, Ok(None) => {},
Err(err) => { return Err(err); } Err(err) => { return Err(err); }
@ -209,7 +213,8 @@ mod test {
if val != value { if val != value {
Err(Box::new(EvalError { Err(Box::new(EvalError {
msg: format!("expected: {:?}, got: {:?}", value, val), msg: format!("expected: {:?}, got: {:?}", value, val),
line: 0 line: root.1.0
})) }))
} else { } else {
Ok(()) Ok(())
@ -217,7 +222,8 @@ mod test {
} else { } else {
Err(Box::new(EvalError { Err(Box::new(EvalError {
msg: format!("unexpected: {:?}", value), msg: format!("unexpected: {:?}", value),
line: 0 line: root.1.0
})) }))
} }
}, },
@ -238,7 +244,8 @@ mod test {
Err(_) => Ok(()), Err(_) => Ok(()),
_ => Err(Box::new(EvalError { _ => Err(Box::new(EvalError {
msg: format!("\"{}\" should fail", source), msg: format!("\"{}\" should fail", source),
line: 0 line: root.1.0
})) }))
} }
} }

View File

@ -2,6 +2,7 @@ use std::fs;
mod ast; mod ast;
mod eval; mod eval;
mod context;
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let args: Vec<String> = std::env::args().collect(); let args: Vec<String> = std::env::args().collect();