aboutsummaryrefslogtreecommitdiffstats
path: root/src/compiler.rs
diff options
context:
space:
mode:
authorEdvard Thörnros <edvard.thornros@gmail.com>2021-02-11 18:42:04 +0100
committerEdvard Thörnros <edvard.thornros@gmail.com>2021-02-11 18:42:04 +0100
commit4e6f4ff865a132df3e7a6f39f481f78c6fc1df47 (patch)
treea9f1ea95995b8b24758ee4d368313ec0e9809c3e /src/compiler.rs
parent04b0c68a792cc9be4dea92bb8750d7990bd43cc8 (diff)
parentb09c97154886e1ca9e0a418f8969870a31f39077 (diff)
downloadsylt-4e6f4ff865a132df3e7a6f39f481f78c6fc1df47.tar.gz
Merge remote-tracking branch 'origin/main' into break-continue
Diffstat (limited to 'src/compiler.rs')
-rw-r--r--src/compiler.rs149
1 files changed, 119 insertions, 30 deletions
diff --git a/src/compiler.rs b/src/compiler.rs
index e0b65c1..f2daa6e 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -126,6 +126,7 @@ struct Variable {
active: bool,
upvalue: bool,
captured: bool,
+ mutable: bool,
}
enum LoopOp {
@@ -437,7 +438,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; },
}
@@ -537,7 +538,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);
@@ -627,27 +628,67 @@ 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 '('.");
+ }
}
add_op(self, block, Op::Call(arity));
@@ -766,18 +807,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));
@@ -807,6 +847,32 @@ impl Compiler {
scope,
active: false,
upvalue: false,
+ mutable: true,
+ });
+ Ok(slot)
+ }
+
+ fn define_constant(&mut self, name: &str, typ: Type, _block: &mut Block) -> Result<usize, ()> {
+ if let Some(var) = self.find_variable(&name) {
+ if var.scope == self.frame().scope {
+ error!(self, format!("Multiple definitions of {} in this block.", name));
+ return Err(());
+ }
+ }
+
+ let slot = self.stack().len();
+ let scope = self.frame().scope;
+ self.stack_mut().push(Variable {
+ name: String::from(name),
+ captured: false,
+ outer_upvalue: false,
+ outer_slot: 0,
+ slot,
+ typ,
+ scope,
+ active: false,
+ upvalue: false,
+ mutable: false,
});
Ok(slot)
}
@@ -822,6 +888,15 @@ impl Compiler {
}
}
+ fn constant_statement(&mut self, name: &str, typ: Type, block: &mut Block) {
+ let slot = self.define_constant(name, typ.clone(), block);
+ self.expression(block);
+
+ if let Ok(slot) = slot {
+ self.stack_mut()[slot].active = true;
+ }
+ }
+
fn assign(&mut self, block: &mut Block) {
let name = match self.eat() {
Token::Identifier(name) => name,
@@ -846,8 +921,16 @@ impl Compiler {
};
if let Some(var) = self.find_variable(&name) {
+ if !var.mutable {
+ // TODO(ed): Maybe a better error than "SyntaxError".
+ 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 {
@@ -1110,15 +1193,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;
+ }
}
}
}
@@ -1174,6 +1256,12 @@ impl Compiler {
self.definition_statement(&name, Type::Unknown, block);
}
+ (Token::Identifier(name), Token::ColonColon, ..) => {
+ self.eat();
+ self.eat();
+ self.constant_statement(&name, Type::Unknown, block);
+ }
+
(Token::Blob, Token::Identifier(_), ..) => {
self.blob_statement(block);
}
@@ -1246,6 +1334,7 @@ impl Compiler {
active: false,
captured: false,
upvalue: false,
+ mutable: true,
});
let mut block = Block::new(name, file, 0);