aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdvard Thörnros <edvard.thornros@gmail.com>2021-01-30 22:34:19 +0100
committerEdvard Thörnros <edvard.thornros@gmail.com>2021-01-30 22:34:19 +0100
commit4253c1c20013ab16564aa3ec34585dd1a358d182 (patch)
treef1d96d0aa8c4af949b1284129d6366d697139bb0
parent1a82b85817646aded501051f4e9d651f7c0d4970 (diff)
downloadsylt-4253c1c20013ab16564aa3ec34585dd1a358d182.tar.gz
add in tuples
-rw-r--r--src/compiler.rs27
-rw-r--r--src/error.rs6
-rw-r--r--src/lib.rs4
-rw-r--r--src/vm.rs28
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)
}
diff --git a/src/lib.rs b/src/lib.rs
index 248a589..9a9aaa7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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,
diff --git a/src/vm.rs b/src/vm.rs
index fa998b8..51d3245 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -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]));
}
}