aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGustav Sörnäs <gustav@sornas.net>2021-01-21 21:56:29 +0100
committerGustav Sörnäs <gustav@sornas.net>2021-01-29 20:44:36 +0100
commit8a6d8b144f45c509602a598f962d872a98226997 (patch)
treec9966ba2b6605accdfce66768935528065232dc4
parent28b84aca844222c3dcccc3ef4b32bac6571ea881 (diff)
downloadsylt-8a6d8b144f45c509602a598f962d872a98226997.tar.gz
call external functions without parameters
-rw-r--r--src/compiler.rs27
-rw-r--r--src/lib.rs23
-rw-r--r--src/main.rs8
-rw-r--r--src/vm.rs26
-rw-r--r--tests/simple.tdy6
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)
}
diff --git a/src/lib.rs b/src/lib.rs
index 081dd70..5150be3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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
+}
diff --git a/src/vm.rs b/src/vm.rs
index 0fb38ea..053100f 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -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()