diff options
| -rw-r--r-- | src/compiler.rs | 27 | ||||
| -rw-r--r-- | src/lib.rs | 23 | ||||
| -rw-r--r-- | src/main.rs | 8 | ||||
| -rw-r--r-- | src/vm.rs | 26 | ||||
| -rw-r--r-- | tests/simple.tdy | 6 |
5 files changed, 64 insertions, 26 deletions
diff --git a/src/compiler.rs b/src/compiler.rs index 3c5498e..d31ee0d 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -181,6 +181,8 @@ impl Frame { } } +pub type RustFunction = fn(&[Value]) -> Value; + #[derive(Debug, Clone)] pub struct Blob { pub name: String, @@ -220,6 +222,8 @@ struct Compiler { blocks: Vec<Rc<RefCell<Block>>>, blobs: Vec<Blob>, + + functions: HashMap<String, (usize, RustFunction)>, } macro_rules! push_frame { @@ -283,6 +287,8 @@ impl Compiler { blocks: Vec::new(), blobs: Vec::new(), + + functions: HashMap::new(), } } @@ -509,6 +515,10 @@ impl Compiler { None } + fn find_extern_function(&self, name: &str) -> Option<usize> { + self.functions.get(name).map(|(i, _)| *i) + } + fn find_variable(&mut self, name: &str) -> Option<Variable> { if let Some(res) = self.frame().find_local(name) { return Some(res); @@ -518,7 +528,7 @@ impl Compiler { return Some(res); } - return Self::find_and_capture_variable(name, self.frames.iter_mut().rev()); + Self::find_and_capture_variable(name, self.frames.iter_mut().rev()) } fn find_blob(&self, name: &str) -> Option<usize> { @@ -672,6 +682,9 @@ impl Compiler { if self.peek() == Token::LeftParen { self.call(block); } + } else if let Some(slot) = self.find_extern_function(&name) { + block.add(Op::Constant(Value::ExternFunction(slot)), self.line()); + self.call(block); } else { error!(self, format!("Using undefined variable {}.", name)); } @@ -1028,8 +1041,14 @@ impl Compiler { } - pub fn compile(&mut self, name: &str, file: &Path) -> Result<Prog, Vec<Error>> { + pub fn compile(&mut self, name: &str, file: &Path, functions: &[(String, RustFunction)]) -> Result<Prog, Vec<Error>> { println!("=== START COMPILATION ==="); + self.functions = functions + .to_vec() + .into_iter() + .enumerate() + .map(|(i, (s, f))| (s, (i, f))) + .collect(); self.stack_mut().push(Variable { name: String::from("/main/"), typ: Type::Void, @@ -1065,6 +1084,6 @@ impl Compiler { } } -pub fn compile(name: &str, file: &Path, tokens: TokenStream) -> Result<Prog, Vec<Error>> { - Compiler::new(file, tokens).compile(name, file) +pub fn compile(name: &str, file: &Path, tokens: TokenStream, functions: &[(String, RustFunction)]) -> Result<Prog, Vec<Error>> { + Compiler::new(file, tokens).compile(name, file, functions) } @@ -6,21 +6,22 @@ pub mod vm; mod error; +use compiler::RustFunction; use error::Error; use tokenizer::TokenStream; -pub fn run_file(path: &Path, print: bool) -> Result<(), Vec<Error>> { - run(tokenizer::file_to_tokens(path), path, print) +pub fn run_file(path: &Path, print: bool, functions: Vec<(String, RustFunction)>) -> Result<(), Vec<Error>> { + run(tokenizer::file_to_tokens(path), path, print, functions) } -pub fn run_string(s: &str, print: bool) -> Result<(), Vec<Error>> { - run(tokenizer::string_to_tokens(s), Path::new("builtin"), print) +pub fn run_string(s: &str, print: bool, functions: Vec<(String, RustFunction)>) -> Result<(), Vec<Error>> { + run(tokenizer::string_to_tokens(s), Path::new("builtin"), print, functions) } -pub fn run(tokens: TokenStream, path: &Path, print: bool) -> Result<(), Vec<Error>> { - match compiler::compile("main", path, tokens) { +pub fn run(tokens: TokenStream, path: &Path, print: bool, functions: Vec<(String, RustFunction)>) -> Result<(), Vec<Error>> { + match compiler::compile("main", path, tokens, &functions) { Ok(blocks) => { - let mut vm = vm::VM::new().print_blocks(print).print_ops(print); + let mut vm = vm::VM::new(&functions).print_blocks(print).print_ops(print); vm.typecheck(&blocks)?; if let Err(e) = vm.run(&blocks) { Err(vec![e]) @@ -59,13 +60,13 @@ mod tests { ($fn:ident, $prog:literal) => { #[test] fn $fn() { - $crate::run_string($prog, true).unwrap(); + $crate::run_string($prog, true, Vec::new()).unwrap(); } }; ($fn:ident, $prog:literal, $errs:tt) => { #[test] fn $fn() { - $crate::assert_errs!($crate::run_string($prog, true), $errs); + $crate::assert_errs!($crate::run_string($prog, true, Vec::new()), $errs); } } } @@ -76,7 +77,7 @@ mod tests { #[test] fn $fn() { let file = Path::new($path); - run_file(&file, true).unwrap(); + run_file(&file, true, Vec::new()).unwrap(); } }; } @@ -85,7 +86,7 @@ mod tests { #[test] fn unreachable_token() { - assert_errs!(run_string("<!>\n", true), [ErrorKind::Unreachable]); + assert_errs!(run_string("<!>\n", true, Vec::new()), [ErrorKind::Unreachable]); } macro_rules! test_multiple { diff --git a/src/main.rs b/src/main.rs index d5cb465..7909eb9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ use std::path::{Path, PathBuf}; use tihdy::run_file; +use tihdy::vm::Value; struct Args { file: Option<PathBuf>, @@ -10,7 +11,7 @@ struct Args { fn main() { let args = parse_args(); let file = args.file.unwrap_or_else(|| Path::new("tests/simple.tdy").to_owned()); - if let Err(errs) = run_file(&file, args.print) { + if let Err(errs) = run_file(&file, args.print, vec![(String::from("hello"), hello)]) { for err in errs.iter() { println!("{}", err); } @@ -36,3 +37,8 @@ fn parse_args() -> Args { }; args } + +pub fn hello(_parameters: &[Value]) -> Value { + println!("Hello World!"); + Value::Nil +} @@ -6,6 +6,7 @@ use std::path::{Path, PathBuf}; use std::rc::Rc; use std::cell::RefCell; +use crate::compiler::RustFunction; use crate::compiler::Type; use crate::error::{Error, ErrorKind}; use crate::compiler::{Prog, Blob}; @@ -28,6 +29,7 @@ pub enum Value { Bool(bool), String(Rc<String>), Function(Vec<Rc<RefCell<UpValue>>>, Rc<RefCell<Block>>), + ExternFunction(usize), Unkown, Nil, } @@ -39,7 +41,6 @@ pub struct UpValue { } impl UpValue { - fn new(value: usize) -> Self { Self { slot: value, @@ -84,6 +85,7 @@ impl Debug for Value { Value::Bool(b) => write!(fmt, "(bool {})", b), Value::String(s) => write!(fmt, "(string \"{}\")", s), Value::Function(_, block) => write!(fmt, "(fn {}: {:?})", block.borrow().name, block.borrow().ty), + Value::ExternFunction(slot) => write!(fmt, "(extern fn {})", slot), Value::Unkown => write!(fmt, "(unkown)"), Value::Nil => write!(fmt, "(nil)"), } @@ -109,6 +111,7 @@ impl Value { 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, } @@ -280,7 +283,6 @@ struct Frame { ip: usize, } -#[derive(Debug)] pub struct VM { upvalues: HashMap<usize, Rc<RefCell<UpValue>>>, @@ -291,6 +293,8 @@ pub struct VM { print_blocks: bool, print_ops: bool, + + extern_functions: Vec<RustFunction>, } enum OpResult { @@ -299,14 +303,17 @@ enum OpResult { } impl VM { - pub fn new() -> Self { + pub fn new(functions: &[(String, RustFunction)]) -> Self { Self { upvalues: HashMap::new(), + stack: Vec::new(), frames: Vec::new(), blobs: Vec::new(), print_blocks: false, print_ops: false, + + extern_functions: functions.iter().map(|(_, f)| *f).collect() } } @@ -618,7 +625,13 @@ impl VM { ip: 0, }); return Ok(OpResult::Continue); - }, + } + Value::ExternFunction(slot) => { + let extern_func = self.extern_functions[*slot]; + let res = extern_func(&[]); + self.stack.truncate(new_base); + self.stack.push(res); + } _ => { unreachable!() } @@ -853,7 +866,10 @@ impl VM { self.stack[new_base] = block.borrow().ret().as_value(); self.stack.truncate(new_base + 1); - }, + } + Value::ExternFunction(_slot) => { + self.stack.truncate(new_base + 1); + } _ => { error!(self, ErrorKind::TypeError(op.clone(), vec![self.stack[new_base].as_type()]), diff --git a/tests/simple.tdy b/tests/simple.tdy index 4a0b7d1..6793088 100644 --- a/tests/simple.tdy +++ b/tests/simple.tdy @@ -1,5 +1 @@ -a := fn f: fn -> { - f() -} - -a(fn { print 2 }) +hello() |
