aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/compiler.rs23
-rw-r--r--src/typer.rs3
-rw-r--r--src/vm.rs228
3 files changed, 230 insertions, 24 deletions
diff --git a/src/compiler.rs b/src/compiler.rs
index d3f442e..1a71482 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -79,13 +79,26 @@ impl From<&Value> for Type {
Value::Float(_) => Type::Float,
Value::Bool(_) => Type::Bool,
Value::String(_) => Type::String,
- Value::Function(args, ret, _) =>
- Type::Function(args.clone(), Box::new(ret.clone())),
+ Value::Function(block) => block.ty.clone(),
_ => Type::Void,
}
}
}
+impl Type {
+ pub fn as_value(&self) -> Value {
+ match self {
+ Type::Void => Value::Nil,
+ Type::UnknownType => Value::Unkown,
+ Type::Int => Value::Int(1),
+ Type::Float => Value::Float(1.0),
+ Type::Bool => Value::Bool(true),
+ Type::String => Value::String(Rc::new("".to_string())),
+ Type::Function(_, _) => Value::Function(Rc::new(Block::from_type(self))),
+ }
+ }
+}
+
struct Variable {
name: String,
typ: Type,
@@ -469,7 +482,9 @@ impl Compiler {
function_block.add(Op::Return, self.line());
}
- block.add(Op::Constant(Value::Function(args, return_type, Rc::new(function_block))), self.line());
+ function_block.ty = Type::Function(args, Box::new(return_type));
+
+ block.add(Op::Constant(Value::Function(Rc::new(function_block))), self.line());
}
fn variable_expression(&mut self, block: &mut Block) {
@@ -729,7 +744,9 @@ impl Compiler {
self.statement(&mut block);
expect!(self, Token::Newline | Token::EOF, "Expect newline or EOF after expression.");
}
+ block.add(Op::Constant(Value::Nil), self.line());
block.add(Op::Return, self.line());
+ block.ty = Type::Function(Vec::new(), Box::new(Type::Void));
if self.errors.is_empty() {
Ok(block)
diff --git a/src/typer.rs b/src/typer.rs
index 44aaabb..9867e9e 100644
--- a/src/typer.rs
+++ b/src/typer.rs
@@ -144,6 +144,8 @@ impl VM {
}
match op {
+ _ => {}
+ /*
Op::Illegal => {}
Op::Unreachable => {}
@@ -327,6 +329,7 @@ impl VM {
error!(self, ErrorKind::TypeError(op, vec![a, return_type.clone()]), "Not matching return type.");
}
}
+ */
}
self.frame_mut().ip += 1;
}
diff --git a/src/vm.rs b/src/vm.rs
index e78b914..71923b8 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -22,7 +22,8 @@ pub enum Value {
Int(i64),
Bool(bool),
String(Rc<String>),
- Function(Vec<Type>, Type, Rc<Block>),
+ Function(Rc<Block>),
+ Unkown,
Nil,
}
@@ -33,12 +34,36 @@ impl Debug for Value {
Value::Int(i) => write!(fmt, "(int {})", i),
Value::Bool(b) => write!(fmt, "(bool {})", b),
Value::String(s) => write!(fmt, "(string \"{}\")", s),
- Value::Function(args, ret, block) => write!(fmt, "(fn {}: {:?} -> {:?})", block.name, args, ret),
+ Value::Function(block) => write!(fmt, "(fn {}: {:?})", block.name, block.ty),
+ Value::Unkown => write!(fmt, "(unkown)"),
Value::Nil => write!(fmt, "(nil)"),
}
}
}
+impl Value {
+ fn identity(self) -> Self {
+ match self {
+ Value::Float(_) => Value::Float(1.0),
+ Value::Int(_) => Value::Int(1),
+ Value::Bool(_) => Value::Bool(true),
+ a => a,
+ }
+ }
+
+ fn as_type(&self) -> Type {
+ match self {
+ Value::Float(_) => Type::Float,
+ Value::Int(_) => Type::Int,
+ Value::Bool(_) => Type::Bool,
+ Value::String(_) => Type::String,
+ Value::Function(block) => block.ty.clone(),
+ Value::Unkown => Type::UnknownType,
+ Value::Nil => Type::Void,
+ }
+ }
+}
+
#[derive(Debug, Clone)]
pub enum Op {
Illegal,
@@ -79,6 +104,8 @@ pub enum Op {
#[derive(Debug)]
pub struct Block {
+ pub ty: Type,
+
pub name: String,
pub file: PathBuf,
pub ops: Vec<Op>,
@@ -90,6 +117,7 @@ pub struct Block {
impl Block {
pub fn new(name: &str, file: &Path, line: usize) -> Self {
Self {
+ ty: Type::Void,
name: String::from(name),
file: file.to_owned(),
ops: Vec::new(),
@@ -99,6 +127,28 @@ impl Block {
}
}
+ pub fn from_type(ty: &Type) -> Self {
+ let mut block = Block::new("/empty/", Path::new(""), 0);
+ block.ty = ty.clone();
+ block
+ }
+
+ pub fn args(&self) -> &Vec<Type> {
+ if let Type::Function(ref args, _) = self.ty {
+ args
+ } else {
+ unreachable!()
+ }
+ }
+
+ pub fn ret(&self) -> &Type {
+ if let Type::Function(_, ref ret) = self.ty {
+ ret
+ } else {
+ unreachable!()
+ }
+ }
+
pub fn id(&self) -> (PathBuf, usize) {
(self.file.clone(), self.line)
}
@@ -203,6 +253,10 @@ impl VM {
self
}
+ fn pop(&mut self) -> Value {
+ self.stack.pop().unwrap()
+ }
+
fn pop_twice(&mut self) -> (Value, Value) {
let len = self.stack.len();
let res = (self.stack[len-2].clone(), self.stack[len-1].clone());
@@ -224,6 +278,11 @@ impl VM {
&mut self.frames[last]
}
+ fn op(&self) -> &Op {
+ let ip = self.frame().ip;
+ &self.frame().block.ops[ip]
+ }
+
fn error(&self, kind: ErrorKind, message: Option<String>) -> Error {
let frame = self.frames.last().unwrap();
Error {
@@ -234,7 +293,7 @@ impl VM {
}
}
- fn eval_op(&mut self, op: &Op) -> Result<OpResult, Error> {
+ fn eval_op(&mut self, op: Op) -> Result<OpResult, Error> {
match op {
Op::Illegal => {
error!(self, ErrorKind::InvalidProgram);
@@ -256,7 +315,7 @@ impl VM {
match self.stack.pop().unwrap() {
Value::Float(a) => self.stack.push(Value::Float(-a)),
Value::Int(a) => self.stack.push(Value::Int(-a)),
- a => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a])),
+ a => error!(self, ErrorKind::RuntimeTypeError(op, vec![a])),
}
}
@@ -267,7 +326,7 @@ impl VM {
(Value::String(a), Value::String(b)) => {
self.stack.push(Value::String(Rc::from(format!("{}{}", a, b))))
}
- (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])),
+ (a, b) => error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])),
}
}
@@ -275,7 +334,7 @@ impl VM {
match self.pop_twice() {
(Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(a - b)),
(Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(a - b)),
- (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])),
+ (a, b) => error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])),
}
}
@@ -283,7 +342,7 @@ impl VM {
match self.pop_twice() {
(Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(a * b)),
(Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(a * b)),
- (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])),
+ (a, b) => error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])),
}
}
@@ -291,7 +350,7 @@ impl VM {
match self.pop_twice() {
(Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(a / b)),
(Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(a / b)),
- (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])),
+ (a, b) => error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])),
}
}
@@ -301,7 +360,7 @@ impl VM {
(Value::Int(a), Value::Int(b)) => self.stack.push(Value::Bool(a == b)),
(Value::String(a), Value::String(b)) => self.stack.push(Value::Bool(a == b)),
(Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a == b)),
- (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])),
+ (a, b) => error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])),
}
}
@@ -311,7 +370,7 @@ impl VM {
(Value::Int(a), Value::Int(b)) => self.stack.push(Value::Bool(a < b)),
(Value::String(a), Value::String(b)) => self.stack.push(Value::Bool(a < b)),
(Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a < b)),
- (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])),
+ (a, b) => error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])),
}
}
@@ -321,39 +380,39 @@ impl VM {
(Value::Int(a), Value::Int(b)) => self.stack.push(Value::Bool(a > b)),
(Value::String(a), Value::String(b)) => self.stack.push(Value::Bool(a > b)),
(Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a > b)),
- (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])),
+ (a, b) => error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])),
}
}
Op::And => {
match self.pop_twice() {
(Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a && b)),
- (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])),
+ (a, b) => error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])),
}
}
Op::Or => {
match self.pop_twice() {
(Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a || b)),
- (a, b) => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a, b])),
+ (a, b) => error!(self, ErrorKind::RuntimeTypeError(op, vec![a, b])),
}
}
Op::Not => {
match self.stack.pop().unwrap() {
Value::Bool(a) => self.stack.push(Value::Bool(!a)),
- a => error!(self, ErrorKind::RuntimeTypeError(op.clone(), vec![a])),
+ a => error!(self, ErrorKind::RuntimeTypeError(op, vec![a])),
}
}
Op::Jmp(line) => {
- self.frame_mut().ip = *line;
+ self.frame_mut().ip = line;
return Ok(OpResult::Continue);
}
Op::JmpFalse(line) => {
if matches!(self.stack.pop(), Some(Value::Bool(false))) {
- self.frame_mut().ip = *line;
+ self.frame_mut().ip = line;
return Ok(OpResult::Continue);
}
}
@@ -380,8 +439,9 @@ impl VM {
Op::Call(num_args) => {
let new_base = self.stack.len() - 1 - num_args;
match &self.stack[new_base] {
- Value::Function(args, _ret, block) => {
- if args.len() != *num_args {
+ Value::Function(block) => {
+ let args = block.args();
+ if args.len() != num_args {
error!(self,
ErrorKind::InvalidProgram,
format!("Invalid number of arguments, got {} expected {}.",
@@ -420,7 +480,7 @@ impl VM {
Ok(OpResult::Continue)
}
- pub fn print_stack(&mut self) {
+ pub fn print_stack(&self) {
let start = self.frame().stack_offset;
print!(" {:3} [", start);
for (i, s) in self.stack.iter().skip(start).enumerate() {
@@ -457,10 +517,136 @@ impl VM {
self.print_stack()
}
- let op = self.frame().block.ops[self.frame().ip].clone();
- if matches!(self.eval_op(&op)?, OpResult::Done) {
+ if matches!(self.eval_op(self.op().clone())?, OpResult::Done) {
return Ok(());
}
}
}
+
+ fn check_op(&mut self, op: Op) -> Result<(), Error> {
+ match op {
+ Op::Jmp(_line) => {}
+
+ Op::Return => {
+ let a = self.stack.pop().unwrap();
+ let ret = self.frame().block.ret();
+ if a.as_type() != *ret {
+ error!(self, ErrorKind::TypeError(op, vec![a.as_type(),
+ ret.clone()]),
+ "Not matching return type.".to_string());
+ }
+ }
+
+ Op::Print => {
+ self.pop();
+ }
+
+ Op::Define(ref ty) => {
+ let top_type = self.stack.last().unwrap().as_type();
+ match (ty, top_type) {
+ (Type::UnknownType, top_type)
+ if top_type != Type::UnknownType => {}
+ (a, b) if a != &b => {
+ error!(self,
+ ErrorKind::TypeError(
+ op.clone(),
+ vec![a.clone(), b.clone()]),
+ format!("Tried to assign a type {:?} to type {:?}.", a, b)
+ );
+ }
+ _ => {}
+ }
+ }
+
+ Op::Call(num_args) => {
+ let new_base = self.stack.len() - 1 - num_args;
+ match &self.stack[new_base] {
+ Value::Function(block) => {
+ let args = block.args();
+ if args.len() != num_args {
+ error!(self,
+ ErrorKind::InvalidProgram,
+ format!("Invalid number of arguments, got {} expected {}.",
+ num_args, args.len()));
+ }
+
+ let stack_args = &self.stack[self.stack.len() - args.len()..];
+ let stack_args: Vec<_> = stack_args.iter().map(|x| x.as_type()).collect();
+ if args != &stack_args {
+ error!(self,
+ ErrorKind::TypeError(op.clone(), vec![]),
+ format!("Expected args of type {:?} but got {:?}.",
+ args, stack_args));
+ }
+
+ self.stack[new_base] = block.ret().as_value();
+ },
+ _ => {
+ error!(self,
+ ErrorKind::TypeError(op.clone(), vec![self.stack[new_base].as_type()]),
+ format!("Tried to call non-function {:?}", self.stack[new_base]));
+ }
+ }
+ }
+
+ Op::JmpFalse(_) => {
+ match self.pop() {
+ Value::Bool(_) => {},
+ a => { error!(self, ErrorKind::TypeError(op.clone(), vec![a.as_type()])) },
+ }
+ }
+ _ => {
+ self.eval_op(op)?;
+ return Ok(())
+ }
+ }
+ self.frame_mut().ip += 1;
+ Ok(())
+ }
+
+ fn typecheck_block(&mut self, block: Rc<Block>) -> Vec<Error> {
+ self.frames.clear();
+
+ self.frames.push(Frame {
+ stack_offset: 0,
+ block: block,
+ ip: 0
+ });
+
+ if self.print_blocks {
+ self.frame().block.debug_print();
+ }
+
+ let mut errors = Vec::new();
+ loop {
+ let ip = self.frame().ip;
+ if ip > self.frame().block.ops.len() {
+ break;
+ }
+
+ if self.print_ops {
+ self.print_stack()
+ }
+
+ if let Err(e) = self.check_op(self.op().clone()) {
+ errors.push(e);
+ }
+
+ if !self.stack.is_empty() {
+ let ident = self.stack.pop().unwrap().identity();
+ self.stack.push(ident);
+ }
+ }
+ errors
+ }
+
+ pub fn typecheck(&mut self, blocks: Vec<Rc<Block>>) -> Result<(), Vec<Error>> {
+ let mut errors = Vec::new();
+
+ for block in blocks.iter() {
+ errors.append(&mut self.typecheck_block(Rc::clone(block)));
+ }
+
+ return Ok(());
+ }
}