aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TODO21
-rw-r--r--src/compiler.rs75
-rw-r--r--src/error.rs6
-rw-r--r--src/lib.rs143
-rw-r--r--src/vm.rs150
5 files changed, 297 insertions, 98 deletions
diff --git a/TODO b/TODO
index 84e970d..2f9af09 100644
--- a/TODO
+++ b/TODO
@@ -4,3 +4,24 @@ PONG
- foreign structs
- graphics api
- parse input
+
+BACKLOG
+ - Dåliga typfelmedelanden
+ LESS, ADD ...
+ - +=, -=, ...
+ - constanter
+ - initializers
+ - infinet loops
+ - default initalization
+ - std-lib
+ - vectorer
+ - (1, 2) + (3, 4) = (4, 6)
+ - bättre rust functions länkning
+ - listor
+ - set
+ - escape newline
+ - variable not found in outer scope - SHould crash not infinet loop
+ - Show stack values affected
+ - Debugmode -- ensure stack semantics (like pop2)
+ - else -- syntax highlight
+ - automatic epsilon on floats
diff --git a/src/compiler.rs b/src/compiler.rs
index 69bf6eb..9a1d1e5 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),
@@ -315,6 +315,8 @@ impl Compiler {
| Token::NotEqual
=> self.binary(block),
+ Token::LeftBracket => self.index(block),
+
_ => { return false; },
}
return true;
@@ -331,6 +333,48 @@ 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;
+ match self.peek() {
+ Token::Comma => { self.eat(); },
+ Token::RightParen => {},
+ _ => { 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.");
@@ -339,6 +383,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,
@@ -473,8 +526,8 @@ impl Compiler {
let mut function_block = Block::new(&name, &self.current_file, self.line());
let block_id = self.blocks.len();
- let new_block = Block::new(&name, &self.current_file, self.line());
- self.blocks.push(Rc::new(RefCell::new(new_block)));
+ let temp_block = Block::new(&name, &self.current_file, self.line());
+ self.blocks.push(Rc::new(RefCell::new(temp_block)));
let _ret = push_frame!(self, function_block, {
loop {
@@ -782,6 +835,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 453d6ce..336a7e2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -323,6 +323,14 @@ a() <=> 4
5 <=> a.a + a.b"
);
+ test_multiple!(tuples,
+ add: "(1, 2, 3, 4) + (4, 3, 2, 1) <=> (5, 5, 5, 5)",
+ sub: "(1, -2, 3, -4) - (4, 3, -2, -1) <=> (-3, 1, 1, -5)",
+ mul: "(0, 1, 2) * (2, 3, 4) <=> (0, 3, 8)",
+ types: "a: (int, float, int) = (1, 1., 1)",
+ more_types: "a: (str, bool, int) = (\"abc\", true, 1)",
+ );
+
test_file!(scoping, "tests/scoping.tdy");
test_file!(for_, "tests/for.tdy");
@@ -351,6 +359,7 @@ a.a <=> 0"
pub enum Value {
Blob(usize),
BlobInstance(usize, Rc<RefCell<Vec<Value>>>),
+ Tuple(Rc<Vec<Value>>),
Float(f64),
Int(i64),
Bool(bool),
@@ -415,10 +424,114 @@ 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),
}
}
}
+mod op {
+ use super::Value;
+ use std::rc::Rc;
+
+ fn tuple_op(a: &Rc<Vec<Value>>, b: &Rc<Vec<Value>>, f: fn (&Value, &Value) -> Value) -> Value {
+ Value::Tuple(Rc::new(a.iter().zip(b.iter()).map(|(a, b)| f(a, b)).collect()))
+ }
+
+ pub fn neg(value: &Value) -> Value {
+ match value {
+ Value::Float(a) => Value::Float(-a),
+ Value::Int(a) => Value::Int(-a),
+ Value::Tuple(a) => Value::Tuple(Rc::new(a.iter().map(neg).collect())),
+ _ => Value::Nil,
+ }
+ }
+
+ pub fn not(value: &Value) -> Value {
+ match value {
+ Value::Bool(a) => Value::Bool(!a),
+ Value::Tuple(a) => Value::Tuple(Rc::new(a.iter().map(not).collect())),
+ _ => Value::Nil,
+ }
+ }
+
+
+ pub fn add(a: &Value, b: &Value) -> Value {
+ match (a, b) {
+ (Value::Float(a), Value::Float(b)) => Value::Float(a + b),
+ (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_op(a, b, add),
+ _ => Value::Nil,
+ }
+ }
+
+ pub fn sub(a: &Value, b: &Value) -> Value {
+ add(a, &neg(b))
+ }
+
+ pub fn mul(a: &Value, b: &Value) -> Value {
+ match (a, b) {
+ (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_op(a, b, mul),
+ _ => Value::Nil,
+ }
+ }
+
+ pub fn div(a: &Value, b: &Value) -> Value {
+ match (a, b) {
+ (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_op(a, b, div),
+ _ => Value::Nil,
+ }
+ }
+
+ pub fn eq(a: &Value, b: &Value) -> Value {
+ match (a, b) {
+ (Value::Float(a), Value::Float(b)) => Value::Bool(a == b),
+ (Value::Int(a), Value::Int(b)) => Value::Bool(a == b),
+ (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_op(a, b, eq),
+ _ => Value::Nil,
+ }
+ }
+
+ pub fn less(a: &Value, b: &Value) -> Value {
+ match (a, b) {
+ (Value::Float(a), Value::Float(b)) => Value::Bool(a < b),
+ (Value::Int(a), Value::Int(b)) => Value::Bool(a < b),
+ (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_op(a, b, less),
+ _ => Value::Nil,
+ }
+ }
+
+ pub fn greater(a: &Value, b: &Value) -> Value {
+ less(b, a)
+ }
+
+ pub fn and(a: &Value, b: &Value) -> Value {
+ 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_op(a, b, and),
+ _ => Value::Nil,
+ }
+ }
+
+ pub fn or(a: &Value, b: &Value) -> Value {
+ 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_op(a, b, or),
+ _ => Value::Nil,
+ }
+ }
+
+}
+
+
impl Value {
fn identity(self) -> Self {
match self {
@@ -429,20 +542,16 @@ impl Value {
}
}
- fn as_type(&self) -> Type {
+ fn is_nil(&self) -> bool {
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,
+ Value::Nil => true,
+ _ => false,
}
}
+
+ fn as_type(&self) -> Type {
+ Type::from(self)
+ }
}
#[derive(Debug, Clone)]
@@ -453,7 +562,9 @@ pub enum Op {
PopUpvalue,
Copy,
Constant(Value),
+ Tuple(usize),
+ Index,
Get(String),
Set(String),
@@ -622,6 +733,7 @@ pub enum Type {
Float,
Bool,
String,
+ Tuple(Vec<Type>),
Function(Vec<Type>, Box<Type>),
Blob(usize),
BlobInstance(usize),
@@ -637,6 +749,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,
@@ -649,6 +764,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,
@@ -672,6 +790,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 6ff7b65..246728d 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -6,7 +6,7 @@ use std::rc::Rc;
use owo_colors::OwoColorize;
-use crate::{Blob, Block, Op, Prog, UpValue, Value};
+use crate::{Blob, Block, Op, Prog, UpValue, Value, op};
use crate::error::{Error, ErrorKind};
use crate::RustFunction;
pub use crate::Type;
@@ -20,6 +20,30 @@ macro_rules! error {
};
}
+macro_rules! one_op {
+ ( $self:expr, $op:expr, $fun:expr ) => {
+ let a = $self.pop();
+ let b = $fun(&a);
+ if b.is_nil() {
+ $self.push(b);
+ error!($self, ErrorKind::RuntimeTypeError($op, vec![a]));
+ }
+ $self.push(b);
+ };
+}
+
+macro_rules! two_op {
+ ( $self:expr, $op:expr, $fun:expr ) => {
+ let (a, b) = $self.poppop();
+ let c = $fun(&a, &b);
+ if c.is_nil() {
+ $self.push(c);
+ error!($self, ErrorKind::RuntimeTypeError($op, vec![a, b]));
+ }
+ $self.push(c);
+ };
+}
+
#[derive(Debug)]
struct Frame {
stack_offset: usize,
@@ -105,6 +129,10 @@ impl VM {
(b, a) // this matches the order they were on the stack
}
+ fn push(&mut self, value: Value) {
+ self.stack.push(value)
+ }
+
fn _peek_up(&self, amount: usize) -> Option<&Value> {
self.stack.get(self.stack.len() - amount)
}
@@ -159,6 +187,11 @@ impl VM {
self.pop();
}
+ 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.pop();
let slot = self.stack.len();
@@ -201,6 +234,26 @@ impl VM {
self.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.pop();
if let Value::BlobInstance(ty, values) = inst {
@@ -222,99 +275,27 @@ impl VM {
}
}
- Op::Neg => {
- match self.pop() {
- Value::Float(a) => self.push(Value::Float(-a)),
- Value::Int(a) => self.push(Value::Int(-a)),
- a => error!(self, ErrorKind::RuntimeTypeError(op, vec![a])),
- }
- }
+ Op::Neg => { one_op!(self, Op::Neg, op::neg); }
- Op::Add => {
- match self.poppop() {
- (Value::Float(a), Value::Float(b)) => self.push(Value::Float(a + b)),
- (Value::Int(a), Value::Int(b)) => self.push(Value::Int(a + b)),
- (Value::String(a), Value::String(b)) => {
- self.push(Value::String(Rc::from(format!("{}{}", a, b))))
- }
- (a, b) => error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])),
- }
- }
+ Op::Add => { two_op!(self, Op::Add, op::add); }
- Op::Sub => {
- match self.poppop() {
- (Value::Float(a), Value::Float(b)) => self.push(Value::Float(a - b)),
- (Value::Int(a), Value::Int(b)) => self.push(Value::Int(a - b)),
- (a, b) => error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])),
- }
- }
+ Op::Sub => { two_op!(self, Op::Sub, op::sub); }
- Op::Mul => {
- match self.poppop() {
- (Value::Float(a), Value::Float(b)) => self.push(Value::Float(a * b)),
- (Value::Int(a), Value::Int(b)) => self.push(Value::Int(a * b)),
- (a, b) => error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])),
- }
- }
+ Op::Mul => { two_op!(self, Op::Mul, op::mul); }
- Op::Div => {
- match self.poppop() {
- (Value::Float(a), Value::Float(b)) => self.push(Value::Float(a / b)),
- (Value::Int(a), Value::Int(b)) => self.push(Value::Int(a / b)),
- (a, b) => error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])),
- }
- }
+ Op::Div => { two_op!(self, Op::Div, op::div); }
- Op::Equal => {
- match self.poppop() {
- (Value::Float(a), Value::Float(b)) => self.push(Value::Bool(a == b)),
- (Value::Int(a), Value::Int(b)) => self.push(Value::Bool(a == b)),
- (Value::String(a), Value::String(b)) => self.push(Value::Bool(a == b)),
- (Value::Bool(a), Value::Bool(b)) => self.push(Value::Bool(a == b)),
- (a, b) => error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])),
- }
- }
+ Op::Equal => { two_op!(self, Op::Equal, op::eq); }
- Op::Less => {
- match self.poppop() {
- (Value::Float(a), Value::Float(b)) => self.push(Value::Bool(a < b)),
- (Value::Int(a), Value::Int(b)) => self.push(Value::Bool(a < b)),
- (Value::String(a), Value::String(b)) => self.push(Value::Bool(a < b)),
- (Value::Bool(a), Value::Bool(b)) => self.push(Value::Bool(a < b)),
- (a, b) => error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])),
- }
- }
+ Op::Less => { two_op!(self, Op::Less, op::less); }
- Op::Greater => {
- match self.poppop() {
- (Value::Float(a), Value::Float(b)) => self.push(Value::Bool(a > b)),
- (Value::Int(a), Value::Int(b)) => self.push(Value::Bool(a > b)),
- (Value::String(a), Value::String(b)) => self.push(Value::Bool(a > b)),
- (Value::Bool(a), Value::Bool(b)) => self.push(Value::Bool(a > b)),
- (a, b) => error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])),
- }
- }
+ Op::Greater => { two_op!(self, Op::Greater, op::greater); }
- Op::And => {
- match self.poppop() {
- (Value::Bool(a), Value::Bool(b)) => self.push(Value::Bool(a && b)),
- (a, b) => error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])),
- }
- }
+ Op::And => { two_op!(self, Op::And, op::and); }
- Op::Or => {
- match self.poppop() {
- (Value::Bool(a), Value::Bool(b)) => self.push(Value::Bool(a || b)),
- (a, b) => error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])),
- }
- }
+ Op::Or => { two_op!(self, Op::Or, op::or); }
- Op::Not => {
- match self.pop() {
- Value::Bool(a) => self.push(Value::Bool(!a)),
- a => error!(self, ErrorKind::RuntimeTypeError(op, vec![a])),
- }
- }
+ Op::Not => { one_op!(self, Op::Not, op::not); }
Op::Jmp(line) => {
self.frame_mut().ip = line;
@@ -552,6 +533,7 @@ impl VM {
Op::Set(field) => {
let value = self.pop();
let inst = self.pop();
+
if let Value::BlobInstance(ty, _) = inst {
let ty = &self.blobs[ty].name_to_field.get(&field).unwrap().1;
if ty != &Type::from(&value) {