diff options
| -rw-r--r-- | src/compiler.rs | 47 | ||||
| -rw-r--r-- | src/lib.rs | 23 | ||||
| -rw-r--r-- | 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."); @@ -314,6 +314,7 @@ a() <=> 4 pub enum Value { Blob(usize), BlobInstance(usize, Rc<RefCell<Vec<Value>>>), + Tuple(Rc<Vec<Value>>), 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<Type>), Function(Vec<Type>, Box<Type>), 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), @@ -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(); |
