aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdvard Thörnros <edvard.thornros@gmail.com>2021-01-10 16:55:26 +0100
committerEdvard Thörnros <edvard.thornros@gmail.com>2021-01-10 16:55:26 +0100
commit6d94077778d6043e135640f40b09e2582d3a3064 (patch)
tree871bffa3f6b9e061f9af5f620a8d432139a3f310
parentd61370656d9f3deb39bb37f9c1d45e8ddc62efd5 (diff)
downloadsylt-6d94077778d6043e135640f40b09e2582d3a3064.tar.gz
Fix this shit
-rw-r--r--src/compiler.rs61
-rw-r--r--src/error.rs11
-rw-r--r--src/main.rs16
-rw-r--r--src/vm.rs13
-rw-r--r--tests/faulty.tdy3
5 files changed, 62 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)]
diff --git a/src/vm.rs b/src/vm.rs
index 92740ea..a372d0b 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -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);
diff --git a/tests/faulty.tdy b/tests/faulty.tdy
new file mode 100644
index 0000000..369b8ff
--- /dev/null
+++ b/tests/faulty.tdy
@@ -0,0 +1,3 @@
+asdflökja;;;;
+123
+asd