aboutsummaryrefslogtreecommitdiffstats
path: root/tihdy_derive/src/lib.rs
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 /tihdy_derive/src/lib.rs
parent674695d7e28f03218aa5a3facd933b87d508ea7d (diff)
downloadsylt-e93e9e7ff4a73bc98a0dcd410eff87dffff3aa1c.tar.gz
external functions proc macro
Diffstat (limited to 'tihdy_derive/src/lib.rs')
-rw-r--r--tihdy_derive/src/lib.rs86
1 files changed, 86 insertions, 0 deletions
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)
+}