RustのsynはRustで書かれたソースコードを解析するためのもので、手続き型マクロを実装するときに重宝するが、普通のプログラムを書く時にも使用できる。
文字列からコードを解析する場合、syn::parse_strを用いる。
fn main() { // 文字列でRustのコードを書く let my_rust_code = " #[derive(Debug, Clone)] #[inline] pub fn myfunc(&self,x:i32, y:i32) -> f32{ println!(\"Hello, world!\"); } " ; // ソースコードのパース let my_parse = syn::parse_str::<syn::ItemFn>(my_rust_code).unwrap(); let mut myfv:MyFnVisitor = MyFnVisitor{indent:0}; myfv.visit_item_fn(&my_parse); }
///////////////////////////// /// 以下、解析のための構造体並びに関数 struct MyFnVisitor{ indent:usize, } use quote::ToTokens; use syn::visit::Visit; impl<'a> syn::visit::Visit<'a> for MyFnVisitor{ // 関数をパースするには、visit_item_fnを実装する fn visit_item_fn(&mut self, node: &'a syn::ItemFn) { let mut indentstr:String = "".to_string(); for _ in 0..self.indent{ indentstr.push_str(" "); } println!("{}****************",indentstr); // 関数がパブリックかどうかをチェック if let syn::Visibility::Public(_pub) = node.vis { println!("{}pub? {}",indentstr,_pub.to_token_stream().to_string()); } // アトリビュートを取得 for attr in &node.attrs{ let id = attr.path().get_ident().unwrap(); println!("{}attribute: {}",indentstr,id); } // 関数名を取得 let function_name = &node.sig.ident; println!("{}func_name: {}",indentstr,function_name); // 引数を取得 for arg in node.sig.inputs.iter(){ match arg{ syn::FnArg::Typed(pat_type) => { if let syn::Pat::Ident(patident) = &*pat_type.pat{ let arg_name = &patident.ident; let arg_type = &pat_type.ty.to_token_stream().to_string(); println!("{}arg: {} {}",indentstr, &arg_name, &arg_type ); } } _ => {} } } } }