diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/compiler.rs | 74 | ||||
| -rw-r--r-- | src/typer.rs | 65 | ||||
| -rw-r--r-- | src/vm.rs | 24 |
3 files changed, 93 insertions, 70 deletions
diff --git a/src/compiler.rs b/src/compiler.rs index 282e582..e32270e 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,6 +1,5 @@ use std::path::{Path, PathBuf}; use std::rc::Rc; -use std::convert::TryFrom; use crate::tokenizer::{Token, TokenStream}; use crate::vm::{Value, Block, Op}; @@ -55,7 +54,7 @@ pub enum Type { Float, Bool, String, - Function(Rc<Block>), + Function(Vec<Type>, Box<Type>), } impl PartialEq for Type { @@ -66,25 +65,22 @@ impl PartialEq for Type { (Type::Float, Type::Float) => true, (Type::Bool, Type::Bool) => true, (Type::String, Type::String) => true, - (Type::Function(a), Type::Function(b)) => { - a.args == b.args && a.ret == b.ret - }, + (Type::Function(a_args, a_ret), Type::Function(b_args, b_ret)) => + a_args == b_args && a_ret == b_ret, _ => false, } } } impl From<&Value> for Type { - fn from(value: &Value) -> Type { match value { Value::Int(_) => Type::Int, Value::Float(_) => Type::Float, Value::Bool(_) => Type::Bool, Value::String(_) => Type::String, - Value::Function(_, block) => { - Type::Function(Rc::clone(block)) - }, + Value::Function(args, ret, _) => + Type::Function(args.clone(), Box::new(ret.clone())), _ => Type::NoType, } } @@ -425,9 +421,9 @@ impl Compiler { "anonumus function" }; - let mut return_type = None; + let mut args = Vec::new(); + let mut return_type = Type::NoType; let mut function_block = Block::new(name, &self.current_file, self.line()); - let arity; let _ret = push_frame!(self, function_block, { loop { match self.peek() { @@ -435,7 +431,7 @@ impl Compiler { self.eat(); expect!(self, Token::Colon, "Expected ':' after parameter name."); if let Ok(typ) = self.parse_type() { - function_block.args.push(typ.clone()); + args.push(typ.clone()); if let Ok(slot) = self.define_variable(&name, typ, &mut function_block) { self.stack_mut()[slot].active = true; } @@ -447,13 +443,12 @@ impl Compiler { } } Token::LeftBrace => { - return_type = Some(Type::NoType); break; } Token::Arrow => { self.eat(); if let Ok(typ) = self.parse_type() { - return_type = Some(typ); + return_type = typ; } else { error!(self, "Failed to parse return type."); } @@ -465,19 +460,17 @@ impl Compiler { } } } - arity = self.frame().stack.len() - 1; + println!("({:?} -> {:?})", args, return_type); self.scope(&mut function_block); }); - match return_type { - Some(typ) => function_block.ret = typ, - None => error!(self, "No returntype secified!"), + if !matches!(function_block.last_op(), Some(&Op::Return)) { + function_block.add(Op::Constant(Value::Nil), self.line()); + function_block.add(Op::Return, self.line()); } - function_block.add(Op::Return, self.line()); - - block.add(Op::Constant(Value::Function(arity, Rc::new(function_block))), self.line()); + block.add(Op::Constant(Value::Function(args, return_type, Rc::new(function_block))), self.line()); } fn variable_expression(&mut self, block: &mut Block) { @@ -615,8 +608,42 @@ impl Compiler { } fn parse_type(&mut self) -> Result<Type, ()> { - match self.eat() { + match self.peek() { + Token::Fn => { + self.eat(); + let mut params = Vec::new(); + let return_type = loop { + match self.peek() { + Token::Identifier(_) | Token::Fn => { + if let Ok(ty) = self.parse_type() { + params.push(ty); + if self.peek() == Token::Comma { + self.eat(); + } + } else { + error!(self, format!("Function type signature contains non-type {:?}.", self.peek())); + return Err(()); + } + } + Token::Arrow => { + self.eat(); + break self.parse_type().unwrap_or(Type::NoType); + } + Token::Comma | Token::Equal => { + break Type::NoType; + } + token => { + error!(self, format!("Function type signature contains non-type {:?}.", token)); + return Err(()); + } + } + }; + let f = Type::Function(params, Box::new(return_type)); + println!("Parsed {:?} on line {}", f, self.line()); + Ok(f) + } Token::Identifier(x) => { + self.eat(); match x.as_str() { "int" => Ok(Type::Int), "float" => Ok(Type::Float), @@ -624,7 +651,7 @@ impl Compiler { "str" => Ok(Type::String), _ => Err(()), } - }, + } _ => Err(()), } @@ -710,7 +737,6 @@ impl Compiler { expect!(self, Token::Newline, "Expect newline after expression."); } block.add(Op::Return, self.line()); - block.ret = Type::NoType; if self.errors.is_empty() { Ok(block) diff --git a/src/typer.rs b/src/typer.rs index f5b0e00..d7b76b9 100644 --- a/src/typer.rs +++ b/src/typer.rs @@ -5,6 +5,7 @@ use std::path::PathBuf; use std::collections::HashSet; use crate::compiler::Type; +use crate::vm::Value; use crate::vm::{Op, Block}; use crate::error::{Error, ErrorKind}; @@ -96,7 +97,7 @@ impl VM { } } - pub fn typecheck(&mut self, block: Rc<Block>) -> Result<(), Error>{ + pub fn typecheck(&mut self, return_type: Type, block: Rc<Block>) -> Result<(), Error>{ let id = block.id(); if self.checked.contains(&id) { return Ok(()); @@ -131,7 +132,7 @@ impl VM { print!(" "); } match s { - Type::Function(block) => print!("Function({:?} -> {:?})", block.args.green(), block.ret.green()), + Type::Function(args, ret) => print!("Function({:?} -> {:?})", args.green(), ret.green()), s => print!("{:?}", s.green()), } } @@ -153,8 +154,24 @@ impl VM { } Op::Constant(value) => { - let typ = Type::from(&value); - self.stack.push(typ); + let ty = Type::from(&value); + if let Value::Function(args, ret, block) = value { + let mut stack = vec![ret.clone()]; + stack.extend_from_slice(&args); + + let mut sub = VM { + checked: self.checked.clone(), + stack, + frames: vec![], + print_blocks: self.print_blocks, + print_ops: self.print_ops, + }; + + sub.typecheck(ret.clone(), Rc::clone(&block))?; + + self.checked = sub.checked; + } + self.stack.push(ty); } Op::Neg => { @@ -237,7 +254,7 @@ impl VM { match (&lhs, &rhs) { (Type::UnkownType, rhs) => { if rhs == &Type::UnkownType { - error!(self, ErrorKind::TypeError(op.clone(), vec![lhs, rhs.clone()]), "Cannot infer type."); + error!(self, ErrorKind::TypeError(op.clone(), vec![lhs, rhs.clone()]), ""); } else { self.stack[slot] = rhs.clone(); } @@ -251,42 +268,23 @@ impl VM { Op::Call(num_args) => { let new_base = self.stack.len() - 1 - num_args; match &self.stack[new_base] { - Type::Function(block) => { - let arity = block.args.len(); - if arity != num_args { + Type::Function(args, ret) => { + if args.len() != num_args { error!(self, ErrorKind::InvalidProgram, format!("Invalid number of arguments, got {} expected {}.", - num_args, arity)); - } - if self.print_blocks { - block.debug_print(); + num_args, args.len())); } - let stack_args = &self.stack[self.stack.len() - arity..]; - if block.args != stack_args { + let stack_args = &self.stack[self.stack.len() - args.len()..]; + if args != stack_args { error!(self, ErrorKind::TypeError(op.clone(), vec![]), format!("Expected args of type {:?} but got {:?}.", - block.args, stack_args)); + args, stack_args)); } - let mut stack = vec![block.ret.clone()]; - stack.extend_from_slice(stack_args); - - let mut sub = VM { - checked: self.checked.clone(), - stack, - frames: vec![], - print_blocks: self.print_blocks, - print_ops: self.print_ops, - }; - - sub.typecheck(Rc::clone(block))?; - - self.checked = sub.checked; - - self.stack[new_base] = block.ret.clone(); + self.stack[new_base] = *ret.clone(); }, _ => { unreachable!() @@ -311,9 +309,8 @@ impl VM { } let a = self.stack.pop().unwrap_or(Type::NoType); - let b = self.frame().block.ret.clone(); - if a != b { - error!(self, ErrorKind::TypeError(op, vec![a, b]), "Not matching return type."); + if a != return_type { + error!(self, ErrorKind::TypeError(op, vec![a, return_type.clone()]), "Not matching return type."); } } } @@ -22,7 +22,8 @@ pub enum Value { Int(i64), Bool(bool), String(Rc<String>), - Function(usize, Rc<Block>), + Function(Vec<Type>, Type, Rc<Block>), + Nil, } impl Debug for Value { @@ -32,7 +33,8 @@ 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(arity, block) => write!(fmt, "(func {}-{})", block.name, arity), + Value::Function(args, ret, block) => write!(fmt, "(fn {}: {:?} -> {:?})", block.name, args, ret), + Value::Nil => write!(fmt, "(nil)"), } } } @@ -75,9 +77,6 @@ pub enum Op { #[derive(Debug)] pub struct Block { - pub args: Vec<Type>, - pub ret: Type, - pub name: String, pub file: PathBuf, pub ops: Vec<Op>, @@ -89,9 +88,6 @@ pub struct Block { impl Block { pub fn new(name: &str, file: &Path, line: usize) -> Self { Self { - args: Vec::new(), - ret: Type::UnkownType, - name: String::from(name), file: file.to_owned(), ops: Vec::new(), @@ -105,6 +101,10 @@ impl Block { (self.file.clone(), self.line) } + pub fn last_op(&self) -> Option<&Op> { + self.ops.last() + } + pub fn add_line(&mut self, token_position: usize) { if token_position != self.last_line_offset { self.line_offsets.insert(self.curr(), token_position); @@ -228,7 +228,7 @@ impl VM { } pub fn run(&mut self, block: Rc<Block>) -> Result<(), Error>{ - if let Err(err) = crate::typer::VM::new().print_ops(true).typecheck(Rc::clone(&block)) { + if let Err(err) = crate::typer::VM::new().print_ops(true).typecheck(Type::NoType, Rc::clone(&block)) { println!("TYPE ERROR: {}", err); } @@ -404,12 +404,12 @@ impl VM { Op::Call(num_args) => { let new_base = self.stack.len() - 1 - num_args; match &self.stack[new_base] { - Value::Function(arity, block) => { - if arity != &num_args { + Value::Function(args, ret, block) => { + if args.len() != num_args { error!(self, ErrorKind::InvalidProgram, format!("Invalid number of arguments, got {} expected {}.", - num_args, arity)); + num_args, args.len())); } if self.print_blocks { block.debug_print(); |
