From 1a82b85817646aded501051f4e9d651f7c0d4970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Sat, 30 Jan 2021 18:42:11 +0100 Subject: tuple values --- src/compiler.rs | 47 ++++++++++++++++++++++++++++++++++++++++++++++- src/lib.rs | 23 +++++++++++------------ src/vm.rs | 5 +++++ 3 files changed, 62 insertions(+), 13 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 92bf3fc..6fc8e78 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -284,7 +284,7 @@ impl Compiler { fn prefix(&mut self, token: Token, block: &mut Block) -> bool { match token { Token::Identifier(_) => self.variable_expression(block), - Token::LeftParen => self.grouping(block), + Token::LeftParen => self.grouping_or_tuple(block), Token::Minus => self.unary(block), Token::Float(_) => self.value(block), @@ -331,6 +331,51 @@ impl Compiler { block.add(Op::Constant(value), self.line()); } + fn grouping_or_tuple(&mut self, block: &mut Block) { + let block_length = block.ops.len(); + let token_length = self.curr; + if self.try_tuple(block).is_err() { + block.ops.truncate(block_length); + self.curr = token_length; + self.grouping(block); + } + } + + fn try_tuple(&mut self, block: &mut Block) -> Result<(), ()> { + expect!(self, Token::LeftParen, "Expected '(' at start of tuple"); + + let mut num_args = 0; + loop { + match self.peek() { + Token::RightParen | Token::EOF => { + break; + } + Token::Newline => { + self.eat(); + } + _ => { + self.expression(block); + num_args += 1; + if self.peek() == Token::Comma { + self.eat(); + continue; + } + if self.peek() == Token::RightParen { + continue; + } + return Err(()); + } + } + } + if num_args == 1 { + return Err(()); + } + + expect!(self, Token::RightParen, "Expected ')' after tuple"); + block.add(Op::Tuple(num_args), self.line()); + Ok(()) + } + fn grouping(&mut self, block: &mut Block) { expect!(self, Token::LeftParen, "Expected '(' around expression."); diff --git a/src/lib.rs b/src/lib.rs index bdd4ae4..248a589 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -314,6 +314,7 @@ a() <=> 4 pub enum Value { Blob(usize), BlobInstance(usize, Rc>>), + Tuple(Rc>), Float(f64), Int(i64), Bool(bool), @@ -378,6 +379,7 @@ impl Debug for Value { Value::ExternFunction(slot) => write!(fmt, "(extern fn {})", slot), Value::Unkown => write!(fmt, "(unkown)"), Value::Nil => write!(fmt, "(nil)"), + Value::Tuple(v) => write!(fmt, "({:?})", v), } } } @@ -393,18 +395,7 @@ impl Value { } fn as_type(&self) -> Type { - match self { - Value::BlobInstance(i, _) => Type::BlobInstance(*i), - Value::Blob(i) => Type::Blob(*i), - Value::Float(_) => Type::Float, - Value::Int(_) => Type::Int, - Value::Bool(_) => Type::Bool, - Value::String(_) => Type::String, - Value::Function(_, block) => block.borrow().ty.clone(), - Value::ExternFunction(_) => Type::Void, //TODO - Value::Unkown => Type::UnknownType, - Value::Nil => Type::Void, - } + Type::from(self) } } @@ -415,6 +406,7 @@ pub enum Op { Pop, PopUpvalue, Constant(Value), + Tuple(usize), Get(String), Set(String), @@ -582,6 +574,7 @@ pub enum Type { Float, Bool, String, + Tuple(Vec), Function(Vec, Box), Blob(usize), BlobInstance(usize), @@ -609,6 +602,9 @@ impl From<&Value> for Type { match value { Value::BlobInstance(i, _) => Type::BlobInstance(*i), Value::Blob(i) => Type::Blob(*i), + Value::Tuple(v) => { + Type::Tuple(v.iter().map(|x| Type::from(x)).collect()) + } Value::Int(_) => Type::Int, Value::Float(_) => Type::Float, Value::Bool(_) => Type::Bool, @@ -632,6 +628,9 @@ impl Type { Type::Void => Value::Nil, Type::Blob(i) => Value::Blob(*i), Type::BlobInstance(i) => Value::BlobInstance(*i, Rc::new(RefCell::new(Vec::new()))), + Type::Tuple(fields) => { + Value::Tuple(Rc::new(fields.iter().map(|x| x.as_value()).collect())) + } Type::UnknownType => Value::Unkown, Type::Int => Value::Int(1), Type::Float => Value::Float(1.0), diff --git a/src/vm.rs b/src/vm.rs index e2b9e57..fa998b8 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -139,6 +139,11 @@ impl VM { self.stack.pop().unwrap(); } + Op::Tuple(size) => { + let values = self.stack.split_off(self.stack.len() - size); + self.stack.push(Value::Tuple(Rc::new(values))); + } + Op::PopUpvalue => { let value = self.stack.pop().unwrap(); let slot = self.stack.len(); -- cgit v1.2.1