value_expr/
parser.rs

1use super::data::*;
2use proc_macro2::TokenStream;
3use std::str::FromStr;
4use syn::ext::IdentExt;
5use syn::parse::discouraged::Speculative;
6use syn::parse::{Parse, ParseStream};
7use syn::{parenthesized, token, Ident, LitInt, Token};
8
9macro_rules! op {
10    ($name:ident => $msg:literal; $($tt:tt => $ident:ident);+$(;)?) => {
11        impl Parse for $name {
12            fn parse(input: ParseStream) -> syn::Result<Self> {
13                let lookahead = input.lookahead1();
14                $(if lookahead.peek(Token!$tt) {
15                    input.parse::<Token!$tt>().map(|_|Self::$ident)
16                } else)+ {
17                    Err(input.error($msg))
18                }
19            }
20        }
21        impl $name {
22            #[allow(unused)]
23            pub fn desc(self) -> &'static str {
24                match self {
25                    $(Self::$ident => stringify!($tt)),+
26                }
27            }
28        }
29    };
30}
31
32op! {
33    UnOp => "expected unary operator";
34    [!] => Not;
35    [-] => Neg;
36}
37
38op! {
39    BinOp => "expected binary operator";
40    [&&] => And;
41    [||] => Or;
42    [<<] => Shl;
43    [>>] => Shr;
44    [==] => Eq;
45    [<=] => Le;
46    [!=] => Ne;
47    [>=] => Ge;
48    [+] => Add;
49    [-] => Sub;
50    [*] => Mul;
51    [/] => Div;
52    [%] => Rem;
53    [^] => BitXor;
54    [&] => BitAnd;
55    [|] => BitOr;
56    [<] => Lt;
57    [>] => Gt;
58}
59
60op! {
61    AssignOp => "expected assignment operator";
62    [=] => Assign;
63    [+=] => AddAssign;
64    [-=] => SubAssign;
65    [*=] => MulAssign;
66    [/=] => DivAssign;
67    [%=] => RemAssign;
68    [^=] => BitAndAssign;
69    [&=] => BitOrAssign;
70    [|=] => BitXorAssign;
71    [<<=] => ShlAssign;
72    [>>=] => ShrAssign;
73}
74
75#[derive(Eq, PartialEq, Ord, PartialOrd)]
76enum Precedence {
77    Any,
78    Or,
79    And,
80    Compare,
81    BitOr,
82    BitXor,
83    BitAnd,
84    Shift,
85    Arithmetic,
86    Term,
87}
88
89impl Precedence {
90    fn of(op: &BinOp) -> Self {
91        match op {
92            BinOp::Add | BinOp::Sub => Precedence::Arithmetic,
93            BinOp::Mul | BinOp::Div | BinOp::Rem => Precedence::Term,
94            BinOp::And => Precedence::And,
95            BinOp::Or => Precedence::Or,
96            BinOp::BitXor => Precedence::BitXor,
97            BinOp::BitAnd => Precedence::BitAnd,
98            BinOp::BitOr => Precedence::BitOr,
99            BinOp::Shl | BinOp::Shr => Precedence::Shift,
100            BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
101                Precedence::Compare
102            }
103        }
104    }
105}
106
107fn unary_value(input: ParseStream) -> syn::Result<Value> {
108    if input.peek(Token![!]) || input.peek(Token![-]) {
109        Ok(Value::Unary(input.parse()?, Box::new(unary_value(input)?)))
110    } else {
111        atom_value(input)
112    }
113}
114
115fn atom_value(input: ParseStream) -> syn::Result<Value> {
116    if input.peek(token::Paren) {
117        let content;
118        parenthesized!(content in input);
119        let data = content
120            .parse_terminated(Value::parse, Token![,])?
121            .into_iter()
122            .collect();
123        return Ok(Value::Paren(data));
124    }
125    if input.peek(LitInt) {
126        let integer = input.parse::<LitInt>()?.base10_parse::<i32>()?;
127        return Ok(Value::Integer(integer));
128    }
129    if input.peek(Ident::peek_any) {
130        let ident = input.call(Ident::parse_any)?.to_string();
131        if input.peek(token::Paren) {
132            let content;
133            parenthesized!(content in input);
134            let data = content
135                .parse_terminated(Value::parse, Token![,])?
136                .into_iter()
137                .collect();
138            return Ok(Value::FuncLike(ident, data));
139        }
140        if !input.peek(Token![==]) {
141            let ahead = input.fork();
142            if let Ok(op) = ahead.parse::<AssignOp>() {
143                input.advance_to(&ahead);
144                return Ok(Value::Assign(op, ident, input.parse()?));
145            }
146        }
147        return Ok(Value::Ident(ident));
148    }
149    Err(input.lookahead1().error())
150}
151
152fn peek_precedence(input: ParseStream) -> Precedence {
153    if let Ok(op) = input.fork().parse() {
154        Precedence::of(&op)
155    } else {
156        Precedence::Any
157    }
158}
159
160fn parse_value(input: ParseStream, mut lhs: Value, base: Precedence) -> syn::Result<Value> {
161    loop {
162        let ahead = input.fork();
163        if let Some(op) = match ahead.parse::<BinOp>() {
164            Ok(op) if Precedence::of(&op) >= base => Some(op),
165            _ => None,
166        } {
167            input.advance_to(&ahead);
168            let precedence = Precedence::of(&op);
169            let mut rhs = unary_value(input)?;
170            loop {
171                let next = peek_precedence(input);
172                if next > precedence {
173                    rhs = parse_value(input, rhs, next)?;
174                } else {
175                    break;
176                }
177            }
178            lhs = Value::Binary(op, Box::new(lhs), Box::new(rhs));
179        } else {
180            break;
181        }
182    }
183    Ok(lhs)
184}
185
186impl Parse for Value {
187    fn parse(input: ParseStream) -> syn::Result<Self> {
188        let lhs = unary_value(input)?;
189        parse_value(input, lhs, Precedence::Any)
190    }
191}
192
193impl Value {
194    pub fn parse_str(input: &str) -> syn::Result<Self> {
195        syn::parse2(TokenStream::from_str(input)?)
196    }
197}
198
199#[cfg(test)]
200mod tests {
201    use super::*;
202
203    #[test]
204    fn test() {
205        let test = |e| Value::parse_str(e).unwrap();
206        test("1");
207        test("-1");
208        test("1+2");
209        test("(1,2,3)");
210        test("(1+2,3,a(1))");
211        test("a");
212        test("a+=1");
213    }
214}