aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGustav Sörnäs <gustav@sornas.net>2021-01-30 12:10:49 +0100
committerGustav Sörnäs <gustav@sornas.net>2021-01-30 12:10:49 +0100
commite93e9e7ff4a73bc98a0dcd410eff87dffff3aa1c (patch)
tree992024e5df64d7735618d2b0d0f85bbc313c6416
parent674695d7e28f03218aa5a3facd933b87d508ea7d (diff)
downloadsylt-e93e9e7ff4a73bc98a0dcd410eff87dffff3aa1c.tar.gz
external functions proc macro
-rw-r--r--Cargo.lock9
-rw-r--r--Cargo.toml1
-rw-r--r--src/compiler.rs2
-rw-r--r--src/error.rs4
-rw-r--r--src/lib.rs3
-rw-r--r--src/main.rs33
-rw-r--r--src/stack.rs3
-rw-r--r--src/vm.rs12
-rw-r--r--tests/simple.tdy5
-rw-r--r--tihdy_derive/Cargo.toml14
-rw-r--r--tihdy_derive/src/lib.rs86
11 files changed, 145 insertions, 27 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 00a0067..3e3759e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -525,6 +525,15 @@ dependencies = [
"criterion",
"logos",
"owo-colors",
+ "tihdy_derive",
+]
+
+[[package]]
+name = "tihdy_derive"
+version = "0.1.0"
+dependencies = [
+ "quote",
+ "syn",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index ddafc76..e78987e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,6 +12,7 @@ name = "tihdy"
[dependencies]
logos = "0.11.4"
owo-colors = { git="https://github.com/FredTheDino/owo-colors.git" }
+tihdy_derive = { path = "tihdy_derive" }
criterion = { version = "0.3", optional = true }
diff --git a/src/compiler.rs b/src/compiler.rs
index 866e0a3..559068d 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -182,7 +182,7 @@ impl Frame {
}
}
-pub type RustFunction = fn(&[Value]) -> Value;
+pub type RustFunction = fn(&[Value], bool) -> Result<Value, ErrorKind>;
#[derive(Debug, Clone)]
pub struct Blob {
diff --git a/src/error.rs b/src/error.rs
index d8d4664..b489cd1 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -11,6 +11,7 @@ use crate::vm::{Op, Value};
#[derive(Debug, Clone)]
pub enum ErrorKind {
TypeError(Op, Vec<Type>),
+ ExternTypeMismatch(String, Vec<Type>),
RuntimeTypeError(Op, Vec<Value>),
Assert,
InvalidProgram,
@@ -36,6 +37,9 @@ impl fmt::Display for ErrorKind {
.fold(String::new(), |a, v| { format!("{}{:?}, ", a, v) });
write!(f, "{} Cannot apply {:?} to types {}", "Type Error".bold(), op, types)
}
+ ErrorKind::ExternTypeMismatch(name, types) => {
+ write!(f, "{} Extern function '{}' doesn't accept argument(s) with type(s) {:?}", "Type Error".bold(), name, types)
+ }
ErrorKind::RuntimeTypeError(op, values) => {
let values = values
.iter()
diff --git a/src/lib.rs b/src/lib.rs
index e68adff..17f680c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,11 +1,10 @@
use std::path::Path;
pub mod compiler;
+pub mod error;
pub mod tokenizer;
pub mod vm;
-mod error;
-
use compiler::RustFunction;
use error::Error;
use tokenizer::TokenStream;
diff --git a/src/main.rs b/src/main.rs
index a97cd43..10b88ba 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,7 +1,6 @@
use std::path::{Path, PathBuf};
use tihdy::run_file;
-use tihdy::vm::Value;
struct Args {
file: Option<PathBuf>,
@@ -11,12 +10,14 @@ 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, vec![(String::from("hello"), hello)]) {
- for err in errs.iter() {
- println!("{}", err);
- }
- println!(" {} errors occured.", errs.len());
+ let errs = match run_file(&file, args.print, vec![(String::from("extern_test"), extern_test)]) {
+ Err(it) => it,
+ _ => return,
+ };
+ for err in errs.iter() {
+ println!("{}", err);
}
+ println!(" {} errors occured.", errs.len());
}
fn parse_args() -> Args {
@@ -38,14 +39,12 @@ fn parse_args() -> Args {
args
}
-pub fn hello(parameters: &[Value]) -> Value {
- match parameters {
- [Value::String(s)] => {
- println!("{}", s);
- }
- _ => {
- println!("Bad parameters");
- }
- }
- Value::Nil
-}
+tihdy_derive::extern_function!(
+ extern_test
+ [tihdy::vm::Value::Float(x), tihdy::vm::Value::Float(y)] -> tihdy::vm::Type::Float => {
+ Ok(tihdy::vm::Value::Float(x + y))
+ },
+ [tihdy::vm::Value::Float(x)] -> tihdy::vm::Type::Float => {
+ Ok(tihdy::vm::Value::Float(*x))
+ },
+);
diff --git a/src/stack.rs b/src/stack.rs
new file mode 100644
index 0000000..a75c775
--- /dev/null
+++ b/src/stack.rs
@@ -0,0 +1,3 @@
+struct Stack<T> {
+
+}
diff --git a/src/vm.rs b/src/vm.rs
index da044a5..3559a2d 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -6,8 +6,9 @@ use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::cell::RefCell;
+pub use crate::compiler::Type;
+
use crate::compiler::RustFunction;
-use crate::compiler::Type;
use crate::error::{Error, ErrorKind};
use crate::compiler::{Prog, Blob};
@@ -629,7 +630,7 @@ impl VM {
}
Value::ExternFunction(slot) => {
let extern_func = self.extern_functions[slot];
- let res = extern_func(&self.stack[new_base+1..]);
+ let res = extern_func(&self.stack[new_base+1..], false).unwrap(); //FIXME
self.stack.truncate(new_base);
self.stack.push(res);
}
@@ -869,8 +870,11 @@ impl VM {
self.stack.truncate(new_base + 1);
}
- Value::ExternFunction(_slot) => {
- self.stack.truncate(new_base + 1);
+ Value::ExternFunction(slot) => {
+ let extern_func = self.extern_functions[slot];
+ let res = extern_func(&self.stack[new_base+1..], true).unwrap(); //FIXME
+ self.stack.truncate(new_base);
+ self.stack.push(res);
}
_ => {
error!(self,
diff --git a/tests/simple.tdy b/tests/simple.tdy
index 8b68da1..a1f255c 100644
--- a/tests/simple.tdy
+++ b/tests/simple.tdy
@@ -1,3 +1,2 @@
-hello()
-hello("a")
-hello("a", "b")
+print extern_test(3.0)
+print extern_test(3.0, 4.0)
diff --git a/tihdy_derive/Cargo.toml b/tihdy_derive/Cargo.toml
new file mode 100644
index 0000000..411f1ab
--- /dev/null
+++ b/tihdy_derive/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "tihdy_derive"
+version = "0.1.0"
+authors = ["Gustav Sörnäs <gustav@sornas.net>"]
+edition = "2018"
+
+[lib]
+proc-macro = true
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+syn = { version = "1.0", features=["full"] }
+quote = "1.0"
diff --git a/tihdy_derive/src/lib.rs b/tihdy_derive/src/lib.rs
new file mode 100644
index 0000000..cc28d64
--- /dev/null
+++ b/tihdy_derive/src/lib.rs
@@ -0,0 +1,86 @@
+use proc_macro::TokenStream;
+use quote::quote;
+use syn::{Expr, Pat, Token, parse::{Parse, ParseStream, Result}, parse_macro_input, punctuated::Punctuated};
+
+struct ExternBlock {
+ pattern: Pat,
+ _arrow: Token![->],
+ return_ty: Expr,
+ _fat_arrow: Token![=>],
+ block: Expr,
+ _comma: Token![,],
+}
+
+struct ExternFunction {
+ function: syn::Ident,
+ blocks: Vec<ExternBlock>
+}
+
+impl Parse for ExternBlock {
+ fn parse(input: ParseStream) -> Result<Self> {
+ Ok(Self {
+ pattern: input.parse()?,
+ _arrow: input.parse()?,
+ return_ty: input.parse()?,
+ _fat_arrow: input.parse()?,
+ block: input.parse()?,
+ _comma: input.parse()?,
+ })
+ }
+}
+
+impl Parse for ExternFunction {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let mut res = Self {
+ function: input.parse()?,
+ blocks: Vec::new(),
+ };
+ while !input.is_empty() {
+ res.blocks.push(input.parse()?);
+ }
+ Ok(res)
+ }
+}
+
+#[proc_macro]
+pub fn extern_function(tokens: TokenStream) -> TokenStream {
+ let parsed: ExternFunction = parse_macro_input!(tokens);
+ let function = parsed.function;
+
+ let typecheck_blocks: Vec<_> = parsed.blocks.iter().map(|block| {
+ let pat = block.pattern.clone();
+ let ty = block.return_ty.clone();
+ quote! {
+ #pat => { Ok(#ty.as_value()) }
+ }
+ }).collect();
+
+ let eval_blocks: Vec<_> = parsed.blocks.iter().map(|block| {
+ let pat = block.pattern.clone();
+ let expr = block.block.clone();
+ quote! {
+ #pat => #expr
+ }
+ }).collect();
+
+ let tokens = quote! {
+ pub fn #function (
+ __values: &[tihdy::vm::Value],
+ __typecheck: bool
+ ) -> ::std::result::Result<tihdy::vm::Value, tihdy::error::ErrorKind>
+ {
+ if __typecheck {
+ match __values {
+ #(#typecheck_blocks),*
+ _ => Err(tihdy::error::ErrorKind::ExternTypeMismatch(stringify!(#function).to_string(), __values.iter().map(|v| tihdy::vm::Type::from(v)).collect()))
+ }
+ } else {
+ match __values {
+ #(#eval_blocks),*
+ _ => Err(tihdy::error::ErrorKind::ExternTypeMismatch(stringify!(#function).to_string(), __values.iter().map(|v| tihdy::vm::Type::from(v)).collect()))
+ }
+ }
+ }
+ };
+ TokenStream::from(tokens)
+}