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