123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- use proc_macro::TokenStream;
- use std::fmt::format;
- use quote::{quote, quote_spanned, TokenStreamExt, ToTokens};
- use syn::parse::{Parse, ParseStream, Result};
- use syn::spanned::Spanned;
- use syn::{token, parse_macro_input, Ident, Token, Type, Stmt, Block, Error};
- use syn::token::RArrow;
- use proc_macro_error::{proc_macro_error, abort};
- #[macro_use]
- extern crate syn;
- const fmt_tip:&str = "`proc fn ProcName (Arg: ArgType) -> (Ret: RetType) { ... }`";
- struct ArgDef {
- name: Ident,
- colon_token: token::Colon,
- type_name: Type,
- }
- struct FnDef {
- name: Ident,
- args: Option<ArgDef>,
- ret: Option<ArgDef>,
- fn_body: Block,
- }
- impl Parse for ArgDef {
- fn parse(input: ParseStream) -> Result<Self> {
- Ok(ArgDef{
- name: input.parse()?,
- colon_token: input.parse()?,
- type_name: input.parse()?,
- })
- }
- }
- impl Parse for FnDef {
- fn parse(input: ParseStream) -> Result<Self> {
- let start_token_res = input.parse::<Ident>();
- let start_token = match start_token_res {
- Err(e) => {
- abort! { input.span(),
- "expect 'proc'";
- note = "expect 'proc' here, but not found.";
- help = fmt_tip;
- }
- },
- Ok(id) => id,
- };
- if start_token != "proc" {
- abort! { start_token.span(),
- "expect 'proc'";
- note = format!("expect 'proc' here, but found '{}'", start_token);
- help = fmt_tip;
- }
- }
- let fn_token_res = input.parse::<Token![fn]>();
- match fn_token_res {
- Err(e) => {
- abort! { input.span(),
- "expect 'fn'";
- note = "expect 'fn' here, but not found.";
- help = fmt_tip;
- }
- },
- Ok(_) => (),
- };
- let fn_name_res = input.parse::<Ident>();
- let fn_name = match fn_name_res {
- Err(e) => {
- abort! { input.span(),
- "expect proc name";
- note = "expect an ident here, but not found.";
- help = fmt_tip;
- }
- },
- Ok(id) => id,
- };
- let args_pat_inner;
- parenthesized!(args_pat_inner in input);
- let args = if args_pat_inner.is_empty() {
- None
- }else{
- let args_parse_res = args_pat_inner.parse::<ArgDef>();
- match args_parse_res {
- Err(e) => {
- abort! { input.span(),
- "expect args define or nothing";
- note = "expect args define or nothing";
- help = fmt_tip;
- }
- },
- Ok(t) => Option::Some(t),
- }
- };
- let ra_res = input.parse::<token::RArrow>();
- match ra_res {
- Err(e) => {
- abort! { input.span(),
- "expect '->'";
- note = "expect '->' here";
- help = fmt_tip;
- }
- },
- Ok(t) => Option::Some(t),
- };
- let ret_pat_inner;
- parenthesized!(ret_pat_inner in input);
- let ret = if ret_pat_inner.is_empty(){
- None
- }else{
- let ret_parse_res = ret_pat_inner.parse::<ArgDef>();
- match ret_parse_res {
- Err(e) => {
- abort! { input.span(),
- "expect ret define or nothing";
- note = "expect ret define or nothing";
- help = fmt_tip;
- }
- },
- Ok(t) => Option::Some(t),
- }
- };
- let fn_body_res = input.parse::<Block>();
- let fn_body = match fn_body_res {
- Err(e) => {
- abort! { input.span(),
- "expect function body here";
- note = "expect function body here, but not found.";
- help = fmt_tip;
- }
- },
- Ok(t) => t,
- };
- Ok(FnDef{
- name: fn_name,
- args: args,
- ret: ret,
- fn_body: fn_body,
- })
- }
- }
- /// Usage:
- ///
- /// zrfu_proc_def! {
- /// proc fn $PROC_NAME ( $ARGS_NAME: $ARGS_TYPE ) -> ( $RET_NAME: $RET_TYPE ) {
- ///
- /// }
- /// }
- ///
- /// For example:
- ///
- /// zrfu_proc_def! {
- /// proc fn TestProcAR ( in: Type1 ) -> ( out: Type2 ) {
- /// // ...
- /// }
- /// }
- ///
- /// zrfu_proc_def! {
- /// proc fn TestProcN () -> () {
- /// // ...
- /// }
- /// }
- ///
- /// zrfu_proc_def! {
- /// proc fn TestProcA ( in: Type1 ) -> () {
- /// // ...
- /// }
- /// }
- ///
- /// zrfu_proc_def! {
- /// proc fn TestProcR () -> ( out: Type2 ) {
- /// // ...
- /// }
- /// }
- ///
- #[proc_macro]
- #[proc_macro_error]
- pub fn zrfu_proc_def(input: TokenStream) -> TokenStream {
- let ast = parse_macro_input!(input as FnDef);
- let tk_proc_name = ast.name;
- let mut tk_strm_blk = proc_macro2::TokenStream::new();
- tk_strm_blk.append_all(ast.fn_body.stmts);
- let tk_stmts = tk_strm_blk;
- let tk_fields = match &ast.args {
- None => {
- match &ast.ret {
- None => {
- quote!{
- proc_name: String,
- }
- },
- Some(ret) => {
- let tk_ret_type = ret.type_name.clone();
- quote!{
- proc_name: String,
- ret: ZRFUProcReturn<#tk_ret_type>,
- }
- },
- }
- },
- Some(arg) => {
- match &ast.ret {
- None => {
- let tk_args_type = arg.type_name.clone();
- quote!{
- proc_name: String,
- args: ZRFUProcArgs<#tk_args_type>,
- }
- },
- Some(ret) => {
- let tk_ret_type = ret.type_name.clone();
- let tk_args_type = arg.type_name.clone();
- quote!{
- proc_name: String,
- ret: ZRFUProcReturn<#tk_ret_type>,
- args: ZRFUProcArgs<#tk_args_type>,
- }
- },
- }
- },
- };
- let tk_decode_input = match &ast.args {
- None => {
- quote!{
- ZRFUProcResultCode::NoArgsNeed
- }
- },
- Some(_) => {
- quote!{
- self.args.cbor_deserialize(bv)
- }
- },
- };
- let tk_encode_return = match &ast.ret {
- None => {
- quote!{
- ZRFUProcResultCode::NoReturnProvided
- }
- },
- Some(_) => {
- quote!{
- self.ret.cbor_serialize(bv)
- }
- },
- };
- let tk_process_input = match &ast.args {
- None => {
- quote!{
- }
- },
- Some(arg) => {
- let tk_argname = arg.name.clone();
- quote!{
- let #tk_argname = match self.args.get_data() {
- None => { return ZRFUProcResultCode::CanNotGetArgs; },
- Some(t) => t,
- };
- }
- },
- };
- let tk_process_return = match &ast.ret {
- None => {
- quote!{
- }
- },
- Some(ret) => {
- let tk_retname = ret.name.clone();
- quote!{
- self.ret.set_data(#tk_retname);
- }
- },
- };
- let tk_new_inst = match &ast.args {
- None => {
- match &ast.ret {
- None => {
- quote!{
- proc_name: name,
- }
- },
- Some(_) => {
- quote!{
- proc_name: name,
- ret: ZRFUProcReturn::new(),
- }
- },
- }
- },
- Some(_) => {
- match &ast.ret {
- None => {
- quote!{
- proc_name: name,
- args: ZRFUProcArgs::new(),
- }
- },
- Some(ret) => {
- quote!{
- proc_name: name,
- ret: ZRFUProcReturn::new(),
- args: ZRFUProcArgs::new(),
- }
- },
- }
- },
- };
- let expanded = quote!{
- pub struct #tk_proc_name {
- #tk_fields
- }
- impl ZRFUProcInstanceTrait for #tk_proc_name {
- fn decode_input(&mut self, bv: &mut ZRFUBytesVec) -> ZRFUProcResultCode {
- #tk_decode_input
- }
- fn call(&mut self) -> ZRFUProcResultCode {
- #tk_process_input
- #tk_stmts
- #tk_process_return
- return ZRFUProcResultCode::Ok;
- }
- fn encode_return(&mut self, bv: &mut ZRFUBytesVec) -> ZRFUProcResultCode {
- #tk_encode_return
- }
- }
- impl #tk_proc_name {
- fn factory(name: String) -> Box<dyn ZRFUProcInstanceTrait> {
- Box::new(#tk_proc_name{
- #tk_new_inst
- })
- }
- }
- };
- TokenStream::from(expanded)
- }
|