sixtyfps_compilerlib/parser/
expressions.rs1use super::document::parse_qualified_name;
5use super::prelude::*;
6
7#[cfg_attr(test, parser_test)]
8pub fn parse_expression(p: &mut impl Parser) -> bool {
35 parse_expression_helper(p, OperatorPrecedence::Default)
36}
37
38#[derive(Eq, PartialEq, Ord, PartialOrd)]
39#[repr(u8)]
40enum OperatorPrecedence {
41 Default,
43 Logical,
45 Equality,
47 Add,
49 Mul,
51 Unary,
52}
53
54fn parse_expression_helper(p: &mut impl Parser, precedence: OperatorPrecedence) -> bool {
55 let mut p = p.start_node(SyntaxKind::Expression);
56 let checkpoint = p.checkpoint();
57 match p.nth(0).kind() {
58 SyntaxKind::Identifier => {
59 parse_qualified_name(&mut *p);
60 }
61 SyntaxKind::StringLiteral => {
62 if p.nth(0).as_str().ends_with('{') {
63 parse_template_string(&mut *p)
64 } else {
65 p.consume()
66 }
67 }
68 SyntaxKind::NumberLiteral => p.consume(),
69 SyntaxKind::ColorLiteral => p.consume(),
70 SyntaxKind::LParent => {
71 p.consume();
72 parse_expression(&mut *p);
73 p.expect(SyntaxKind::RParent);
74 }
75 SyntaxKind::LBracket => parse_array(&mut *p),
76 SyntaxKind::LBrace => parse_object_notation(&mut *p),
77 SyntaxKind::Plus | SyntaxKind::Minus | SyntaxKind::Bang => {
78 let mut p = p.start_node(SyntaxKind::UnaryOpExpression);
79 p.consume();
80 parse_expression_helper(&mut *p, OperatorPrecedence::Unary);
81 }
82 SyntaxKind::At => {
83 parse_at_keyword(&mut *p);
84 }
85 _ => {
86 p.error("invalid expression");
87 return false;
88 }
89 }
90
91 loop {
92 match p.nth(0).kind() {
93 SyntaxKind::Dot => {
94 {
95 let _ = p.start_node_at(checkpoint.clone(), SyntaxKind::Expression);
96 }
97 let mut p = p.start_node_at(checkpoint.clone(), SyntaxKind::MemberAccess);
98 p.consume(); if !p.expect(SyntaxKind::Identifier) {
100 return false;
101 }
102 }
103 SyntaxKind::LParent => {
104 {
105 let _ = p.start_node_at(checkpoint.clone(), SyntaxKind::Expression);
106 }
107 let mut p = p.start_node_at(checkpoint.clone(), SyntaxKind::FunctionCallExpression);
108 parse_function_arguments(&mut *p);
109 }
110 SyntaxKind::LBracket => {
111 {
112 let _ = p.start_node_at(checkpoint.clone(), SyntaxKind::Expression);
113 }
114 let mut p = p.start_node_at(checkpoint.clone(), SyntaxKind::IndexExpression);
115 p.expect(SyntaxKind::LBracket);
116 parse_expression(&mut *p);
117 p.expect(SyntaxKind::RBracket);
118 }
119 _ => break,
120 }
121 }
122
123 if precedence >= OperatorPrecedence::Mul {
124 return true;
125 }
126
127 while matches!(p.nth(0).kind(), SyntaxKind::Star | SyntaxKind::Div) {
128 {
129 let _ = p.start_node_at(checkpoint.clone(), SyntaxKind::Expression);
130 }
131 let mut p = p.start_node_at(checkpoint.clone(), SyntaxKind::BinaryExpression);
132 p.consume();
133 parse_expression_helper(&mut *p, OperatorPrecedence::Mul);
134 }
135
136 if precedence >= OperatorPrecedence::Add {
137 return true;
138 }
139
140 while matches!(p.nth(0).kind(), SyntaxKind::Plus | SyntaxKind::Minus) {
141 {
142 let _ = p.start_node_at(checkpoint.clone(), SyntaxKind::Expression);
143 }
144 let mut p = p.start_node_at(checkpoint.clone(), SyntaxKind::BinaryExpression);
145 p.consume();
146 parse_expression_helper(&mut *p, OperatorPrecedence::Add);
147 }
148
149 if precedence > OperatorPrecedence::Equality {
150 return true;
151 }
152
153 if matches!(
154 p.nth(0).kind(),
155 SyntaxKind::LessEqual
156 | SyntaxKind::GreaterEqual
157 | SyntaxKind::EqualEqual
158 | SyntaxKind::NotEqual
159 | SyntaxKind::LAngle
160 | SyntaxKind::RAngle
161 ) {
162 if precedence == OperatorPrecedence::Equality {
163 p.error("Use parentheses to disambiguate equality expression on the same level");
164 }
165
166 {
167 let _ = p.start_node_at(checkpoint.clone(), SyntaxKind::Expression);
168 }
169 let mut p = p.start_node_at(checkpoint.clone(), SyntaxKind::BinaryExpression);
170 p.consume();
171 parse_expression_helper(&mut *p, OperatorPrecedence::Equality);
172 }
173
174 if precedence >= OperatorPrecedence::Logical {
175 return true;
176 }
177
178 let mut prev_logical_op = None;
179 while matches!(p.nth(0).kind(), SyntaxKind::AndAnd | SyntaxKind::OrOr) {
180 if let Some(prev) = prev_logical_op {
181 if prev != p.nth(0).kind() {
182 p.error("Use parentheses to disambiguate between && and ||");
183 prev_logical_op = None;
184 }
185 } else {
186 prev_logical_op = Some(p.nth(0).kind());
187 }
188
189 {
190 let _ = p.start_node_at(checkpoint.clone(), SyntaxKind::Expression);
191 }
192 let mut p = p.start_node_at(checkpoint.clone(), SyntaxKind::BinaryExpression);
193 p.consume();
194 parse_expression_helper(&mut *p, OperatorPrecedence::Logical);
195 }
196
197 if p.nth(0).kind() == SyntaxKind::Question {
198 {
199 let _ = p.start_node_at(checkpoint.clone(), SyntaxKind::Expression);
200 }
201 let mut p = p.start_node_at(checkpoint, SyntaxKind::ConditionalExpression);
202 p.consume();
203 parse_expression(&mut *p);
204 p.expect(SyntaxKind::Colon);
205 parse_expression(&mut *p);
206 }
207 true
208}
209
210#[cfg_attr(test, parser_test)]
211fn parse_at_keyword(p: &mut impl Parser) {
216 debug_assert_eq!(p.peek().kind(), SyntaxKind::At);
217 match p.nth(1).as_str() {
218 "image-url" | "image_url" => {
219 let mut p = p.start_node(SyntaxKind::AtImageUrl);
220 p.consume(); p.consume(); p.expect(SyntaxKind::LParent);
223 p.expect(SyntaxKind::StringLiteral);
224 p.expect(SyntaxKind::RParent);
225 }
226 "linear-gradient" | "linear_gradient" => {
227 parse_at_linear_gradient(p);
228 }
229 _ => {
230 p.consume();
231 p.error("Expected 'image-url' or 'linear-gradient' after '@'");
232 }
233 }
234}
235
236#[cfg_attr(test, parser_test)]
237fn parse_array(p: &mut impl Parser) {
244 let mut p = p.start_node(SyntaxKind::Array);
245 p.expect(SyntaxKind::LBracket);
246
247 while p.nth(0).kind() != SyntaxKind::RBracket {
248 parse_expression(&mut *p);
249 if !p.test(SyntaxKind::Comma) {
250 break;
251 }
252 }
253 p.expect(SyntaxKind::RBracket);
254}
255
256#[cfg_attr(test, parser_test)]
257fn parse_object_notation(p: &mut impl Parser) {
264 let mut p = p.start_node(SyntaxKind::ObjectLiteral);
265 p.expect(SyntaxKind::LBrace);
266
267 while p.nth(0).kind() != SyntaxKind::RBrace {
268 let mut p = p.start_node(SyntaxKind::ObjectMember);
269 p.expect(SyntaxKind::Identifier);
270 p.expect(SyntaxKind::Colon);
271 parse_expression(&mut *p);
272 if !p.test(SyntaxKind::Comma) {
273 break;
274 }
275 }
276 p.expect(SyntaxKind::RBrace);
277}
278
279#[cfg_attr(test, parser_test)]
280fn parse_function_arguments(p: &mut impl Parser) {
287 p.expect(SyntaxKind::LParent);
288
289 while p.nth(0).kind() != SyntaxKind::RParent {
290 parse_expression(&mut *p);
291 if !p.test(SyntaxKind::Comma) {
292 break;
293 }
294 }
295 p.expect(SyntaxKind::RParent);
296}
297
298#[cfg_attr(test, parser_test)]
299fn parse_template_string(p: &mut impl Parser) {
304 let mut p = p.start_node(SyntaxKind::StringTemplate);
305 debug_assert!(p.nth(0).as_str().ends_with("\\{"));
306 {
307 let mut p = p.start_node(SyntaxKind::Expression);
308 p.consume();
309 }
310 loop {
311 parse_expression(&mut *p);
312 let peek = p.peek();
313 if peek.kind != SyntaxKind::StringLiteral || !peek.as_str().starts_with('}') {
314 p.error("Error while parsing string template")
315 }
316 let mut p = p.start_node(SyntaxKind::Expression);
317 let cont = peek.as_str().ends_with('{');
318 p.consume();
319 if !cont {
320 break;
321 }
322 }
323}
324
325#[cfg_attr(test, parser_test)]
326fn parse_at_linear_gradient(p: &mut impl Parser) {
334 let mut p = p.start_node(SyntaxKind::AtLinearGradient);
335 p.expect(SyntaxKind::At);
336 debug_assert!(p.peek().as_str() == "linear-gradient" || p.peek().as_str() == "linear_gradient");
337 p.consume(); p.expect(SyntaxKind::LParent);
340
341 while !p.test(SyntaxKind::RParent) {
342 if !parse_expression(&mut *p) {
343 return;
344 }
345 p.test(SyntaxKind::Comma);
346 }
347}