aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdvard Thörnros <edvard.thornros@gmail.com>2021-01-10 16:15:52 +0100
committerEdvard Thörnros <edvard.thornros@gmail.com>2021-01-10 16:15:52 +0100
commitd61370656d9f3deb39bb37f9c1d45e8ddc62efd5 (patch)
tree9fa83578abc1e18c4415c97bbfce10886bbc2daa
parent64576ba8f08990dc8bc94ef1bec4dd502d5cef06 (diff)
downloadsylt-d61370656d9f3deb39bb37f9c1d45e8ddc62efd5.tar.gz
More errors!
-rw-r--r--src/compiler.rs84
-rw-r--r--src/error.rs48
-rw-r--r--src/main.rs5
-rw-r--r--src/vm.rs84
4 files changed, 128 insertions, 93 deletions
diff --git a/src/compiler.rs b/src/compiler.rs
index 5808abe..0b7ff55 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -1,15 +1,11 @@
-use std::path::Path;
+use std::path::{Path, PathBuf};
use crate::tokenizer::{Token, TokenStream};
use crate::vm::{Value, Block, Op};
-
-struct Compiler {
- curr: usize,
- tokens: TokenStream,
-}
+use crate::error::{Error, ErrorKind};
macro_rules! nextable_enum {
- ( $name:ident, $( $thing:ident ),* ) => {
+ ( $name:ident { $( $thing:ident ),* } ) => {
#[derive(PartialEq, PartialOrd, Clone, Copy, Debug)]
enum $name {
$( $thing, )*
@@ -25,25 +21,62 @@ macro_rules! nextable_enum {
};
}
-nextable_enum!(Prec,
+macro_rules! error {
+ ( $thing:expr, $msg:expr) => {
+ $thing.error(ErrorKind::SyntaxError($thing.line().unwrap()), Some(String::from($msg)))
+ };
+}
+
+macro_rules! expect {
+ ($thing:expr, $exp:pat, $msg:expr) => {
+ match $thing.peek() {
+ $exp => $thing.eat(),
+ _ => error!($thing, $msg),
+ }
+ };
+}
+
+nextable_enum!(Prec {
No,
Assert,
Bool,
Comp,
Term,
Factor
-);
+});
+
+struct Compiler {
+ curr: usize,
+ tokens: TokenStream,
+ current_file: PathBuf,
+ panic: bool,
+ errors: Vec<Error>,
+}
impl Compiler {
- pub fn new(tokens: TokenStream) -> Self {
+ pub fn new(current_file: &Path, tokens: TokenStream) -> Self {
Self {
curr: 0,
tokens,
+ current_file: PathBuf::from(current_file),
+ panic: false,
+ errors: vec![],
}
}
- fn error(&self, msg: &str) -> ! {
- println!("ERROR: {} line {:?}", msg, self.line());
+ fn clear_panic(&mut self) {
+ self.panic = false;
+ }
+
+ fn error(&mut self, kind: ErrorKind, message: Option<String>) -> ! {
+ if self.panic { panic!(); }
+ self.panic = true;
+ self.errors.push(Error {
+ kind: kind,
+ file: self.current_file.clone(),
+ line: self.line().unwrap(),
+ message: message,
+ });
panic!();
}
@@ -132,28 +165,24 @@ impl Compiler {
Token::Float(f) => { Value::Float(f) },
Token::Int(i) => { Value::Int(i) }
Token::Bool(b) => { Value::Bool(b) }
- _ => { self.error("Invalid value.") }
+ _ => { error!(self, "Cannot parse value.") }
};
block.add(Op::Constant(value), self.line());
}
fn grouping(&mut self, block: &mut Block) {
- if Token::LeftParen != self.eat() {
- self.error("Expected left parenthesis around expression.");
- }
+ expect!(self, Token::LeftParen, "Expected '(' around expression.");
self.expression(block);
- if Token::RightParen != self.eat() {
- self.error("Expected closing parenthesis after expression.");
- }
+ expect!(self, Token::RightParen, "Expected ')' around expression.");
}
fn unary(&mut self, block: &mut Block) {
let op = match self.eat() {
Token::Minus => Op::Neg,
Token::Not => Op::Not,
- _ => self.error("Invalid unary operator"),
+ _ => error!(self, "Invalid unary operator"),
};
self.parse_precedence(block, Prec::Factor);
block.add(op, self.line());
@@ -176,7 +205,7 @@ impl Compiler {
Token::NotEqual => &[Op::Equal, Op::Not],
Token::LessEqual => &[Op::Greater, Op::Not],
Token::GreaterEqual => &[Op::Less, Op::Not],
- _ => { self.error("Illegal operator"); }
+ _ => { error!(self, "Illegal operator"); }
};
block.add_from(op, self.line());
}
@@ -186,9 +215,8 @@ impl Compiler {
}
fn parse_precedence(&mut self, block: &mut Block, precedence: Prec) {
- println!("-- {:?}", self.peek());
if !self.prefix(self.peek(), block) {
- self.error("Expected expression.");
+ error!(self, "Invalid expression.");
}
while precedence <= self.precedence(self.peek()) {
@@ -204,17 +232,13 @@ impl Compiler {
self.eat();
self.expression(block);
block.add(Op::Print, self.line());
- if self.eat() != Token::Newline {
- self.error("Expect newline after expression.");
- }
+ expect!(self, Token::Newline, "Expect newline after expression.");
},
_ => {
self.expression(block);
- if self.eat() != Token::Newline {
- self.error("Expect newline after expression.");
- }
block.add(Op::Pop, None);
+ expect!(self, Token::Newline, "Expect newline after expression.");
}
}
}
@@ -237,5 +261,5 @@ impl Compiler {
}
pub fn compile(name: &str, file: &Path, tokens: TokenStream) -> Block {
- Compiler::new(tokens).compile(name, file)
+ Compiler::new(file, tokens).compile(name, file)
}
diff --git a/src/error.rs b/src/error.rs
new file mode 100644
index 0000000..277be5f
--- /dev/null
+++ b/src/error.rs
@@ -0,0 +1,48 @@
+use std::fmt;
+use std::path::PathBuf;
+use crate::vm::{Op, Value};
+
+#[derive(Debug)]
+pub enum ErrorKind {
+ TypeError(Op, Vec<Value>),
+ AssertFailed(Value, Value),
+ SyntaxError(usize),
+}
+
+#[derive(Debug)]
+pub struct Error {
+ pub kind: ErrorKind,
+ pub file: PathBuf,
+ pub line: usize,
+ pub message: Option<String>,
+}
+
+impl fmt::Display for ErrorKind {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ ErrorKind::TypeError(op, values) => {
+ let values = values
+ .iter()
+ .fold(String::new(), |a, v| { format!("{}, {:?}", a, v) });
+ write!(f, "Cannot apply {:?} to values {}", op, values)
+ }
+ ErrorKind::AssertFailed(a, b) => {
+ write!(f, "Assertion failed, {:?} != {:?}.", a, b)
+ }
+ ErrorKind::SyntaxError(line) => {
+ write!(f, "Syntax error on line {}", line)
+ }
+ }
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let message = match &self.message {
+ Some(s) => format!("\n{}", s),
+ None => String::from(""),
+ };
+ write!(f, "{:?}:{} [Runtime Error] {}{}", self.file, self.line, self.kind, message)
+ }
+}
+
diff --git a/src/main.rs b/src/main.rs
index ed85961..bcda641 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,9 +1,12 @@
use std::path::{Path, PathBuf};
+mod error;
mod tokenizer;
mod vm;
mod compiler;
+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) {
@@ -15,7 +18,7 @@ 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<(), vm::Error> {
+fn run_file(path: &Path) -> Result<(), Error> {
let tokens = tokenizer::file_to_tokens(path);
let block = compiler::compile("main", path, tokens); // path -> str might fail
vm::run_block(block)
diff --git a/src/vm.rs b/src/vm.rs
index ca541a0..92740ea 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -1,6 +1,16 @@
-use std::collections::HashMap;
-use std::fmt;
use std::path::{Path, PathBuf};
+use std::collections::HashMap;
+
+use crate::error::{Error, ErrorKind};
+
+macro_rules! error {
+ ( $thing:expr, $kind:expr) => {
+ return Err($thing.error($kind, None));
+ };
+ ( $thing:expr, $kind:expr, $msg:expr) => {
+ return Err($thing.error($kind, Some($msg)));
+ };
+}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub enum Value {
@@ -82,47 +92,6 @@ pub struct VM {
ip: usize,
}
-#[derive(Debug)]
-pub enum VMErrorKind {
- TypeError(Op, Vec<Value>),
- AssertFailed(Value, Value),
-}
-
-#[derive(Debug)]
-pub struct Error {
- kind: VMErrorKind,
- file: PathBuf,
- line: usize,
- message: Option<String>,
-}
-
-impl fmt::Display for VMErrorKind {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- VMErrorKind::TypeError(op, values) => {
- let values = values
- .iter()
- .fold(String::new(), |a, v| { format!("{}, {:?}", a, v) });
- write!(f, "Cannot apply {:?} to values {}", op, values)
- }
- VMErrorKind::AssertFailed(a, b) => {
- write!(f, "Assertion failed, {:?} != {:?}.", a, b)
- }
- }
- }
-}
-
-impl fmt::Display for Error {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let message = match &self.message {
- Some(s) => format!("\n{}", s),
- None => String::from(""),
- };
- write!(f, "{:?}:{} [Runtime Error] {}{}", self.file, self.line, self.kind, message)
- }
-}
-
-
pub fn run_block(block: Block) -> Result<(), Error> {
let mut vm = VM {
stack: Vec::new(),
@@ -134,15 +103,6 @@ pub fn run_block(block: Block) -> Result<(), Error> {
vm.run()
}
-macro_rules! error {
- ( $vm:expr, $kind:expr) => {
- return Err($vm.error($kind, None));
- };
- ( $vm:expr, $kind:expr, $msg:expr) => {
- return Err($vm.error($kind, Some($msg)));
- };
-}
-
impl VM {
fn pop_twice(&mut self) -> (Value, Value) {
let (a, b) = (self.stack.pop().unwrap(), self.stack.pop().unwrap());
@@ -153,7 +113,7 @@ impl VM {
self.stack.get(self.stack.len() - amount)
}
- fn error(&self, kind: VMErrorKind, message: Option<String>) -> Error {
+ fn error(&self, kind: ErrorKind, message: Option<String>) -> Error {
let find_line = || {
for i in (0..=self.ip).rev() {
if let Some(line) = self.block.line_offsets.get(&i) {
@@ -208,7 +168,7 @@ impl VM {
match self.stack.pop().unwrap() {
Value::Float(a) => self.stack.push(Value::Float(-a)),
Value::Int(a) => self.stack.push(Value::Int(-a)),
- a => error!(self, VMErrorKind::TypeError(op, vec![a])),
+ a => error!(self, ErrorKind::TypeError(op, vec![a])),
}
}
@@ -216,7 +176,7 @@ impl VM {
match self.pop_twice() {
(Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(b + a)),
(Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(b + a)),
- (a, b) => error!(self, VMErrorKind::TypeError(op, vec![a, b])),
+ (a, b) => error!(self, ErrorKind::TypeError(op, vec![a, b])),
}
}
@@ -224,7 +184,7 @@ impl VM {
match self.pop_twice() {
(Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(b - a)),
(Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(b - a)),
- (a, b) => error!(self, VMErrorKind::TypeError(op, vec![a, b])),
+ (a, b) => error!(self, ErrorKind::TypeError(op, vec![a, b])),
}
}
@@ -232,7 +192,7 @@ impl VM {
match self.pop_twice() {
(Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(b * a)),
(Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(b * a)),
- (a, b) => error!(self, VMErrorKind::TypeError(op, vec![a, b])),
+ (a, b) => error!(self, ErrorKind::TypeError(op, vec![a, b])),
}
}
@@ -240,7 +200,7 @@ impl VM {
match self.pop_twice() {
(Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(b / a)),
(Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(b / a)),
- (a, b) => error!(self, VMErrorKind::TypeError(op, vec![a, b])),
+ (a, b) => error!(self, ErrorKind::TypeError(op, vec![a, b])),
}
}
@@ -262,28 +222,28 @@ impl VM {
Op::And => {
match self.pop_twice() {
(Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a && b)),
- (a, b) => error!(self, VMErrorKind::TypeError(op, vec![a, b])),
+ (a, b) => error!(self, ErrorKind::TypeError(op, vec![a, b])),
}
}
Op::Or => {
match self.pop_twice() {
(Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a || b)),
- (a, b) => error!(self, VMErrorKind::TypeError(op, vec![a, b])),
+ (a, b) => error!(self, ErrorKind::TypeError(op, vec![a, b])),
}
}
Op::Not => {
match self.stack.pop().unwrap() {
Value::Bool(a) => self.stack.push(Value::Bool(!a)),
- a => error!(self, VMErrorKind::TypeError(op, vec![a])),
+ a => error!(self, ErrorKind::TypeError(op, vec![a])),
}
}
Op::AssertEqual => {
let (a, b) = self.pop_twice();
if a != b {
- error!(self, VMErrorKind::AssertFailed(a, b));
+ error!(self, ErrorKind::AssertFailed(a, b));
}
self.stack.push(Value::Bool(a == b));
}