diff options
Diffstat (limited to 'crates/ra_syntax/src/ast/expr_extensions.rs')
-rw-r--r-- | crates/ra_syntax/src/ast/expr_extensions.rs | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs new file mode 100644 index 000000000..ddc26206f --- /dev/null +++ b/crates/ra_syntax/src/ast/expr_extensions.rs | |||
@@ -0,0 +1,250 @@ | |||
1 | use crate::{ | ||
2 | SyntaxToken, SyntaxElement, SmolStr, | ||
3 | ast::{self, AstNode, AstChildren, children, child_opt}, | ||
4 | SyntaxKind::* | ||
5 | }; | ||
6 | |||
7 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
8 | pub enum ElseBranch<'a> { | ||
9 | Block(&'a ast::Block), | ||
10 | IfExpr(&'a ast::IfExpr), | ||
11 | } | ||
12 | |||
13 | impl ast::IfExpr { | ||
14 | pub fn then_branch(&self) -> Option<&ast::Block> { | ||
15 | self.blocks().nth(0) | ||
16 | } | ||
17 | pub fn else_branch(&self) -> Option<ElseBranch> { | ||
18 | let res = match self.blocks().nth(1) { | ||
19 | Some(block) => ElseBranch::Block(block), | ||
20 | None => { | ||
21 | let elif: &ast::IfExpr = child_opt(self)?; | ||
22 | ElseBranch::IfExpr(elif) | ||
23 | } | ||
24 | }; | ||
25 | Some(res) | ||
26 | } | ||
27 | |||
28 | fn blocks(&self) -> AstChildren<ast::Block> { | ||
29 | children(self) | ||
30 | } | ||
31 | } | ||
32 | |||
33 | impl ast::RefExpr { | ||
34 | pub fn is_mut(&self) -> bool { | ||
35 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) | ||
36 | } | ||
37 | } | ||
38 | |||
39 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
40 | pub enum PrefixOp { | ||
41 | /// The `*` operator for dereferencing | ||
42 | Deref, | ||
43 | /// The `!` operator for logical inversion | ||
44 | Not, | ||
45 | /// The `-` operator for negation | ||
46 | Neg, | ||
47 | } | ||
48 | |||
49 | impl ast::PrefixExpr { | ||
50 | pub fn op_kind(&self) -> Option<PrefixOp> { | ||
51 | match self.op_token()?.kind() { | ||
52 | STAR => Some(PrefixOp::Deref), | ||
53 | EXCL => Some(PrefixOp::Not), | ||
54 | MINUS => Some(PrefixOp::Neg), | ||
55 | _ => None, | ||
56 | } | ||
57 | } | ||
58 | |||
59 | pub fn op_token(&self) -> Option<SyntaxToken> { | ||
60 | self.syntax().first_child_or_token()?.as_token() | ||
61 | } | ||
62 | } | ||
63 | |||
64 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
65 | pub enum BinOp { | ||
66 | /// The `||` operator for boolean OR | ||
67 | BooleanOr, | ||
68 | /// The `&&` operator for boolean AND | ||
69 | BooleanAnd, | ||
70 | /// The `==` operator for equality testing | ||
71 | EqualityTest, | ||
72 | /// The `!=` operator for equality testing | ||
73 | NegatedEqualityTest, | ||
74 | /// The `<=` operator for lesser-equal testing | ||
75 | LesserEqualTest, | ||
76 | /// The `>=` operator for greater-equal testing | ||
77 | GreaterEqualTest, | ||
78 | /// The `<` operator for comparison | ||
79 | LesserTest, | ||
80 | /// The `>` operator for comparison | ||
81 | GreaterTest, | ||
82 | /// The `+` operator for addition | ||
83 | Addition, | ||
84 | /// The `*` operator for multiplication | ||
85 | Multiplication, | ||
86 | /// The `-` operator for subtraction | ||
87 | Subtraction, | ||
88 | /// The `/` operator for division | ||
89 | Division, | ||
90 | /// The `%` operator for remainder after division | ||
91 | Remainder, | ||
92 | /// The `<<` operator for left shift | ||
93 | LeftShift, | ||
94 | /// The `>>` operator for right shift | ||
95 | RightShift, | ||
96 | /// The `^` operator for bitwise XOR | ||
97 | BitwiseXor, | ||
98 | /// The `|` operator for bitwise OR | ||
99 | BitwiseOr, | ||
100 | /// The `&` operator for bitwise AND | ||
101 | BitwiseAnd, | ||
102 | /// The `..` operator for right-open ranges | ||
103 | RangeRightOpen, | ||
104 | /// The `..=` operator for right-closed ranges | ||
105 | RangeRightClosed, | ||
106 | /// The `=` operator for assignment | ||
107 | Assignment, | ||
108 | /// The `+=` operator for assignment after addition | ||
109 | AddAssign, | ||
110 | /// The `/=` operator for assignment after division | ||
111 | DivAssign, | ||
112 | /// The `*=` operator for assignment after multiplication | ||
113 | MulAssign, | ||
114 | /// The `%=` operator for assignment after remainders | ||
115 | RemAssign, | ||
116 | /// The `>>=` operator for assignment after shifting right | ||
117 | ShrAssign, | ||
118 | /// The `<<=` operator for assignment after shifting left | ||
119 | ShlAssign, | ||
120 | /// The `-=` operator for assignment after subtraction | ||
121 | SubAssign, | ||
122 | /// The `|=` operator for assignment after bitwise OR | ||
123 | BitOrAssign, | ||
124 | /// The `&=` operator for assignment after bitwise AND | ||
125 | BitAndAssign, | ||
126 | /// The `^=` operator for assignment after bitwise XOR | ||
127 | BitXorAssign, | ||
128 | } | ||
129 | |||
130 | impl ast::BinExpr { | ||
131 | fn op_details(&self) -> Option<(SyntaxToken, BinOp)> { | ||
132 | self.syntax().children_with_tokens().filter_map(|it| it.as_token()).find_map(|c| { | ||
133 | match c.kind() { | ||
134 | PIPEPIPE => Some((c, BinOp::BooleanOr)), | ||
135 | AMPAMP => Some((c, BinOp::BooleanAnd)), | ||
136 | EQEQ => Some((c, BinOp::EqualityTest)), | ||
137 | NEQ => Some((c, BinOp::NegatedEqualityTest)), | ||
138 | LTEQ => Some((c, BinOp::LesserEqualTest)), | ||
139 | GTEQ => Some((c, BinOp::GreaterEqualTest)), | ||
140 | L_ANGLE => Some((c, BinOp::LesserTest)), | ||
141 | R_ANGLE => Some((c, BinOp::GreaterTest)), | ||
142 | PLUS => Some((c, BinOp::Addition)), | ||
143 | STAR => Some((c, BinOp::Multiplication)), | ||
144 | MINUS => Some((c, BinOp::Subtraction)), | ||
145 | SLASH => Some((c, BinOp::Division)), | ||
146 | PERCENT => Some((c, BinOp::Remainder)), | ||
147 | SHL => Some((c, BinOp::LeftShift)), | ||
148 | SHR => Some((c, BinOp::RightShift)), | ||
149 | CARET => Some((c, BinOp::BitwiseXor)), | ||
150 | PIPE => Some((c, BinOp::BitwiseOr)), | ||
151 | AMP => Some((c, BinOp::BitwiseAnd)), | ||
152 | DOTDOT => Some((c, BinOp::RangeRightOpen)), | ||
153 | DOTDOTEQ => Some((c, BinOp::RangeRightClosed)), | ||
154 | EQ => Some((c, BinOp::Assignment)), | ||
155 | PLUSEQ => Some((c, BinOp::AddAssign)), | ||
156 | SLASHEQ => Some((c, BinOp::DivAssign)), | ||
157 | STAREQ => Some((c, BinOp::MulAssign)), | ||
158 | PERCENTEQ => Some((c, BinOp::RemAssign)), | ||
159 | SHREQ => Some((c, BinOp::ShrAssign)), | ||
160 | SHLEQ => Some((c, BinOp::ShlAssign)), | ||
161 | MINUSEQ => Some((c, BinOp::SubAssign)), | ||
162 | PIPEEQ => Some((c, BinOp::BitOrAssign)), | ||
163 | AMPEQ => Some((c, BinOp::BitAndAssign)), | ||
164 | CARETEQ => Some((c, BinOp::BitXorAssign)), | ||
165 | _ => None, | ||
166 | } | ||
167 | }) | ||
168 | } | ||
169 | |||
170 | pub fn op_kind(&self) -> Option<BinOp> { | ||
171 | self.op_details().map(|t| t.1) | ||
172 | } | ||
173 | |||
174 | pub fn op_token(&self) -> Option<SyntaxToken> { | ||
175 | self.op_details().map(|t| t.0) | ||
176 | } | ||
177 | |||
178 | pub fn lhs(&self) -> Option<&ast::Expr> { | ||
179 | children(self).nth(0) | ||
180 | } | ||
181 | |||
182 | pub fn rhs(&self) -> Option<&ast::Expr> { | ||
183 | children(self).nth(1) | ||
184 | } | ||
185 | |||
186 | pub fn sub_exprs(&self) -> (Option<&ast::Expr>, Option<&ast::Expr>) { | ||
187 | let mut children = children(self); | ||
188 | let first = children.next(); | ||
189 | let second = children.next(); | ||
190 | (first, second) | ||
191 | } | ||
192 | } | ||
193 | |||
194 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||
195 | pub enum LiteralFlavor { | ||
196 | String, | ||
197 | ByteString, | ||
198 | Char, | ||
199 | Byte, | ||
200 | IntNumber { suffix: Option<SmolStr> }, | ||
201 | FloatNumber { suffix: Option<SmolStr> }, | ||
202 | Bool, | ||
203 | } | ||
204 | |||
205 | impl ast::Literal { | ||
206 | pub fn token(&self) -> SyntaxToken { | ||
207 | match self.syntax().first_child_or_token().unwrap() { | ||
208 | SyntaxElement::Token(token) => token, | ||
209 | _ => unreachable!(), | ||
210 | } | ||
211 | } | ||
212 | |||
213 | pub fn flavor(&self) -> LiteralFlavor { | ||
214 | match self.token().kind() { | ||
215 | INT_NUMBER => { | ||
216 | let allowed_suffix_list = [ | ||
217 | "isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32", | ||
218 | "u16", "u8", | ||
219 | ]; | ||
220 | let text = self.token().text().to_string(); | ||
221 | let suffix = allowed_suffix_list | ||
222 | .iter() | ||
223 | .find(|&s| text.ends_with(s)) | ||
224 | .map(|&suf| SmolStr::new(suf)); | ||
225 | LiteralFlavor::IntNumber { suffix } | ||
226 | } | ||
227 | FLOAT_NUMBER => { | ||
228 | let allowed_suffix_list = ["f64", "f32"]; | ||
229 | let text = self.token().text().to_string(); | ||
230 | let suffix = allowed_suffix_list | ||
231 | .iter() | ||
232 | .find(|&s| text.ends_with(s)) | ||
233 | .map(|&suf| SmolStr::new(suf)); | ||
234 | LiteralFlavor::FloatNumber { suffix: suffix } | ||
235 | } | ||
236 | STRING | RAW_STRING => LiteralFlavor::String, | ||
237 | TRUE_KW | FALSE_KW => LiteralFlavor::Bool, | ||
238 | BYTE_STRING | RAW_BYTE_STRING => LiteralFlavor::ByteString, | ||
239 | CHAR => LiteralFlavor::Char, | ||
240 | BYTE => LiteralFlavor::Byte, | ||
241 | _ => unreachable!(), | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | |||
246 | impl ast::NamedField { | ||
247 | pub fn parent_struct_lit(&self) -> &ast::StructLit { | ||
248 | self.syntax().ancestors().find_map(ast::StructLit::cast).unwrap() | ||
249 | } | ||
250 | } | ||