aboutsummaryrefslogtreecommitdiffstats
path: root/sylt_macro/src
diff options
context:
space:
mode:
Diffstat (limited to 'sylt_macro/src')
-rw-r--r--sylt_macro/src/lib.rs87
1 files changed, 87 insertions, 0 deletions
diff --git a/sylt_macro/src/lib.rs b/sylt_macro/src/lib.rs
new file mode 100644
index 0000000..241ef7d
--- /dev/null
+++ b/sylt_macro/src/lib.rs
@@ -0,0 +1,87 @@
+use proc_macro::TokenStream;
+use quote::quote;
+use syn::{Expr, Pat, Token, parse::{Parse, ParseStream, Result}, parse_macro_input};
+
+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: &[sylt::Value],
+ __typecheck: bool
+ ) -> ::std::result::Result<sylt::Value, sylt::error::ErrorKind>
+ {
+ if __typecheck {
+ #[allow(unused_variables)]
+ match __values {
+ #(#typecheck_blocks),*
+ _ => Err(sylt::error::ErrorKind::ExternTypeMismatch(stringify!(#function).to_string(), __values.iter().map(|v| sylt::Type::from(v)).collect()))
+ }
+ } else {
+ match __values {
+ #(#eval_blocks),*
+ _ => Err(sylt::error::ErrorKind::ExternTypeMismatch(stringify!(#function).to_string(), __values.iter().map(|v| sylt::Type::from(v)).collect()))
+ }
+ }
+ }
+ };
+ TokenStream::from(tokens)
+}