diff options
| -rw-r--r-- | src/compiler.rs | 27 | ||||
| -rw-r--r-- | src/error.rs | 6 | ||||
| -rw-r--r-- | src/lib.rs | 4 | ||||
| -rw-r--r-- | src/vm.rs | 28 |
4 files changed, 61 insertions, 4 deletions
diff --git a/src/compiler.rs b/src/compiler.rs index 6fc8e78..0ddae1a 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -315,6 +315,8 @@ impl Compiler { | Token::NotEqual => self.binary(block), + Token::LeftBracket => self.index(block), + _ => { return false; }, } return true; @@ -384,6 +386,15 @@ impl Compiler { expect!(self, Token::RightParen, "Expected ')' around expression."); } + fn index(&mut self, block: &mut Block) { + expect!(self, Token::LeftBracket, "Expected ']' around index."); + + self.expression(block); + block.add(Op::Index, self.line()); + + expect!(self, Token::RightBracket, "Expected '[' around index."); + } + fn unary(&mut self, block: &mut Block) { let op = match self.eat() { Token::Minus => Op::Neg, @@ -797,6 +808,22 @@ impl Compiler { let f = Type::Function(params, Box::new(return_type)); Ok(f) } + Token::LeftParen => { + self.eat(); + let mut element = Vec::new(); + loop { + element.push(self.parse_type()?); + if self.peek() == Token::RightParen { + self.eat(); + return Ok(Type::Tuple(element)); + } + if !expect!(self, + Token::Comma, + "Expect comma efter element in tuple.") { + return Err(()); + } + } + } Token::Identifier(x) => { self.eat(); match x.as_str() { diff --git a/src/error.rs b/src/error.rs index 2caced9..e73d863 100644 --- a/src/error.rs +++ b/src/error.rs @@ -14,6 +14,9 @@ pub enum ErrorKind { TypeError(Op, Vec<Type>), ExternTypeMismatch(String, Vec<Type>), RuntimeTypeError(Op, Vec<Value>), + + IndexOutOfBounds(Value, usize, usize), + Assert, InvalidProgram, Unreachable, @@ -38,6 +41,9 @@ impl fmt::Display for ErrorKind { .fold(String::new(), |a, v| { format!("{}{:?}, ", a, v) }); write!(f, "{} Cannot apply {:?} to types {}", "Type Error".bold(), op, types) } + ErrorKind::IndexOutOfBounds(value, len, slot) => { + write!(f, "{} for {:?} - length is {} but index is {}", "Index Error".bold(), value, len, slot) + } ErrorKind::ExternTypeMismatch(name, types) => { write!(f, "{} Extern function '{}' doesn't accept argument(s) with type(s) {:?}", "Type Error".bold(), name, types) } @@ -408,6 +408,7 @@ pub enum Op { Constant(Value), Tuple(usize), + Index, Get(String), Set(String), @@ -590,6 +591,9 @@ impl PartialEq for Type { (Type::Float, Type::Float) => true, (Type::Bool, Type::Bool) => true, (Type::String, Type::String) => true, + (Type::Tuple(a), Type::Tuple(b)) => { + a.iter().zip(b.iter()).all(|(a, b)| a == b) + } (Type::Function(a_args, a_ret), Type::Function(b_args, b_ret)) => a_args == b_args && a_ret == b_ret, _ => false, @@ -175,6 +175,26 @@ impl VM { self.stack.push(value); } + Op::Index => { + let slot = self.stack.pop().unwrap(); + let val = self.stack.pop().unwrap(); + match (val, slot) { + (Value::Tuple(v), Value::Int(slot)) => { + let slot = slot as usize; + if v.len() < slot { + self.stack.push(Value::Nil); + let len = v.len(); + error!(self, ErrorKind::IndexOutOfBounds(Value::Tuple(v), len, slot)); + } + self.stack.push(v[slot].clone()); + } + (val, slot) => { + self.stack.push(Value::Nil); + error!(self, ErrorKind::RuntimeTypeError(op, vec![val, slot]), String::from("Cannot index type")); + } + } + } + Op::Get(field) => { let inst = self.stack.pop(); if let Some(Value::BlobInstance(ty, values)) = inst { @@ -519,14 +539,14 @@ impl VM { Op::Set(field) => { let value = self.stack.pop().unwrap(); - let inst = self.stack.pop(); - if let Some(Value::BlobInstance(ty, _)) = inst { + let inst = self.stack.pop().unwrap(); + if let Value::BlobInstance(ty, _) = inst { let ty = &self.blobs[ty].name_to_field.get(&field).unwrap().1; if ty != &Type::from(&value) { - error!(self, ErrorKind::RuntimeTypeError(Op::Set(field.clone()), vec![inst.unwrap()])); + error!(self, ErrorKind::RuntimeTypeError(Op::Set(field.clone()), vec![inst])); } } else { - error!(self, ErrorKind::RuntimeTypeError(Op::Set(field.clone()), vec![inst.unwrap()])); + error!(self, ErrorKind::RuntimeTypeError(Op::Set(field.clone()), vec![inst])); } } |
