From 14bdddbe019ec1733b36e63f64969156bde070f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 7 Mar 2021 23:13:45 +0100 Subject: unknown in operators produce some _a_ value This makes sense when type-checking. --- src/lib.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index e94eaad..5094698 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -561,7 +561,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>, b: &Rc>, f: fn (&Value, &Value) -> Value) -> Value { @@ -577,6 +577,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 +586,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 +598,7 @@ 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) => a.clone(), _ => Value::Nil, } } @@ -609,6 +612,7 @@ 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) => a.clone(), _ => Value::Nil, } } @@ -618,6 +622,7 @@ 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) => a.clone(), _ => Value::Nil, } } @@ -629,6 +634,7 @@ 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, _) | (_, Value::Unknown) => Value::from(Type::Bool), _ => Value::Nil, } } @@ -640,6 +646,7 @@ 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, _) | (_, Value::Unknown) => Value::from(Type::Bool), _ => Value::Nil, } } @@ -652,6 +659,7 @@ 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, _) | (_, Value::Unknown) => Value::from(Type::Bool), _ => Value::Nil, } } @@ -660,6 +668,7 @@ 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, _) | (_, Value::Unknown) => Value::from(Type::Bool), _ => Value::Nil, } } -- cgit v1.2.1 From ad0618e8d1f81d98cd6228ab365186dad560d3c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 7 Mar 2021 23:16:26 +0100 Subject: allow trailing commas in tuples --- src/compiler.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index dc3bd96..17c6330 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -683,10 +683,10 @@ impl Compiler { 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(); @@ -695,7 +695,12 @@ impl Compiler { 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"); @@ -704,9 +709,9 @@ impl Compiler { } } } - } - if num_args == 1 { - error!(self, "A tuple must contain more than 1 element."); + }; + if num_args == 1 && !trailing_comma { + error!(self, "A tuple must contain more than 1 element or end with a trailing comma."); return; } -- cgit v1.2.1 From e39ff44d87fbbd04bad6b28a7ce3a4c1147547cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 7 Mar 2021 23:16:38 +0100 Subject: skip indexing into tuples when type checking --- src/vm.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/vm.rs b/src/vm.rs index 7cfc8d3..6b69b3c 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -717,6 +717,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(); // indexable + self.stack.pop().unwrap(); // slot + self.stack.push(Value::Unknown); + } + Op::Call(num_args) => { let new_base = self.stack.len() - 1 - num_args; match self.stack[new_base].clone() { -- cgit v1.2.1 From 294d304768dad5fca5f9844500c7003cd9f9ed8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 7 Mar 2021 23:16:51 +0100 Subject: cleanup comment --- src/compiler.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler.rs b/src/compiler.rs index 17c6330..46fe38c 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. -- cgit v1.2.1 From 1ccd9b3f2ffa449a11f2348314f0dcae2e224c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 7 Mar 2021 23:42:42 +0100 Subject: document Value::{Unknown,Nil} --- src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 5094698..7e09dce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -178,7 +178,10 @@ pub enum Value { String(Rc), Function(Vec>>, Rc>), 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, } -- cgit v1.2.1 From dc25e664305ed49edff4e45eaec6ed1fad910c60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 8 Mar 2021 00:09:24 +0100 Subject: check index out of bounds correctly --- src/vm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vm.rs b/src/vm.rs index 6b69b3c..1e04673 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -296,7 +296,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)); -- cgit v1.2.1 From 8e2c0e345facee83d63991dda548b71e6a0c4cf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 8 Mar 2021 00:15:46 +0100 Subject: error on '(,)'-tuples Currently creats a lot of syntax errors. See #100. --- progs/tests/tuples_fail_invalid_singleton.sy | 7 +++++++ src/compiler.rs | 8 ++++++++ 2 files changed, 15 insertions(+) create mode 100644 progs/tests/tuples_fail_invalid_singleton.sy diff --git a/progs/tests/tuples_fail_invalid_singleton.sy b/progs/tests/tuples_fail_invalid_singleton.sy new file mode 100644 index 0000000..c70fc21 --- /dev/null +++ b/progs/tests/tuples_fail_invalid_singleton.sy @@ -0,0 +1,7 @@ +start :: fn { + a := (,) + a +} + +//TODO(gu) See #100 +// errors: [ErrorKind::SyntaxError(_, _), ErrorKind::SyntaxError(_, _), ErrorKind::SyntaxError(_, _), ErrorKind::SyntaxError(_, _)] diff --git a/src/compiler.rs b/src/compiler.rs index 46fe38c..c4f687f 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -691,6 +691,14 @@ impl Compiler { 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; -- cgit v1.2.1 From bd2371faefb2d2cd52477dbd2628013ed8feb103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 8 Mar 2021 00:16:45 +0100 Subject: minor fix some errors --- src/compiler.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index c4f687f..b2900b6 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -680,7 +680,7 @@ 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; let trailing_comma = loop { @@ -711,7 +711,7 @@ impl Compiler { }, Token::RightParen => {}, _ => { - error!(self, "Expected ',' or ')' in tuple"); + error!(self, "Expected ',' or ')' after tuple element."); return; }, } @@ -719,7 +719,7 @@ impl Compiler { } }; if num_args == 1 && !trailing_comma { - error!(self, "A tuple must contain more than 1 element or end with a trailing comma."); + error!(self, "A tuple with 1 element must end with a trailing comma."); return; } -- cgit v1.2.1 From 6b2ff65735bb8229af9994db8221303b73a8194b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 8 Mar 2021 00:18:31 +0100 Subject: add tests --- progs/tests/tuples.sy | 12 ++++++++++++ progs/tests/tuples_fail_out_of_bounds.sy | 6 ++++++ 2 files changed, 18 insertions(+) create mode 100644 progs/tests/tuples.sy create mode 100644 progs/tests/tuples_fail_out_of_bounds.sy diff --git a/progs/tests/tuples.sy b/progs/tests/tuples.sy new file mode 100644 index 0000000..74f2701 --- /dev/null +++ b/progs/tests/tuples.sy @@ -0,0 +1,12 @@ +start :: fn { + a := (1,2) + a[0] <=> 1 + a[1] <=> 2 + + b := (1,) + b[0] <=> 1 + + empty := () + c := (empty,) + c[0] <=> () +} diff --git a/progs/tests/tuples_fail_out_of_bounds.sy b/progs/tests/tuples_fail_out_of_bounds.sy new file mode 100644 index 0000000..cb0764a --- /dev/null +++ b/progs/tests/tuples_fail_out_of_bounds.sy @@ -0,0 +1,6 @@ +start :: fn { + a := (1, 2) + a[2] +} + +// errors: [ErrorKind::IndexOutOfBounds(_, 2, 2)] -- cgit v1.2.1 From 5052d46071aaba4d24307aa62ad0cde766aaab3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 8 Mar 2021 00:21:32 +0100 Subject: correct amount of errors in test --- progs/tests/tuples_fail_invalid_singleton.sy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progs/tests/tuples_fail_invalid_singleton.sy b/progs/tests/tuples_fail_invalid_singleton.sy index c70fc21..a8fafaa 100644 --- a/progs/tests/tuples_fail_invalid_singleton.sy +++ b/progs/tests/tuples_fail_invalid_singleton.sy @@ -4,4 +4,4 @@ start :: fn { } //TODO(gu) See #100 -// errors: [ErrorKind::SyntaxError(_, _), ErrorKind::SyntaxError(_, _), ErrorKind::SyntaxError(_, _), ErrorKind::SyntaxError(_, _)] +// errors: [ErrorKind::SyntaxError(_, _), ErrorKind::SyntaxError(_, _), ErrorKind::SyntaxError(_, _)] -- cgit v1.2.1 From f145fbd1d8ad6148c8c5631487d5208c043a0a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 8 Mar 2021 00:46:54 +0100 Subject: remove comment --- src/vm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vm.rs b/src/vm.rs index 1e04673..2752435 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -720,8 +720,8 @@ impl VM { Op::Index => { // We don't have any information about the slot and the indexable might contain // mixed types. - self.stack.pop().unwrap(); // indexable - self.stack.pop().unwrap(); // slot + self.stack.pop().unwrap(); + self.stack.pop().unwrap(); self.stack.push(Value::Unknown); } -- cgit v1.2.1 From e9282cc37813c2632b2e55329343a6ab233b4cc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 8 Mar 2021 17:15:46 +0100 Subject: check other operand if one is unknown --- src/lib.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7e09dce..a138c33 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -601,7 +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) => a.clone(), + (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => add(a, a), + (Value::Unknown, Value::Unknown) => Value::Unknown, _ => Value::Nil, } } @@ -615,7 +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) => a.clone(), + (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => mul(a, a), + (Value::Unknown, Value::Unknown) => Value::Unknown, _ => Value::Nil, } } @@ -625,7 +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) => a.clone(), + (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => div(a, a), + (Value::Unknown, Value::Unknown) => Value::Unknown, _ => Value::Nil, } } @@ -637,7 +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, _) | (_, Value::Unknown) => Value::from(Type::Bool), + (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => eq(a, a), + (Value::Unknown, Value::Unknown) => Value::Unknown, _ => Value::Nil, } } @@ -649,7 +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, _) | (_, Value::Unknown) => Value::from(Type::Bool), + (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => less(a, a), + (Value::Unknown, Value::Unknown) => Value::Unknown, _ => Value::Nil, } } @@ -662,7 +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, _) | (_, Value::Unknown) => Value::from(Type::Bool), + (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => and(a, a), + (Value::Unknown, Value::Unknown) => Value::Unknown, _ => Value::Nil, } } @@ -671,7 +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, _) | (_, Value::Unknown) => Value::from(Type::Bool), + (Value::Unknown, a) | (a, Value::Unknown) if !matches!(a, Value::Unknown) => or(a, a), + (Value::Unknown, Value::Unknown) => Value::Unknown, _ => Value::Nil, } } -- cgit v1.2.1 From c2eddfeb7f0733b8676ddb22636f1054ae141b33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Mon, 8 Mar 2021 17:18:58 +0100 Subject: add more tests to tuples --- progs/tests/tuples.sy | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/progs/tests/tuples.sy b/progs/tests/tuples.sy index 74f2701..51f0b37 100644 --- a/progs/tests/tuples.sy +++ b/progs/tests/tuples.sy @@ -9,4 +9,15 @@ start :: fn { empty := () c := (empty,) c[0] <=> () + + a := (1,2) + a[0] <=> a[1] + + { + q := a[0] + w := a[0] + q + w + q - w + q * w + } } -- cgit v1.2.1 From 39e47cc62ca5372fcac20aceb94a200419281a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Mon, 8 Mar 2021 17:46:06 +0100 Subject: fix the tests --- progs/tests/tuples.sy | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/progs/tests/tuples.sy b/progs/tests/tuples.sy index 51f0b37..f2fcfcb 100644 --- a/progs/tests/tuples.sy +++ b/progs/tests/tuples.sy @@ -10,12 +10,12 @@ start :: fn { c := (empty,) c[0] <=> () - a := (1,2) - a[0] <=> a[1] + d := (1,2) + d[0] <=> d[0] { - q := a[0] - w := a[0] + q := d[0] + w := d[0] q + w q - w q * w -- cgit v1.2.1 From 16ba42c52bbf57fa78217327bd9759fec9f09fa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 8 Mar 2021 17:58:34 +0100 Subject: parse indexing precedence --- progs/tests/tuples.sy | 3 ++- src/compiler.rs | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/progs/tests/tuples.sy b/progs/tests/tuples.sy index f2fcfcb..642e381 100644 --- a/progs/tests/tuples.sy +++ b/progs/tests/tuples.sy @@ -14,7 +14,8 @@ start :: fn { d[0] <=> d[0] { - q := d[0] + q := d[2-2] + d[d[(5 + 3) * 0]] <=> d[d[(5 + 3) * 0]] w := d[0] q + w q - w diff --git a/src/compiler.rs b/src/compiler.rs index b2900b6..c04a36f 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -186,6 +186,7 @@ nextable_enum!(Prec { Comp, Term, Factor, + Index, }); #[derive(Clone, Debug)] @@ -603,6 +604,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, -- cgit v1.2.1