aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler.rs74
-rw-r--r--src/typer.rs65
-rw-r--r--src/vm.rs24
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.");
}
}
}
diff --git a/src/vm.rs b/src/vm.rs
index eb4de31..daf2ead 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -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();