1use core::fmt;
2
3use crate::ast::prelude::*;
4use crate::parse::Advance;
5
6#[test]
7#[cfg(not(miri))]
8fn ast_parse() {
9 rt::<ast::ExprBinary>("42 + b");
10 rt::<ast::ExprBinary>("b << 10");
11}
12
13#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
17#[non_exhaustive]
18pub struct ExprBinary {
19 #[rune(iter)]
21 pub attributes: Vec<ast::Attribute>,
22 pub lhs: Box<ast::Expr>,
24 pub op: BinOp,
26 pub rhs: Box<ast::Expr>,
28}
29
30expr_parse!(Binary, ExprBinary, "binary expression");
31
32#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Hash, ToTokens, Spanned)]
34#[try_clone(copy)]
35#[non_exhaustive]
36pub enum BinOp {
37 Add(T![+]),
39 Sub(T![-]),
41 Div(T![/]),
43 Mul(T![*]),
45 Rem(T![%]),
47 Eq(T![==]),
49 Neq(T![!=]),
51 Gt(T![>]),
53 Lt(T![<]),
55 Gte(T![>=]),
57 Lte(T![<=]),
59 As(T![as]),
61 Is(T![is]),
63 IsNot(T![is not]),
65 And(T![&&]),
67 Or(T![||]),
69 Shl(T![<<]),
71 Shr(T![>>]),
73 BitAnd(T![&]),
75 BitXor(T![^]),
77 BitOr(T![|]),
79 AddAssign(T![+=]),
81 SubAssign(T![-=]),
83 MulAssign(T![*=]),
85 DivAssign(T![/=]),
87 RemAssign(T![%=]),
89 BitAndAssign(T![&=]),
91 BitXorAssign(T![^=]),
93 BitOrAssign(T![|=]),
95 ShlAssign(T![<<=]),
97 ShrAssign(T![>>=]),
99 DotDot(T![..]),
101 DotDotEq(T![..=]),
103}
104
105impl BinOp {
106 pub(crate) fn is_assign(&self) -> bool {
108 match self {
109 Self::AddAssign(..) => true,
110 Self::SubAssign(..) => true,
111 Self::MulAssign(..) => true,
112 Self::DivAssign(..) => true,
113 Self::RemAssign(..) => true,
114 Self::BitAndAssign(..) => true,
115 Self::BitXorAssign(..) => true,
116 Self::BitOrAssign(..) => true,
117 Self::ShlAssign(..) => true,
118 Self::ShrAssign(..) => true,
119 _ => false,
120 }
121 }
122
123 pub(crate) fn is_conditional(self) -> bool {
125 match self {
126 Self::And(..) => true,
127 Self::Or(..) => true,
128 _ => false,
129 }
130 }
131
132 pub(crate) fn precedence(&self) -> usize {
134 match self {
136 Self::Is(..) | Self::IsNot(..) => 13,
137 Self::As(..) => 13,
138 Self::Mul(..) | Self::Div(..) | Self::Rem(..) => 11,
139 Self::Add(..) | Self::Sub(..) => 10,
140 Self::Shl(..) | Self::Shr(..) => 9,
141 Self::BitAnd(..) => 8,
142 Self::BitXor(..) => 7,
143 Self::BitOr(..) => 6,
144 Self::Eq(..)
145 | Self::Neq(..)
146 | Self::Lt(..)
147 | Self::Gt(..)
148 | Self::Lte(..)
149 | Self::Gte(..) => 5,
150 Self::And(..) => 4,
151 Self::Or(..) => 3,
152 Self::DotDot(..) | Self::DotDotEq(..) => 2,
153 _ => 1,
155 }
156 }
157
158 pub(crate) fn is_assoc(&self) -> bool {
160 match self {
161 Self::Mul(..) => true,
162 Self::Div(..) => true,
163 Self::Add(..) => true,
164 Self::Sub(..) => true,
165 Self::Or(..) => true,
166 Self::And(..) => true,
167 Self::Rem(..) => true,
168 Self::Shl(..) => true,
169 Self::Shr(..) => true,
170 Self::BitAnd(..) => true,
171 Self::BitOr(..) => true,
172 Self::BitXor(..) => true,
173 _ => false,
174 }
175 }
176
177 pub(crate) fn from_slice_with_range(out: &[ast::Token]) -> Option<Self> {
179 Self::from_slice_with(out, true)
180 }
181
182 pub(crate) fn from_slice(out: &[ast::Token]) -> Option<Self> {
184 Self::from_slice_with(out, false)
185 }
186
187 fn from_slice_with(out: &[ast::Token], range: bool) -> Option<Self> {
189 let &ast::Token { span, kind } = out.first()?;
190
191 let out = match kind {
192 K![+] => Self::Add(ast::Plus { span }),
193 K![-] => Self::Sub(ast::Dash { span }),
194 K![*] => Self::Mul(ast::Star { span }),
195 K![/] => Self::Div(ast::Div { span }),
196 K![%] => Self::Rem(ast::Perc { span }),
197 K![==] => Self::Eq(ast::EqEq { span }),
198 K![!=] => Self::Neq(ast::BangEq { span }),
199 K![<] => Self::Lt(ast::Lt { span }),
200 K![>] => Self::Gt(ast::Gt { span }),
201 K![<=] => Self::Lte(ast::LtEq { span }),
202 K![>=] => Self::Gte(ast::GtEq { span }),
203 K![as] => Self::As(ast::As { span }),
204 K![is] => {
205 let is = ast::Is { span };
206
207 if let Some(&ast::Token {
208 kind: K![not],
209 span,
210 }) = out.get(1)
211 {
212 Self::IsNot(ast::IsNot {
213 is,
214 not: ast::Not { span },
215 })
216 } else {
217 Self::Is(is)
218 }
219 }
220 K![&&] => Self::And(ast::AmpAmp { span }),
221 K![||] => Self::Or(ast::PipePipe { span }),
222 K![<<] => Self::Shl(ast::LtLt { span }),
223 K![>>] => Self::Shr(ast::GtGt { span }),
224 K![&] => Self::BitAnd(ast::Amp { span }),
225 K![^] => Self::BitXor(ast::Caret { span }),
226 K![|] => Self::BitOr(ast::Pipe { span }),
227 K![+=] => Self::AddAssign(ast::PlusEq { span }),
228 K![-=] => Self::SubAssign(ast::DashEq { span }),
229 K![*=] => Self::MulAssign(ast::StarEq { span }),
230 K![/=] => Self::DivAssign(ast::SlashEq { span }),
231 K![%=] => Self::RemAssign(ast::PercEq { span }),
232 K![&=] => Self::BitAndAssign(ast::AmpEq { span }),
233 K![^=] => Self::BitXorAssign(ast::CaretEq { span }),
234 K![|=] => Self::BitOrAssign(ast::PipeEq { span }),
235 K![<<=] => Self::ShlAssign(ast::LtLtEq { span }),
236 K![>>=] => Self::ShrAssign(ast::GtGtEq { span }),
237 K![..] if range => Self::DotDot(ast::DotDot { span }),
238 K![..=] if range => Self::DotDotEq(ast::DotDotEq { span }),
239 _ => return None,
240 };
241
242 Some(out)
243 }
244
245 pub(crate) fn from_peeker(p: &mut Peeker<'_>) -> Option<Self> {
247 let array = p.array::<2>();
248 Self::from_slice_with_range(&array)
249 }
250
251 pub(crate) fn advance<A>(&self, p: &mut A) -> Result<(), A::Error>
253 where
254 A: ?Sized + Advance,
255 {
256 match self {
257 Self::IsNot(..) => {
258 p.advance(2)?;
259 }
260 _ => {
261 p.advance(1)?;
262 }
263 }
264
265 Ok(())
266 }
267}
268
269impl fmt::Display for BinOp {
270 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
271 match *self {
272 Self::Add(..) => write!(f, "+"),
273 Self::Sub(..) => write!(f, "-"),
274 Self::Div(..) => write!(f, "/"),
275 Self::Mul(..) => write!(f, "*"),
276 Self::Rem(..) => write!(f, "%"),
277 Self::Eq(..) => write!(f, "=="),
278 Self::Neq(..) => write!(f, "!="),
279 Self::Gt(..) => write!(f, ">"),
280 Self::Lt(..) => write!(f, "<"),
281 Self::Gte(..) => write!(f, ">="),
282 Self::Lte(..) => write!(f, "<="),
283 Self::As(..) => write!(f, "as"),
284 Self::Is(..) => write!(f, "is"),
285 Self::IsNot(..) => write!(f, "is not"),
286 Self::And(..) => write!(f, "&&"),
287 Self::Or(..) => write!(f, "||"),
288 Self::Shl(..) => write!(f, "<<"),
289 Self::Shr(..) => write!(f, ">>"),
290 Self::BitAnd(..) => write!(f, "&"),
291 Self::BitXor(..) => write!(f, "^"),
292 Self::BitOr(..) => write!(f, "|"),
293 Self::AddAssign(..) => write!(f, "+="),
294 Self::SubAssign(..) => write!(f, "-="),
295 Self::DivAssign(..) => write!(f, "/="),
296 Self::MulAssign(..) => write!(f, "*="),
297 Self::BitAndAssign(..) => write!(f, "&="),
298 Self::BitXorAssign(..) => write!(f, "^="),
299 Self::BitOrAssign(..) => write!(f, "|="),
300 Self::RemAssign(..) => write!(f, "%="),
301 Self::ShlAssign(..) => write!(f, "<<="),
302 Self::ShrAssign(..) => write!(f, ">>="),
303 Self::DotDot(..) => write!(f, ".."),
304 Self::DotDotEq(..) => write!(f, "..="),
305 }
306 }
307}
308
309impl Peek for BinOp {
310 fn peek(p: &mut Peeker<'_>) -> bool {
311 let slice = p.array::<2>();
312 Self::from_slice_with_range(&slice).is_some()
313 }
314}