aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler.rs34
-rw-r--r--src/lib.rs21
-rw-r--r--src/vm.rs10
3 files changed, 54 insertions, 11 deletions
diff --git a/src/compiler.rs b/src/compiler.rs
index 2aad62b..b45d47e 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -51,7 +51,7 @@ macro_rules! parse_branch {
let num_errors = $compiler.errors.len();
let mut stored_errors = Vec::new();
- // Closures for early return on success.
+ // Loop for early return on success.
let success = loop {
// We risk getting a lot of errors if we are in an invalid state
// when we start the parse.
@@ -187,6 +187,7 @@ nextable_enum!(Prec {
Comp,
Term,
Factor,
+ Index,
});
#[derive(Clone, Debug)]
@@ -604,6 +605,8 @@ impl Compiler {
fn precedence(&self, token: Token) -> Prec {
match token {
+ Token::LeftBracket => Prec::Index,
+
Token::Star | Token::Slash => Prec::Factor,
Token::Minus | Token::Plus => Prec::Term,
@@ -685,33 +688,46 @@ impl Compiler {
}
fn tuple(&mut self, block: &mut Block) {
- expect!(self, Token::LeftParen, "Expected '(' at start of tuple");
+ expect!(self, Token::LeftParen, "Expected '(' at start of tuple.");
let mut num_args = 0;
- loop {
+ let trailing_comma = loop {
match self.peek() {
Token::RightParen | Token::EOF => {
- break;
+ break false;
}
Token::Newline => {
self.eat();
}
+ Token::Comma => {
+ //TODO(gu): This creates a lot of syntax errors since the compiler panic is
+ // ignored and the statement is tried as a grouping instead, even though we
+ // _know_ that this can't be parsed as a grouping either.
+ // Tracked in #100.
+ error!(self, "Tuples must begin with an element or ')'.");
+ return;
+ }
_ => {
self.expression(block);
num_args += 1;
match self.peek() {
- Token::Comma => { self.eat(); },
+ Token::Comma => {
+ self.eat();
+ if matches!(self.peek(), Token::RightParen) {
+ break true;
+ }
+ },
Token::RightParen => {},
_ => {
- error!(self, "Expected ',' or ')' in tuple");
+ error!(self, "Expected ',' or ')' after tuple element.");
return;
},
}
}
}
- }
- if num_args == 1 {
- error!(self, "A tuple must contain more than 1 element.");
+ };
+ if num_args == 1 && !trailing_comma {
+ error!(self, "A tuple with 1 element must end with a trailing comma.");
return;
}
diff --git a/src/lib.rs b/src/lib.rs
index e94eaad..a138c33 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -178,7 +178,10 @@ pub enum Value {
String(Rc<String>),
Function(Vec<Rc<RefCell<UpValue>>>, Rc<RefCell<Block>>),
ExternFunction(usize),
+ /// This value should not be present when running, only when type checking.
+ /// Most operations are valid but produce funky results.
Unknown,
+ /// Should not be present when running.
Nil,
}
@@ -561,7 +564,7 @@ pub enum Op {
///
/// Broken out because they need to be recursive.
mod op {
- use super::Value;
+ use super::{Type, Value};
use std::rc::Rc;
fn tuple_bin_op(a: &Rc<Vec<Value>>, b: &Rc<Vec<Value>>, f: fn (&Value, &Value) -> Value) -> Value {
@@ -577,6 +580,7 @@ mod op {
Value::Float(a) => Value::Float(-*a),
Value::Int(a) => Value::Int(-*a),
Value::Tuple(a) => tuple_un_op(a, neg),
+ Value::Unknown => Value::Unknown,
_ => Value::Nil,
}
}
@@ -585,6 +589,7 @@ mod op {
match value {
Value::Bool(a) => Value::Bool(!*a),
Value::Tuple(a) => tuple_un_op(a, not),
+ Value::Unknown => Value::from(Type::Bool),
_ => Value::Nil,
}
}
@@ -596,6 +601,8 @@ mod op {
(Value::Int(a), Value::Int(b)) => Value::Int(a + b),
(Value::String(a), Value::String(b)) => Value::String(Rc::from(format!("{}{}", a, b))),
(Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_bin_op(a, b, add),
+ (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => add(a, a),
+ (Value::Unknown, Value::Unknown) => Value::Unknown,
_ => Value::Nil,
}
}
@@ -609,6 +616,8 @@ mod op {
(Value::Float(a), Value::Float(b)) => Value::Float(a * b),
(Value::Int(a), Value::Int(b)) => Value::Int(a * b),
(Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_bin_op(a, b, mul),
+ (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => mul(a, a),
+ (Value::Unknown, Value::Unknown) => Value::Unknown,
_ => Value::Nil,
}
}
@@ -618,6 +627,8 @@ mod op {
(Value::Float(a), Value::Float(b)) => Value::Float(a / b),
(Value::Int(a), Value::Int(b)) => Value::Int(a / b),
(Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_bin_op(a, b, div),
+ (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => div(a, a),
+ (Value::Unknown, Value::Unknown) => Value::Unknown,
_ => Value::Nil,
}
}
@@ -629,6 +640,8 @@ mod op {
(Value::String(a), Value::String(b)) => Value::Bool(a == b),
(Value::Bool(a), Value::Bool(b)) => Value::Bool(a == b),
(Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_bin_op(a, b, eq),
+ (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => eq(a, a),
+ (Value::Unknown, Value::Unknown) => Value::Unknown,
_ => Value::Nil,
}
}
@@ -640,6 +653,8 @@ mod op {
(Value::String(a), Value::String(b)) => Value::Bool(a < b),
(Value::Bool(a), Value::Bool(b)) => Value::Bool(a < b),
(Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_bin_op(a, b, less),
+ (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => less(a, a),
+ (Value::Unknown, Value::Unknown) => Value::Unknown,
_ => Value::Nil,
}
}
@@ -652,6 +667,8 @@ mod op {
match (a, b) {
(Value::Bool(a), Value::Bool(b)) => Value::Bool(*a && *b),
(Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_bin_op(a, b, and),
+ (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => and(a, a),
+ (Value::Unknown, Value::Unknown) => Value::Unknown,
_ => Value::Nil,
}
}
@@ -660,6 +677,8 @@ mod op {
match (a, b) {
(Value::Bool(a), Value::Bool(b)) => Value::Bool(*a || *b),
(Value::Tuple(a), Value::Tuple(b)) if a.len() == b.len() => tuple_bin_op(a, b, or),
+ (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => or(a, a),
+ (Value::Unknown, Value::Unknown) => Value::Unknown,
_ => Value::Nil,
}
}
diff --git a/src/vm.rs b/src/vm.rs
index 7321deb..e001ebc 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -294,7 +294,7 @@ impl VM {
match (val, slot) {
(Value::Tuple(v), Value::Int(slot)) => {
let slot = slot as usize;
- if v.len() < slot {
+ if v.len() <= slot {
self.stack.push(Value::Nil);
let len = v.len();
error!(self, ErrorKind::IndexOutOfBounds(Value::Tuple(v), len, slot));
@@ -715,6 +715,14 @@ impl VM {
};
}
+ Op::Index => {
+ // We don't have any information about the slot and the indexable might contain
+ // mixed types.
+ self.stack.pop().unwrap();
+ self.stack.pop().unwrap();
+ self.stack.push(Value::Unknown);
+ }
+
Op::Call(num_args) => {
let new_base = self.stack.len() - 1 - num_args;
match self.stack[new_base].clone() {