🐛 line numbers in error messages.
parent
3811b2ddb2
commit
c45b885dc5
|
@ -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,16 +40,16 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.cursor = cursor;
|
self.cursor = cursor;
|
||||||
self.line = line;
|
self.line = line;
|
||||||
node
|
node
|
||||||
|
@ -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 {
|
||||||
|
@ -85,7 +86,7 @@ impl Lexer {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !c.is_ascii_alphabetic() && c != '_'
|
if !c.is_ascii_alphabetic() && c != '_'
|
||||||
&& !c.is_digit(10) {
|
&& !c.is_digit(10) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(
|
||||||
Box::new(Node::Ident(String::from("HELLO"))),
|
Contextual(
|
||||||
vec![Node::Int(4), Node::Bool(true)]
|
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; "
|
" HELLO = 4 true; "
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
test_parser(
|
test_parser(
|
||||||
Node::Module("mod".to_owned(), vec![
|
Node::Module("mod".to_owned(), vec![
|
||||||
Node::AssignIfInstr(
|
Contextual(Node::AssignIfInstr(
|
||||||
Box::new(Node::Ident(String::from("HELLO_2"))),
|
Contextual(
|
||||||
vec![Node::Int(4)]
|
Box::new(Node::Ident(String::from("HELLO_2"))),
|
||||||
)
|
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]; "
|
||||||
)?;
|
)?;
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Reference in New Issue