aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler.rs102
-rw-r--r--src/lib.rs36
-rw-r--r--src/tokenizer.rs2
-rw-r--r--src/vm.rs22
4 files changed, 130 insertions, 32 deletions
diff --git a/src/compiler.rs b/src/compiler.rs
index d18d9c6..eb6058a 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -390,7 +390,7 @@ impl Compiler {
Token::Bool(_) => self.value(block),
Token::String(_) => self.value(block),
- Token::Not => self.unary(block),
+ Token::Bang => self.unary(block),
_ => { return false; },
}
@@ -490,7 +490,7 @@ impl Compiler {
fn unary(&mut self, block: &mut Block) {
let op = match self.eat() {
Token::Minus => Op::Neg,
- Token::Not => Op::Not,
+ Token::Bang => Op::Not,
_ => { error!(self, "Invalid unary operator"); Op::Neg },
};
self.parse_precedence(block, Prec::Factor);
@@ -580,26 +580,66 @@ impl Compiler {
}
fn call(&mut self, block: &mut Block) {
- expect!(self, Token::LeftParen, "Expected '(' at start of function call.");
-
let mut arity = 0;
- loop {
- match self.peek() {
- Token::EOF => {
- error!(self, "Unexpected EOF in function call.");
- break;
- }
- Token::RightParen => {
- self.eat();
- break;
+ match self.peek() {
+ Token::LeftParen => {
+ self.eat();
+ loop {
+ match self.peek() {
+ Token::EOF => {
+ error!(self, "Unexpected EOF in function call.");
+ break;
+ }
+ Token::RightParen => {
+ self.eat();
+ break;
+ }
+ _ => {
+ self.expression(block);
+ arity += 1;
+ if !matches!(self.peek(), Token::RightParen) {
+ expect!(self, Token::Comma, "Expected ',' after argument.");
+ }
+ }
+ }
+ if self.panic {
+ break;
+ }
}
- _ => {
- self.expression(block);
- arity += 1;
- if !matches!(self.peek(), Token::RightParen) {
- expect!(self, Token::Comma, "Expected ',' after argument.");
+ },
+
+ Token::Bang => {
+ self.eat();
+ loop {
+ match self.peek() {
+ Token::EOF => {
+ error!(self, "Unexpected EOF in function call.");
+ break;
+ }
+ Token::Newline => {
+ break;
+ }
+ _ => {
+ if !parse_branch!(self, block, self.expression(block)) {
+ break;
+ }
+ arity += 1;
+ if matches!(self.peek(), Token::Comma) {
+ self.eat();
+ }
+ }
+ }
+ if self.panic {
+ break;
}
}
+ if !self.panic {
+ println!("LINE {} -- ", self.line());
+ }
+ }
+
+ _ => {
+ error!(self, "Invalid function call. Expected '!' or '('.");
}
}
@@ -719,18 +759,17 @@ impl Compiler {
break;
}
}
- Token::LeftParen => {
- self.call(block);
+ _ => {
+ if !parse_branch!(self, block, self.call(block)) {
+ break
+ }
}
- _ => { break }
}
}
} else if let Some(blob) = self.find_blob(&name) {
let string = self.add_constant(Value::Blob(blob));
add_op(self, block, Op::Constant(string));
- if self.peek() == Token::LeftParen {
- self.call(block);
- }
+ parse_branch!(self, block, self.call(block));
} else if let Some(slot) = self.find_extern_function(&name) {
let string = self.add_constant(Value::ExternFunction(slot));
add_op(self, block, Op::Constant(string));
@@ -839,7 +878,11 @@ impl Compiler {
error!(self, format!("Cannot assign to constant '{}'", var.name));
}
if let Some(op) = op {
- add_op(self, block, Op::Copy);
+ if var.upvalue {
+ add_op(self, block, Op::ReadUpvalue(var.slot));
+ } else {
+ add_op(self, block, Op::ReadLocal(var.slot));
+ }
self.expression(block);
add_op(self, block, op);
} else {
@@ -1099,15 +1142,14 @@ impl Compiler {
add_op(self, block, Op::Set(field));
return;
}
- Token::LeftParen => {
- self.call(block);
- }
Token::Newline => {
return;
}
_ => {
- error!(self, "Unexpected token when parsing blob-field.");
- return;
+ if !parse_branch!(self, block, self.call(block)) {
+ error!(self, "Unexpected token when parsing blob-field.");
+ return;
+ }
}
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 3f753f1..22b6713 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1056,6 +1056,14 @@ a.a <=> 0"
);
test_multiple!(
+ fancy_call,
+ not: "f := fn {}\n f!\n",
+ one_arg: "f := fn a:int { a <=> 1 }\n f! 1\n",
+ two_arg: "f := fn a:int, b:int { b <=> 3 }\n f! 1, 1 + 2\n",
+ three_arg: "f := fn a:int, b:int, c:int { c <=> 13 }\n f! 1, 1 + 2, 1 + 4 * 3\n",
+ );
+
+ test_multiple!(
newline_regression,
simple: "a := 1 // blargh \na += 1 // blargh \n a <=> 2 // HARGH",
expressions: "1 + 1 // blargh \n 2 // blargh \n // HARGH \n",
@@ -1069,7 +1077,35 @@ a <=> 1
b := 2
{
a <=> 1
+}",
+ );
+
+ test_multiple!(
+ assignment_op_regression,
+ simple_add: "
+a := 0
+b := 99999
+a += 1
+a <=> 1
+",
+
+ simple_sub: "
+a := 0
+b := 99999
+a -= 1
+a <=> -1
+",
+
+ strange: "
+a := 0
+{
+ b := 99999
+ {
+ a := 99999
+ }
+ a -= 1
}
+a <=> -1
",
);
}
diff --git a/src/tokenizer.rs b/src/tokenizer.rs
index 9574af1..cf7a14c 100644
--- a/src/tokenizer.rs
+++ b/src/tokenizer.rs
@@ -112,7 +112,7 @@ pub enum Token {
#[token("||")]
Or,
#[token("!")]
- Not,
+ Bang,
#[token(",")]
Comma,
diff --git a/src/vm.rs b/src/vm.rs
index e5c7b2e..d238087 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -63,9 +63,10 @@ pub struct VM {
pub print_blocks: bool,
pub print_ops: bool,
+ runtime: bool,
- extern_functions: Vec<RustFunction>,
+ extern_functions: Vec<RustFunction>,
}
#[derive(Eq, PartialEq)]
@@ -92,6 +93,7 @@ impl VM {
print_blocks: false,
print_ops: false,
+ runtime: false,
extern_functions: Vec::new()
}
@@ -158,10 +160,25 @@ impl VM {
self.frame().block.borrow().ops[ip]
}
+ fn print_stacktrace(&self) {
+ if !self.runtime { return; }
+
+ println!("\n<{}>", "STACK".red());
+ for (i, frame) in self.frames.iter().enumerate() {
+ println!(" {:>3}. {}:{:<4} in {:10}",
+ i,
+ frame.block.borrow().file.display(),
+ frame.block.borrow().line(self.frame().ip),
+ frame.block.borrow().name.blue());
+ }
+ println!("")
+ }
+
/// Stop the program, violently
fn crash_and_burn(&self) -> ! {
self.print_stack();
println!("\n");
+ self.print_stacktrace();
self.frame().block.borrow().debug_print();
println!(" ip: {}, line: {}\n",
self.frame().ip.blue(),
@@ -171,6 +188,7 @@ impl VM {
fn error(&self, kind: ErrorKind, message: Option<String>) -> Error {
let frame = self.frames.last().unwrap();
+ self.print_stacktrace();
Error {
kind,
file: frame.block.borrow().file.clone(),
@@ -458,6 +476,7 @@ impl VM {
self.extern_functions = prog.functions.clone();
self.stack.clear();
self.frames.clear();
+ self.runtime = true;
self.push(Value::Function(Vec::new(), Rc::clone(&block)));
@@ -738,6 +757,7 @@ impl VM {
self.blobs = prog.blobs.clone();
self.constants = prog.constants.clone();
self.strings = prog.strings.clone();
+ self.runtime = false;
self.extern_functions = prog.functions.clone();
for block in prog.blocks.iter() {