From 4fccff5e27e054e949cf363f83f2a09882001859 Mon Sep 17 00:00:00 2001 From: greg Date: Thu, 27 Sep 2018 04:07:42 -0700 Subject: [PATCH] Working on improved proc_macro handling --- schala-codegen/Cargo.toml | 1 + schala-codegen/src/lib.rs | 36 ++++++++++++++++++++++++++++++++++-- schala-lang/src/lib.rs | 3 ++- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/schala-codegen/Cargo.toml b/schala-codegen/Cargo.toml index 5a63e5e..3317294 100644 --- a/schala-codegen/Cargo.toml +++ b/schala-codegen/Cargo.toml @@ -6,6 +6,7 @@ authors = ["greg "] [dependencies] syn = { version = "0.15.6", features = ["full", "extra-traits"] } quote = "0.6.8" +proc-macro2 = "0.4.19" schala-repl = { path = "../schala-repl" } [lib] diff --git a/schala-codegen/src/lib.rs b/schala-codegen/src/lib.rs index 3dd7714..e026d2f 100644 --- a/schala-codegen/src/lib.rs +++ b/schala-codegen/src/lib.rs @@ -1,5 +1,6 @@ #![feature(trace_macros)] extern crate proc_macro; +extern crate proc_macro2; #[macro_use] extern crate quote; extern crate syn; @@ -51,8 +52,17 @@ fn extract_attribute_list(name: &str, attrs: &Vec) -> Option(name: &str, attrs: &'a Vec) -> Option<&'a Attribute> { + attrs.iter().find(|attr| { + let first = attr.path.segments.first(); + let seg: Option<&&syn::PathSegment> = first.as_ref().map(|x| x.value()); + seg.map(|seg| seg.ident.to_string() == name).unwrap_or(false) + }) +} + #[proc_macro_derive(ProgrammingLanguageInterface, attributes(LanguageName, SourceFileExtension, PipelineSteps, DocMethod))] pub fn derive_programming_language_interface(input: TokenStream) -> TokenStream { + let ast: DeriveInput = syn::parse(input).unwrap(); let name = &ast.ident; let attrs = &ast.attrs; @@ -61,7 +71,29 @@ pub fn derive_programming_language_interface(input: TokenStream) -> TokenStream let file_ext = extract_attribute_arg_by_name("SourceFileExtension", attrs).expect("SourceFileExtension is required"); let passes = extract_attribute_list("PipelineSteps", attrs).expect("PipelineSteps are required"); let pass_idents = passes.iter().map(|x| x.0.clone()); - let doc_method: Option = extract_attribute_arg_by_name("DocMethod", attrs); + + let doc_method: Option= find_attr_by_name("DocMethod", attrs).and_then(|attr| { + let tts = attr.tts.clone().into_iter().collect::>(); + + if tts.len() == 2 { + let ref after_equals: proc_macro2::TokenTree = tts[1]; + match after_equals { + proc_macro2::TokenTree::Ident(ident) => Some(ident.to_string()), + _ => None + } + } else { + None + } + }); + + let doc_method_body = match doc_method { + None => quote! { }, + Some(s) => quote!{ + fn get_doc(&self, commands: &Vec<&str>) -> Option { + #s(commands) + } + } + }; //let pass_names: Vec = passes.iter().map(|pass| pass.0.to_string()).collect(); let pass_descriptors = passes.iter().map(|pass| { @@ -97,7 +129,7 @@ pub fn derive_programming_language_interface(input: TokenStream) -> TokenStream //vec![ #(PassDescriptor { name: #pass_names.to_string(), debug_options: vec![] }),* ] } } - //TODO if doc_method is defined, add code here + #doc_method_body }; let output: TokenStream = tokens.into(); diff --git a/schala-lang/src/lib.rs b/schala-lang/src/lib.rs index 231db05..390ef98 100644 --- a/schala-lang/src/lib.rs +++ b/schala-lang/src/lib.rs @@ -1,4 +1,5 @@ #![feature(trace_macros)] +#![feature(unrestricted_attribute_tokens)] #![feature(slice_patterns, box_patterns, box_syntax)] extern crate itertools; #[macro_use] @@ -35,7 +36,7 @@ mod eval; #[LanguageName = "Schala"] #[SourceFileExtension = "schala"] #[PipelineSteps(tokenizing, parsing(compact,expanded,trace), symbol_table, typechecking, ast_reducing, eval)] -#[DocMethod = "get_doc"] +#[DocMethod = get_doc] pub struct Schala { state: eval::State<'static>, symbol_table: Rc>,