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}