How to parse proc_macro_attribute on syn=2.0 version?

//maybe #[sql(RB, "select * from biz_activity where id = ?")]
//maybe #[sql("select * from biz_activity where id = ?")]
#[proc_macro_attribute]
pub fn sql(args: TokenStream, func: TokenStream) -> TokenStream {
    let args = parse_macro_input!(args as AttributeArgs); // this is syn=1.0
   // how to parse in 2.0? What type should I choose to parse into?
    let args = parse_macro_input!(args as ?);
}

Parse with the parser, see ParseBuffer in syn::parse - Rust and parse_macro_input in syn - Rust

let args = parse_macro_input!(args with Attribute::parse_outer);
// or equivalently 
let args = Attribute::parse_outer.parse(args).unwrap();

this is fail

#[proc_macro_attribute]
pub fn html_sql(args: TokenStream, func: TokenStream) -> TokenStream {
    println!("parse html_sql");
    let args = parse_macro_input!(args with Attribute::parse_outer);
}
error: unexpected token
  --> src/macro_proc_htmlsql.rs:28:12
   |
28 |   #[html_sql(r#"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "https://raw.githubusercontent.com/rbatis/rbatis/master/rbatis-codegen/my...
   |  ____________^
29 | |   <select id="select_by_condition">
30 | |         `select * from biz_activity`
31 | |         <where>
...  |
51 | |         </where>
52 | |   </select>"#)]

I forget the first argument in proc_macro_attribute is parsed as the argument in attribute proc_macro instead of the whole attribute, so for you case

let args = parse_macro_input!(args as LitStr); should be fine.

for #[sql(RB, "select * from biz_activity where id = ?")], you should define a custom struct that implements Parse trait and manually parses tokens.

Mainly because the type is not fixed, the first parameter may be Ident or a LitStr.
for example:

#[sql(RB, "select * from biz_activity where id = ?")]
#[sql("select * from biz_activity where id = ?")]
#[sql("select * from biz_activity where id = ?","select * from biz_activity where id = ?")]
#[html_sql(r#"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "https://raw.githubusercontent.com/rbatis/rbatis/master/rbatis-codegen/mybatis-3-mapper.dtd">
<mapper>
    <insert id="insert">
        'insert into biz_activity'
        <foreach collection="arg" index="key" item="item" open="(" close=")" separator=",">
            '${key}'
        </foreach>
        'values'
        <foreach collection="arg" index="key" item="item" open="(" close=")" separator=",">
            '${item}'
        </foreach>
    </insert></mapper>"#)]

How do I define this changing struct?

You have to define your struct then as I've already answered above.

let args = parse_macro_input!(args as YourStructImplementsParse);
1 Like
pub struct MyStructImplementsParse1{
    pub ident:Ident,
}
pub struct MyStructImplementsParse2{
    pub ident:Ident,
    pub litStr:LitStr
}

is this?

No, just one struct: parse_macro_input in syn - Rust

pub struct Args {
    pub ident: Option<Ident>,
    pub litStr: LitStr
}
impl Parse for Args {
    ...
}
1 Like

oh,Thank you for your replay. I'll try again

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.