1use crate::cst::utils::token_with;
2
3use super::*;
4
5pub enum Expr {
7 Literal(LiteralToken),
9
10 Ident(IdentToken),
12
13 Paren(ParenExpr),
15
16 Block(BlockExpr),
18 Binary(BinaryExpr),
20 Unary(UnaryExpr),
22 Chain(ChainExpr),
24
25 Break(Break),
27 Continue(Continue),
29 Return(Return),
31 Throw(Throw),
33
34 While(While),
36 For(ForLoop),
38
39 TryCatch(TryCatch),
41
42 IfElse(IfElse),
44
45 Match(Match),
47
48 Variable(VariableStmt),
50 Import(ImportStmt),
52 TypeAlias(TypeAlias),
54 Function(Function),
56 Trait(Trait),
58 TraitImpl(TraitImpl),
60 Class(Class),
62 Enum(Enum),
64
65 Fragment(Fragment),
67}
68
69impl CstNode for Expr {
70 fn can_cast(_kind: SyntaxKind) -> bool {
71 true
72 }
73
74 fn syntax(&self) -> &SyntaxNode {
75 match self {
76 Expr::Break(n) => n.syntax(),
77 Expr::Continue(n) => n.syntax(),
78 Expr::Return(n) => n.syntax(),
79 Expr::Throw(n) => n.syntax(),
80 Expr::While(n) => n.syntax(),
81 Expr::For(n) => n.syntax(),
82 Expr::TryCatch(n) => n.syntax(),
83 Expr::IfElse(n) => n.syntax(),
84 Expr::Match(n) => n.syntax(),
85 Expr::Variable(n) => n.syntax(),
86 Expr::Import(n) => n.syntax(),
87 Expr::TypeAlias(n) => n.syntax(),
88 Expr::Function(n) => n.syntax(),
89 Expr::Trait(n) => n.syntax(),
90 Expr::TraitImpl(n) => n.syntax(),
91 Expr::Class(n) => n.syntax(),
92 Expr::Enum(n) => n.syntax(),
93
94 Expr::Binary(n) => &n.syntax,
95 Expr::Unary(n) => &n.syntax,
96 Expr::Chain(n) => &n.syntax,
97 Expr::Paren(n) => &n.syntax,
98 Expr::Block(n) => &n.syntax,
99 Expr::Fragment(n) => match n {
100 Fragment::EnumVariant(enum_variant_decl) => &enum_variant_decl.syntax,
101 Fragment::Modifiers(modifiers) => &modifiers.syntax,
102 Fragment::Generic { syntax } => &syntax,
103 Fragment::Unknown(_) => todo!(),
104 Fragment::MatchArm(match_arm) => match match_arm {
105 MatchArm::WithCondition(match_arm_with_condition) => {
106 &match_arm_with_condition.syntax
107 }
108 MatchArm::Default(match_arm_default) => &match_arm_default.syntax,
109 },
110 },
111 Expr::Literal(_) | Expr::Ident(_) => todo!(),
112 }
113 }
114
115 fn cast(syntax: SyntaxNode) -> Option<Self> {
116 let kind = syntax.kind();
117 Some(match kind {
118 SyntaxKind::DelimitedRange => disambiguate_delimited(syntax),
119 SyntaxKind::Operator => disambiguate_operator(syntax),
120 SyntaxKind::LoopBreak => Expr::Break(Break { syntax }),
121 SyntaxKind::LoopContinue => Expr::Continue(Continue { syntax }),
122 SyntaxKind::Return => Expr::Return(Return { syntax }),
123 SyntaxKind::ThrowError => Expr::Throw(Throw { syntax }),
124
125 SyntaxKind::WhileLoop => Expr::While(While { syntax }),
126 SyntaxKind::ForLoop => Expr::For(ForLoop { syntax }),
127 SyntaxKind::TryCatch => Expr::TryCatch(TryCatch { syntax }),
128 SyntaxKind::IfElse => Expr::IfElse(IfElse { syntax }),
129 SyntaxKind::Match => Expr::Match(Match { syntax }),
130 SyntaxKind::VariableDeclaration => Expr::Variable(VariableStmt { syntax }),
131 SyntaxKind::Import => Expr::Import(ImportStmt { syntax }),
132 SyntaxKind::TypeAlias => Expr::TypeAlias(TypeAlias { syntax }),
133 SyntaxKind::Function => Expr::Function(Function { syntax }),
134 SyntaxKind::Trait => Expr::Trait(Trait { syntax }),
135 SyntaxKind::TraitImpl => Expr::TraitImpl(TraitImpl { syntax }),
136 SyntaxKind::Class => Expr::Class(Class { syntax }),
137 SyntaxKind::Enum => Expr::Enum(Enum { syntax }),
138 SyntaxKind::EnumVariant => {
139 Expr::Fragment(Fragment::EnumVariant(EnumVariant { syntax }))
140 }
141 SyntaxKind::Modifiers => Expr::Fragment(Fragment::Modifiers(Modifiers { syntax })),
142 SyntaxKind::MatchCondition => Expr::Fragment(Fragment::MatchArm(
143 MatchArm::WithCondition(MatchArmWithCondition { syntax }),
144 )),
145 SyntaxKind::MatchConditionDefault => {
146 Expr::Fragment(Fragment::MatchArm(MatchArm::Default(MatchArmDefault {
147 syntax,
148 })))
149 }
150 _ => Expr::Fragment(Fragment::Generic { syntax }),
151 })
152 }
153}
154
155fn disambiguate_delimited(syntax: SyntaxNode) -> Expr {
156 let para = ParenRange { syntax };
157
158 if para.open_token().is_some() || para.close_token().is_some() {
159 Expr::Paren(ParenExpr {
160 syntax: para.syntax,
161 })
162 } else {
163 Expr::Block(BlockExpr {
164 syntax: para.syntax,
165 })
166 }
167}
168
169fn disambiguate_operator(syntax: SyntaxNode) -> Expr {
170 const fn is(kind: SyntaxKind) -> bool {
171 matches!(
172 kind,
173 SyntaxKind::OpMethodChaining
174 | OpMinus
175 | OpNot
176 | OpEq
177 | OpNotEq
178 | OpLt
179 | OpGt
180 | OpLtEq
181 | OpGtEq
182 | OpAnd
183 | OpOr
184 | OpPlus
185 | OpMul
186 | OpDivide
187 | OpMod
188 )
189 }
190
191 let Some(token) = token_with(&syntax, is) else {
192 unreachable!()
193 };
194
195 use SyntaxKind::*;
196 match token.kind() {
197 OpMethodChaining => Expr::Chain(ChainExpr { syntax }),
198 OpEq | OpNotEq | OpLt | OpGt | OpLtEq | OpGtEq | OpAnd | OpOr | OpPlus | OpMul
199 | OpDivide | OpMod => Expr::Binary(BinaryExpr { syntax }),
200 OpNot => Expr::Unary(UnaryExpr { syntax }),
201 OpMinus => {
202 let binary = BinaryExpr { syntax };
203
204 match binary.lhs() {
206 None => Expr::Unary(UnaryExpr {
207 syntax: binary.syntax,
208 }),
209 _ => Expr::Binary(binary),
210 }
211 }
212 _ => unreachable!(),
213 }
214}
215
216impl Expr {
217 pub(crate) fn cast_element(element: SyntaxElementRef) -> Expr {
218 match element {
219 cstree::util::NodeOrToken::Node(node) => {
220 let Some(expr) = Expr::cast(node.clone()) else {
221 unreachable!()
222 };
223
224 expr
225 }
226 cstree::util::NodeOrToken::Token(token) => {
227 let token = token.clone();
228 match token.kind() {
229 SyntaxKind::Unknown => {
230 Expr::Fragment(Fragment::Unknown(UnknownToken { token }))
231 }
232 SyntaxKind::Literal => Expr::Literal(LiteralToken { token }),
233 SyntaxKind::Ident => Expr::Ident(IdentToken { token }),
234
235 _ => unreachable!(),
236 }
237 }
238 }
239 }
240}