diff options
| author | Edvard Thörnros <edvard.thornros@gmail.com> | 2021-01-10 16:55:26 +0100 |
|---|---|---|
| committer | Edvard Thörnros <edvard.thornros@gmail.com> | 2021-01-10 16:55:26 +0100 |
| commit | 6d94077778d6043e135640f40b09e2582d3a3064 (patch) | |
| tree | 871bffa3f6b9e061f9af5f620a8d432139a3f310 /src | |
| parent | d61370656d9f3deb39bb37f9c1d45e8ddc62efd5 (diff) | |
| download | sylt-6d94077778d6043e135640f40b09e2582d3a3064.tar.gz | |
Fix this shit
Diffstat (limited to 'src')
| -rw-r--r-- | src/compiler.rs | 61 | ||||
| -rw-r--r-- | src/error.rs | 11 | ||||
| -rw-r--r-- | src/main.rs | 16 | ||||
| -rw-r--r-- | src/vm.rs | 13 |
4 files changed, 59 insertions, 42 deletions
diff --git a/src/compiler.rs b/src/compiler.rs index 0b7ff55..345088f 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -22,15 +22,15 @@ macro_rules! nextable_enum { } macro_rules! error { - ( $thing:expr, $msg:expr) => { - $thing.error(ErrorKind::SyntaxError($thing.line().unwrap()), Some(String::from($msg))) + ($thing:expr, $msg:expr) => { + $thing.error(ErrorKind::SyntaxError($thing.line(), $thing.peek()), Some(String::from($msg))) }; } macro_rules! expect { ($thing:expr, $exp:pat, $msg:expr) => { match $thing.peek() { - $exp => $thing.eat(), + $exp => { $thing.eat(); }, _ => error!($thing, $msg), } }; @@ -65,19 +65,28 @@ impl Compiler { } fn clear_panic(&mut self) { - self.panic = false; + if self.panic { + self.panic = false; + + while match self.peek() { + Token::EOF | Token::Newline => false, + _ => true, + } { + self.eat(); + } + self.eat(); + } } - fn error(&mut self, kind: ErrorKind, message: Option<String>) -> ! { - if self.panic { panic!(); } + fn error(&mut self, kind: ErrorKind, message: Option<String>) { + if self.panic { return } self.panic = true; self.errors.push(Error { kind: kind, file: self.current_file.clone(), - line: self.line().unwrap(), + line: self.line(), message: message, }); - panic!(); } fn peek(&self) -> Token { @@ -116,10 +125,11 @@ impl Compiler { } } - fn line(&self) -> Option<usize> { - match self.tokens.get(self.curr) { - Some((_, line)) => Some(*line), - None => None, + fn line(&self) -> usize { + if self.curr < self.tokens.len() { + self.tokens[self.curr].1 + } else { + self.tokens[self.tokens.len() - 1].1 } } @@ -165,7 +175,7 @@ impl Compiler { Token::Float(f) => { Value::Float(f) }, Token::Int(i) => { Value::Int(i) } Token::Bool(b) => { Value::Bool(b) } - _ => { error!(self, "Cannot parse value.") } + _ => { error!(self, "Cannot parse value."); Value::Bool(false) } }; block.add(Op::Constant(value), self.line()); } @@ -182,7 +192,7 @@ impl Compiler { let op = match self.eat() { Token::Minus => Op::Neg, Token::Not => Op::Not, - _ => error!(self, "Invalid unary operator"), + _ => { error!(self, "Invalid unary operator"); Op::Neg }, }; self.parse_precedence(block, Prec::Factor); block.add(op, self.line()); @@ -205,7 +215,7 @@ impl Compiler { Token::NotEqual => &[Op::Equal, Op::Not], Token::LessEqual => &[Op::Greater, Op::Not], Token::GreaterEqual => &[Op::Less, Op::Not], - _ => { error!(self, "Illegal operator"); } + _ => { error!(self, "Illegal operator"); &[] } }; block.add_from(op, self.line()); } @@ -227,6 +237,8 @@ impl Compiler { } fn statement(&mut self, block: &mut Block) { + self.clear_panic(); + match self.peek() { Token::Print => { self.eat(); @@ -237,29 +249,28 @@ impl Compiler { _ => { self.expression(block); - block.add(Op::Pop, None); + block.add(Op::Pop, self.line()); expect!(self, Token::Newline, "Expect newline after expression."); } } } - pub fn compile(&mut self, name: &str, file: &Path) -> Block { + pub fn compile(&mut self, name: &str, file: &Path) -> Result<Block, Vec<Error>> { let mut block = Block::new(name, file); - loop { - if self.peek() == Token::EOF { - break; - } - + while self.peek() != Token::EOF { self.statement(&mut block); - } block.add(Op::Return, self.line()); - block + if self.errors.is_empty() { + Ok(block) + } else { + Err(self.errors.clone()) + } } } -pub fn compile(name: &str, file: &Path, tokens: TokenStream) -> Block { +pub fn compile(name: &str, file: &Path, tokens: TokenStream) -> Result<Block, Vec<Error>> { Compiler::new(file, tokens).compile(name, file) } diff --git a/src/error.rs b/src/error.rs index 277be5f..22e0d1a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,15 +1,16 @@ use std::fmt; use std::path::PathBuf; use crate::vm::{Op, Value}; +use crate::tokenizer::Token; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum ErrorKind { TypeError(Op, Vec<Value>), AssertFailed(Value, Value), - SyntaxError(usize), + SyntaxError(usize, Token), } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Error { pub kind: ErrorKind, pub file: PathBuf, @@ -29,8 +30,8 @@ impl fmt::Display for ErrorKind { ErrorKind::AssertFailed(a, b) => { write!(f, "Assertion failed, {:?} != {:?}.", a, b) } - ErrorKind::SyntaxError(line) => { - write!(f, "Syntax error on line {}", line) + ErrorKind::SyntaxError(line, token) => { + write!(f, "Syntax error on line {} at token {:?}", line, token) } } } diff --git a/src/main.rs b/src/main.rs index bcda641..53e2e08 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,8 +9,11 @@ use error::Error; fn main() { let file = file_from_args().unwrap_or_else(|| Path::new("tests/simple.tdy").to_owned()); - if let Err(err) = run_file(&file) { - println!("{}", err); + if let Err(errs) = run_file(&file) { + for err in errs.iter() { + println!("{}", err); + } + println!(" {} errors occured.", errs.len()); } } @@ -18,10 +21,13 @@ fn file_from_args() -> Option<PathBuf> { std::env::args().skip(1).map(|s| Path::new(&s).to_owned()).find(|p| p.is_file()) } -fn run_file(path: &Path) -> Result<(), Error> { +fn run_file(path: &Path) -> Result<(), Vec<Error>> { let tokens = tokenizer::file_to_tokens(path); - let block = compiler::compile("main", path, tokens); // path -> str might fail - vm::run_block(block) + match compiler::compile("main", path, tokens) { + Ok(block) => vm::run_block(block).or_else(|e| Err(vec![e])), + Err(errors) => Err(errors), + } + } #[cfg(test)] @@ -49,7 +49,7 @@ pub struct Block { name: String, file: PathBuf, ops: Vec<Op>, - last_line_offset: Option<usize>, + last_line_offset: usize, line_offsets: HashMap<usize, usize>, } @@ -59,23 +59,22 @@ impl Block { name: String::from(name), file: file.to_owned(), ops: Vec::new(), - last_line_offset: None, + last_line_offset: 0, line_offsets: HashMap::new(), } } - pub fn add(&mut self, op: Op, token_position: Option<usize>) -> usize { + pub fn add(&mut self, op: Op, token_position: usize) -> usize { let len = self.ops.len(); if token_position != self.last_line_offset { - if let Some(token_position) = token_position { - self.line_offsets.insert(len, token_position); - } + self.line_offsets.insert(len, token_position); + self.last_line_offset = token_position; } self.ops.push(op); len } - pub fn add_from(&mut self, ops: &[Op], token_position: Option<usize>) -> usize { + pub fn add_from(&mut self, ops: &[Op], token_position: usize) -> usize { let len = self.ops.len(); for op in ops { self.add(*op, token_position); |
