aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/compiler.rs24
-rw-r--r--src/lib.rs13
-rw-r--r--src/typer.rs360
-rw-r--r--src/vm.rs46
4 files changed, 68 insertions, 375 deletions
diff --git a/src/compiler.rs b/src/compiler.rs
index 1a71482..1a6cfc6 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -121,6 +121,8 @@ struct Compiler {
panic: bool,
errors: Vec<Error>,
+
+ blocks: Vec<Rc<Block>>,
}
macro_rules! push_frame {
@@ -174,6 +176,8 @@ impl Compiler {
panic: false,
errors: vec![],
+
+ blocks: Vec::new(),
}
}
@@ -483,8 +487,10 @@ impl Compiler {
}
function_block.ty = Type::Function(args, Box::new(return_type));
+ let function_block = Rc::new(function_block);
- block.add(Op::Constant(Value::Function(Rc::new(function_block))), self.line());
+ block.add(Op::Constant(Value::Function(Rc::clone(&function_block))), self.line());
+ self.blocks.push(function_block);
}
fn variable_expression(&mut self, block: &mut Block) {
@@ -737,9 +743,15 @@ impl Compiler {
}
- pub fn compile(&mut self, name: &str, file: &Path) -> Result<Block, Vec<Error>> {
- let mut block = Block::new(name, file, 0);
+ pub fn compile(&mut self, name: &str, file: &Path) -> Result<Vec<Rc<Block>>, Vec<Error>> {
+ self.stack_mut().push(Variable {
+ name: String::from("/main/"),
+ typ: Type::Void,
+ scope: 0,
+ active: false,
+ });
+ let mut block = Block::new(name, file, 0);
while self.peek() != Token::EOF {
self.statement(&mut block);
expect!(self, Token::Newline | Token::EOF, "Expect newline or EOF after expression.");
@@ -748,14 +760,16 @@ impl Compiler {
block.add(Op::Return, self.line());
block.ty = Type::Function(Vec::new(), Box::new(Type::Void));
+ self.blocks.insert(0, Rc::new(block));
+
if self.errors.is_empty() {
- Ok(block)
+ Ok(self.blocks.clone())
} else {
Err(self.errors.clone())
}
}
}
-pub fn compile(name: &str, file: &Path, tokens: TokenStream) -> Result<Block, Vec<Error>> {
+pub fn compile(name: &str, file: &Path, tokens: TokenStream) -> Result<Vec<Rc<Block>>, Vec<Error>> {
Compiler::new(file, tokens).compile(name, file)
}
diff --git a/src/lib.rs b/src/lib.rs
index ce8ee51..693fb6c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -21,10 +21,15 @@ pub fn run_string(s: &str, print: bool) -> Result<(), Vec<Error>> {
pub fn run(tokens: TokenStream, path: &Path, print: bool) -> Result<(), Vec<Error>> {
match compiler::compile("main", path, tokens) {
- Ok(block) =>
- vm::VM::new().print_blocks(print)
- .print_ops(print)
- .run(Rc::new(block)).or_else(|e| Err(vec![e])),
+ Ok(blocks) => {
+ let mut vm = vm::VM::new().print_blocks(print).print_ops(print);
+ vm.typecheck(&blocks)?;
+ if let Err(e) = vm.run(Rc::clone(&blocks[0])) {
+ Err(vec![e])
+ } else {
+ Ok(())
+ }
+ }
Err(errors) => Err(errors),
}
}
diff --git a/src/typer.rs b/src/typer.rs
index 9867e9e..e69de29 100644
--- a/src/typer.rs
+++ b/src/typer.rs
@@ -1,360 +0,0 @@
-use owo_colors::OwoColorize;
-use std::collections::HashSet;
-use std::fmt::Debug;
-use std::path::PathBuf;
-use std::rc::Rc;
-
-use crate::compiler::Type;
-use crate::error::{Error, ErrorKind};
-use crate::vm::{Block, Op, Value};
-
-macro_rules! error {
- ( $thing:expr, $kind:expr) => {
- return Err($thing.error($kind, None));
- };
- ( $thing:expr, $kind:expr, $msg:expr) => {
- return Err($thing.error($kind, Some(String::from($msg))));
- };
-}
-
-#[derive(Debug)]
-struct Frame {
- stack_offset: usize,
- block: Rc<Block>,
- ip: usize,
-}
-
-#[derive(Debug)]
-pub struct VM {
- checked: HashSet<(PathBuf, usize)>,
-
- stack: Vec<Type>,
- frames: Vec<Frame>,
-
- print_blocks: bool,
- print_ops: bool,
-}
-
-impl VM {
- pub fn new() -> Self {
- Self {
- checked: HashSet::new(),
-
- stack: Vec::new(),
- frames: Vec::new(),
- print_blocks: false,
- print_ops: false,
- }
- }
-
- pub fn print_blocks(mut self, b: bool) -> Self {
- self.print_blocks = b;
- self
- }
-
- pub fn print_ops(mut self, b: bool) -> Self {
- self.print_ops = b;
- self
- }
-
- fn pop(&mut self) -> Type {
- let len = self.stack.len();
- let res = self.stack[len-1].clone();
- self.stack.truncate(len - 1);
- res
- }
-
-
- fn pop_twice(&mut self) -> (Type, Type) {
- let len = self.stack.len();
- let res = (self.stack[len - 2].clone(), self.stack[len - 1].clone());
- self.stack.truncate(len - 2);
- res
- }
-
- fn peek_up(&self, amount: usize) -> Type {
- self.stack[self.stack.len() - 1 - amount].clone()
- }
-
- fn frame(&self) -> &Frame {
- let last = self.frames.len() - 1;
- &self.frames[last]
- }
-
- fn frame_mut(&mut self) -> &mut Frame {
- let last = self.frames.len() - 1;
- &mut self.frames[last]
- }
-
- fn error(&self, kind: ErrorKind, message: Option<String>) -> Error {
- let frame = self.frames.last().unwrap();
- Error {
- kind,
- file: frame.block.file.clone(),
- line: frame.block.line(frame.ip),
- message,
- }
- }
-
- pub fn typecheck(&mut self, return_type: Type, block: Rc<Block>) -> Result<(), Error>{
- let id = block.id();
- if self.checked.contains(&id) {
- return Ok(());
- }
- self.checked.insert(id);
-
- self.frames.push(Frame {
- stack_offset: 0,
- block,
- ip: 0
- });
-
- let outer = self.stack.is_empty();
-
- if self.print_blocks {
- self.frame().block.debug_print();
- }
-
- loop {
- let ip = self.frame().ip;
- let op = self.frame().block.ops.get(ip);
- if op.is_none() {
- return Ok(());
- }
- let op = op.unwrap().clone();
-
- if self.print_ops {
- let start = self.frame().stack_offset;
- print!(" {:3} [", start);
- for (i, s) in self.stack.iter().skip(start).enumerate() {
- if i != 0 {
- print!(" ");
- }
- match s {
- Type::Function(args, ret) => print!("Function({:?} -> {:?})", args.green(), ret.green()),
- s => print!("{:?}", s.green()),
- }
- }
- println!("]");
-
- println!("{:5} {:05} {:?}",
- self.frame().block.line(self.frame().ip).red(),
- self.frame().ip.blue(),
- self.frame().block.ops[self.frame().ip]);
- }
-
- match op {
- _ => {}
- /*
- Op::Illegal => {}
-
- Op::Unreachable => {}
-
- Op::Pop => {
- self.stack.pop();
- }
-
- Op::Constant(value) => {
- 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 => {
- match self.peek_up(0) {
- Type::Float | Type::Int => {},
- a => error!(self, ErrorKind::TypeError(op.clone(), vec![a.clone()])),
- }
- }
-
- Op::Add => {
- let (a, b) = self.pop_twice();
- match (&a, &b) {
- (Type::Float, Type::Float)
- | (Type::Int, Type::Int)
- | (Type::String, Type::String) => {
- self.stack.push(a)
- }
- _ => error!(self, ErrorKind::TypeError(op.clone(), vec![a, b])),
- }
- }
-
- Op::Sub | Op::Mul | Op::Div => {
- let (a, b) = self.pop_twice();
- match (&a, &b) {
- (Type::Float, Type::Float)
- | (Type::Int, Type::Int) => self.stack.push(a),
- _ => error!(self, ErrorKind::TypeError(op.clone(), vec![a, b])),
- }
- }
-
- Op::Equal | Op::Less | Op::Greater => {
- match self.pop_twice() {
- (a, b) if (&[&a, &b]).contains(&&Type::UnknownType) =>
- error!(self, ErrorKind::TypeError(op.clone(), vec![a, b])),
- (a, b) if a == b => self.stack.push(Type::Bool),
- (a, b) => error!(self, ErrorKind::TypeError(op.clone(), vec![a, b])),
- }
- }
-
- Op::And | Op::Or => {
- match self.pop_twice() {
- (Type::Bool, Type::Bool) => self.stack.push(Type::Bool),
- (a, b) => error!(self, ErrorKind::TypeError(op.clone(), vec![a, b])),
- }
- }
-
- Op::Not => {
- match self.pop() {
- Type::Bool => { self.stack.push(Type::Bool); },
- a => { error!(self, ErrorKind::TypeError(op.clone(), vec![a])) },
- }
- }
-
- Op::Jmp(_line) => {
- }
-
- Op::JmpFalse(_line) => {
- match self.pop() {
- Type::Bool => {},
- a => { error!(self, ErrorKind::TypeError(op.clone(), vec![a])) },
- }
- }
-
- Op::Assert => {
- match self.pop() {
- Type::Bool => { self.stack.push(Type::Bool); },
- a => { error!(self, ErrorKind::TypeError(op.clone(), vec![a])) },
- }
- }
-
- Op::ReadLocal(slot) => {
- let slot = self.frame().stack_offset + slot;
- self.stack.push(self.stack[slot].clone());
- }
-
- Op::Assign(slot) => {
- let slot = self.frame().stack_offset + slot;
- let lhs = self.stack[slot].clone();
- let rhs = self.pop();
- match (&lhs, &rhs) {
- (Type::UnknownType, rhs) => {
- if rhs == &Type::UnknownType {
- error!(self, ErrorKind::TypeError(op.clone(), vec![lhs, rhs.clone()]), "");
- } else {
- self.stack[slot] = rhs.clone();
- }
- }
- (lhs, rhs) if lhs == rhs => {},
- (lhs, rhs) => error!(self,
- ErrorKind::TypeError(
- op.clone(),
- vec![lhs.clone(), rhs.clone()]
- )),
- }
- }
-
- Op::Define(ref ty) => {
- let top_type = self.stack.last().unwrap();
- 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] {
- Type::Function(args, ret) => {
- 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()..];
- 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] = *ret.clone();
- },
- _ => {
- error!(self,
- ErrorKind::TypeError(op.clone(), vec![self.stack[new_base].clone()]),
- format!("Tried to call non-function {:?}", self.stack[new_base]));
- }
- }
- }
-
- Op::Print => {
- self.pop();
- }
-
- Op::Return => {
- if outer {
- return Ok(());
- }
-
- let a = self.stack.pop().unwrap_or(Type::Void);
- if a != return_type {
- error!(self, ErrorKind::TypeError(op, vec![a, return_type.clone()]), "Not matching return type.");
- }
- }
- */
- }
- self.frame_mut().ip += 1;
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::test_string;
- use crate::error::ErrorKind;
-
- test_string!(uncallable_type, "
- f := fn i: int {
- i()
- }
- ",
- [ErrorKind::TypeError(_, _)]);
-
- test_string!(wrong_params, "
- f : fn -> int = fn a: int -> int {}
- ",
- [ErrorKind::TypeError(_, _)]);
-
- test_string!(wrong_ret, "
- f : fn -> int = fn {}
- ",
- [ErrorKind::TypeError(_, _)]);
-}
diff --git a/src/vm.rs b/src/vm.rs
index 71923b8..02d90a7 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -498,9 +498,10 @@ impl VM {
}
pub fn run(&mut self, block: Rc<Block>) -> Result<(), Error>{
- crate::typer::VM::new().print_ops(self.print_ops)
- .print_blocks(self.print_blocks)
- .typecheck(Type::Void, Rc::clone(&block))?;
+ self.stack.clear();
+ self.frames.clear();
+
+ self.stack.push(Value::Function(Rc::clone(&block)));
self.frames.push(Frame {
stack_offset: 0,
@@ -605,8 +606,14 @@ impl VM {
}
fn typecheck_block(&mut self, block: Rc<Block>) -> Vec<Error> {
+ self.stack.clear();
self.frames.clear();
+ self.stack.push(Value::Function(Rc::clone(&block)));
+ for arg in block.args() {
+ self.stack.push(arg.as_value());
+ }
+
self.frames.push(Frame {
stack_offset: 0,
block: block,
@@ -620,7 +627,7 @@ impl VM {
let mut errors = Vec::new();
loop {
let ip = self.frame().ip;
- if ip > self.frame().block.ops.len() {
+ if ip >= self.frame().block.ops.len() {
break;
}
@@ -630,6 +637,7 @@ impl VM {
if let Err(e) = self.check_op(self.op().clone()) {
errors.push(e);
+ self.frame_mut().ip += 1;
}
if !self.stack.is_empty() {
@@ -640,13 +648,39 @@ impl VM {
errors
}
- pub fn typecheck(&mut self, blocks: Vec<Rc<Block>>) -> Result<(), Vec<Error>> {
+ 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(());
+ if errors.is_empty() {
+ Ok(())
+ } else {
+ Err(errors)
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ mod typing {
+ use crate::test_string;
+ use crate::error::ErrorKind;
+
+ test_string!(uncallable_type, "
+ f := fn i: int {
+ i()
+ }",
+ [ErrorKind::TypeError(_, _)]);
+
+ test_string!(wrong_params, "
+ f : fn -> int = fn a: int -> int {}",
+ [ErrorKind::TypeError(_, _)]);
+
+ test_string!(wrong_ret, "
+ f : fn -> int = fn {}",
+ [ErrorKind::TypeError(_, _)]);
}
}