1use crate::arena::Arena;
2use crate::ast::node::{IdentWithToken, MatchArm, Pattern};
3use crate::error::syntax::SyntaxError;
4use crate::lexer::Lexer;
5use crate::lexer::token::{Token, TokenKind};
6use crate::module::ModuleId;
7use crate::selector::Selector;
8use crate::{Ident, Shared, lexer};
9use smallvec::{SmallVec, smallvec};
10use smol_str::SmolStr;
11use std::iter::Peekable;
12use std::sync::LazyLock;
13
14use super::constants;
15use super::node::{AccessTarget, Args, Branches, Expr, Literal, Node, Param, Params};
16use super::{Program, TokenId};
17
18type IfExpr = (Option<Shared<Node>>, Shared<Node>);
19
20static GET_IDENT: LazyLock<Ident> = LazyLock::new(|| Ident::from(constants::builtins::GET));
21
22pub struct Parser<'a, 'alloc> {
23 tokens: Peekable<core::slice::Iter<'a, Shared<Token>>>,
24 token_arena: &'alloc mut Arena<Shared<Token>>,
25 module_id: ModuleId,
26}
27
28impl<'a, 'alloc> Parser<'a, 'alloc> {
29 pub fn new(
30 tokens: core::slice::Iter<'a, Shared<Token>>,
31 token_arena: &'alloc mut Arena<Shared<Token>>,
32 module_id: ModuleId,
33 ) -> Self {
34 Self {
35 tokens: tokens.peekable(),
36 token_arena,
37 module_id,
38 }
39 }
40
41 pub fn parse(&mut self) -> Result<Program, SyntaxError> {
42 self.parse_program(true)
43 }
44
45 fn parse_program(&mut self, root: bool) -> Result<Program, SyntaxError> {
46 let mut asts = Vec::with_capacity(64);
47
48 match self.tokens.peek() {
50 Some(token) => match &token.kind {
51 TokenKind::Pipe | TokenKind::SemiColon => {
52 return Err(SyntaxError::UnexpectedToken((***token).clone()));
53 }
54 TokenKind::End => {
55 return Err(SyntaxError::UnmatchedEnd((***token).clone()));
56 }
57 _ => {}
58 },
59 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
60 };
61
62 while let Some(token) = self.tokens.next() {
63 match &token.kind {
64 TokenKind::Pipe => continue, TokenKind::Eof => break, TokenKind::SemiColon | TokenKind::End => {
67 if root {
71 match self.tokens.peek() {
72 Some(next_token) if !matches!(next_token.kind, TokenKind::Eof) => {
73 if matches!(token.kind, TokenKind::End) {
74 return Err(SyntaxError::UnmatchedEnd((**token).clone()));
75 } else {
76 return Err(SyntaxError::UnexpectedToken((***next_token).clone()));
77 }
78 }
79 _ => break,
80 }
81 }
82 break;
84 }
85 TokenKind::Nodes if root => {
86 let ast = self.parse_all_nodes(token)?;
87 asts.push(ast);
88 }
89 TokenKind::Nodes => {
90 return Err(SyntaxError::UnexpectedToken((**token).clone()));
91 }
92 TokenKind::NewLine | TokenKind::Tab(_) | TokenKind::Whitespace(_) => {
93 unreachable!("parse_program should have filtered out whitespace tokens")
94 }
95 _ => {
96 let ast = self.parse_expr(token)?;
97 asts.push(ast);
98 }
99 }
100 }
101
102 if asts.is_empty() {
103 return Err(SyntaxError::UnexpectedEOFDetected(self.module_id));
104 }
105
106 Ok(asts)
107 }
108
109 #[inline(always)]
110 fn parse_expr(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
111 self.parse_equality_expr(token)
112 }
113
114 #[inline(always)]
115 fn binary_op_precedence(kind: &TokenKind) -> u8 {
116 match kind {
117 TokenKind::Equal
118 | TokenKind::PlusEqual
119 | TokenKind::MinusEqual
120 | TokenKind::StarEqual
121 | TokenKind::SlashEqual
122 | TokenKind::PercentEqual
123 | TokenKind::DoubleSlashEqual => 0,
124 TokenKind::Or => 1,
125 TokenKind::And => 2,
126 TokenKind::EqEq
127 | TokenKind::NeEq
128 | TokenKind::Gt
129 | TokenKind::Gte
130 | TokenKind::Lt
131 | TokenKind::Lte
132 | TokenKind::TildeEqual
133 | TokenKind::NotTildeEqual => 3,
134 TokenKind::Plus | TokenKind::Minus | TokenKind::RightShift | TokenKind::LeftShift => 4,
135 TokenKind::Asterisk | TokenKind::Slash | TokenKind::Percent | TokenKind::Convert => 5,
136 TokenKind::DoubleDot | TokenKind::Coalesce => 6,
137 _ => 0,
138 }
139 }
140
141 fn binary_op_function_name(kind: &TokenKind) -> &'static str {
142 match kind {
143 TokenKind::Asterisk => constants::builtins::MUL,
144 TokenKind::Coalesce => constants::builtins::COALESCE,
145 TokenKind::EqEq => constants::builtins::EQ,
146 TokenKind::Gte => constants::builtins::GTE,
147 TokenKind::Gt => constants::builtins::GT,
148 TokenKind::Lte => constants::builtins::LTE,
149 TokenKind::Lt => constants::builtins::LT,
150 TokenKind::Minus => constants::builtins::SUB,
151 TokenKind::NeEq => constants::builtins::NE,
152 TokenKind::Percent => constants::builtins::MOD,
153 TokenKind::Plus => constants::builtins::ADD,
154 TokenKind::DoubleDot => constants::builtins::RANGE,
155 TokenKind::Slash => constants::builtins::DIV,
156 TokenKind::TildeEqual => constants::builtins::IS_REGEX_MATCH,
157 TokenKind::NotTildeEqual => constants::builtins::IS_NOT_REGEX_MATCH,
158 TokenKind::LeftShift => constants::builtins::SHIFT_LEFT,
159 TokenKind::RightShift => constants::builtins::SHIFT_RIGHT,
160 TokenKind::Convert => constants::builtins::CONVERT,
161 _ => unreachable!("binary_op_function_name called with non-binary operator"),
162 }
163 }
164
165 fn create_compound_assign(
166 &self,
167 lhs: &Shared<Node>,
168 rhs: Shared<Node>,
169 operator_token_id: TokenId,
170 operator_token: &Shared<Token>,
171 function_name: &'static str,
172 ) -> Result<Shared<Node>, SyntaxError> {
173 let compound_rhs = Shared::new(Node {
174 token_id: operator_token_id,
175 expr: Shared::new(Expr::Call(
176 IdentWithToken::new_with_token(function_name, Some(Shared::clone(operator_token))),
177 smallvec![Shared::clone(lhs), rhs],
178 )),
179 });
180 self.create_assign(lhs, compound_rhs, operator_token_id, operator_token)
181 }
182
183 fn create_assign(
188 &self,
189 lhs: &Shared<Node>,
190 rhs: Shared<Node>,
191 operator_token_id: TokenId,
192 operator_token: &Shared<Token>,
193 ) -> Result<Shared<Node>, SyntaxError> {
194 match &*lhs.expr {
195 Expr::Ident(ident) => Ok(Shared::new(Node {
196 token_id: operator_token_id,
197 expr: Shared::new(Expr::Assign(ident.clone(), rhs)),
198 })),
199 Expr::Call(func_ident, args) if func_ident.name == *GET_IDENT && args.len() == 2 => match &*args[0].expr {
200 Expr::Ident(var_ident) => Ok(Shared::new(Node {
201 token_id: operator_token_id,
202 expr: Shared::new(Expr::Assign(
203 var_ident.clone(),
204 Shared::new(Node {
205 token_id: operator_token_id,
206 expr: Shared::new(Expr::Call(
207 IdentWithToken::new_with_token(
208 constants::builtins::SET,
209 Some(Shared::clone(operator_token)),
210 ),
211 smallvec![Shared::clone(&args[0]), Shared::clone(&args[1]), rhs,],
212 )),
213 }),
214 )),
215 })),
216 _ => Err(SyntaxError::InvalidAssignmentTarget(
217 (*self.token_arena[args[0].token_id]).clone(),
218 )),
219 },
220 _ => Err(SyntaxError::InvalidAssignmentTarget(
221 (*self.token_arena[lhs.token_id]).clone(),
222 )),
223 }
224 }
225
226 fn parse_binary_op(parser: &mut Parser, min_prec: u8, mut lhs: Shared<Node>) -> Result<Shared<Node>, SyntaxError> {
227 while let Some(peeked_token_rc) = parser.tokens.peek() {
228 let kind = &peeked_token_rc.kind;
229 if !Self::is_binary_op(kind) {
230 break;
231 }
232
233 let prec = Self::binary_op_precedence(kind);
234
235 if prec < min_prec {
236 break;
237 }
238
239 let operator_token = parser.tokens.next().unwrap();
240 let operator_token_id = parser.token_arena.alloc(Shared::clone(operator_token));
241
242 let rhs_token = match parser.tokens.next() {
243 Some(t) if t.kind == TokenKind::Eof => {
244 return Err(SyntaxError::UnexpectedEOFAfterToken((**operator_token).clone()));
245 }
246 Some(t) => t,
247 None => return Err(SyntaxError::UnexpectedEOFAfterToken((**operator_token).clone())),
248 };
249 let mut rhs = parser.parse_primary_expr(rhs_token)?;
250
251 loop {
252 let next_prec = if let Some(next_token) = parser.tokens.peek() {
253 if Self::is_binary_op(&next_token.kind) {
254 Self::binary_op_precedence(&next_token.kind)
255 } else {
256 0
257 }
258 } else {
259 0
260 };
261 if next_prec > prec {
262 rhs = Self::parse_binary_op(parser, next_prec, rhs)?;
263 } else {
264 break;
265 }
266 }
267
268 lhs = match kind {
269 TokenKind::Equal => parser.create_assign(&lhs, rhs, operator_token_id, operator_token)?,
270 TokenKind::And => {
271 let operands = match &*lhs.expr {
272 Expr::And(existing) => {
273 let mut ops = existing.clone();
274 ops.push(rhs);
275 ops
276 }
277 _ => vec![lhs, rhs],
278 };
279 Shared::new(Node {
280 token_id: operator_token_id,
281 expr: Shared::new(Expr::And(operands)),
282 })
283 }
284 TokenKind::Or => {
285 let operands = match &*lhs.expr {
286 Expr::Or(existing) => {
287 let mut ops = existing.clone();
288 ops.push(rhs);
289 ops
290 }
291 _ => vec![lhs, rhs],
292 };
293 Shared::new(Node {
294 token_id: operator_token_id,
295 expr: Shared::new(Expr::Or(operands)),
296 })
297 }
298 TokenKind::PlusEqual => parser.create_compound_assign(
299 &lhs,
300 rhs,
301 operator_token_id,
302 operator_token,
303 constants::builtins::ADD,
304 )?,
305 TokenKind::MinusEqual => parser.create_compound_assign(
306 &lhs,
307 rhs,
308 operator_token_id,
309 operator_token,
310 constants::builtins::SUB,
311 )?,
312 TokenKind::StarEqual => parser.create_compound_assign(
313 &lhs,
314 rhs,
315 operator_token_id,
316 operator_token,
317 constants::builtins::MUL,
318 )?,
319 TokenKind::SlashEqual => parser.create_compound_assign(
320 &lhs,
321 rhs,
322 operator_token_id,
323 operator_token,
324 constants::builtins::DIV,
325 )?,
326 TokenKind::PercentEqual => parser.create_compound_assign(
327 &lhs,
328 rhs,
329 operator_token_id,
330 operator_token,
331 constants::builtins::MOD,
332 )?,
333 TokenKind::DoubleSlashEqual => {
334 let floor_div_rhs = Shared::new(Node {
335 token_id: operator_token_id,
336 expr: Shared::new(Expr::Call(
337 IdentWithToken::new_with_token(
338 constants::builtins::FLOOR,
339 Some(Shared::clone(operator_token)),
340 ),
341 smallvec![Shared::new(Node {
342 token_id: operator_token_id,
343 expr: Shared::new(Expr::Call(
344 IdentWithToken::new_with_token(
345 constants::builtins::DIV,
346 Some(Shared::clone(operator_token)),
347 ),
348 smallvec![Shared::clone(&lhs), rhs],
349 )),
350 })],
351 )),
352 });
353 parser.create_assign(&lhs, floor_div_rhs, operator_token_id, operator_token)?
354 }
355 _ => Shared::new(Node {
356 token_id: operator_token_id,
357 expr: Shared::new(Expr::Call(
358 IdentWithToken::new_with_token(
359 Self::binary_op_function_name(kind),
360 Some(Shared::clone(operator_token)),
361 ),
362 smallvec![lhs, rhs],
363 )),
364 }),
365 };
366 }
367
368 Ok(lhs)
369 }
370
371 fn parse_equality_expr(&mut self, initial_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
372 let lhs = self.parse_primary_expr(initial_token)?;
373 let lhs = Self::parse_binary_op(self, 0, lhs)?;
374
375 if let Some(token) = self.tokens.peek()
376 && matches!(token.kind, TokenKind::As)
377 {
378 return self.parse_as_binding(lhs);
379 }
380
381 Ok(lhs)
382 }
383
384 fn parse_as_binding(&mut self, expr: Shared<Node>) -> Result<Shared<Node>, SyntaxError> {
385 let as_token = self.tokens.next().unwrap();
386 let as_token_id = self.token_arena.alloc(Shared::clone(as_token));
387
388 let name_token = match self.tokens.next() {
389 Some(token) => token,
390 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
391 };
392
393 match &name_token.kind {
394 TokenKind::Ident(name) => {
395 let ident = IdentWithToken::new_with_token(name, Some(Shared::clone(name_token)));
396 Ok(Shared::new(Node {
397 token_id: as_token_id,
398 expr: Shared::new(Expr::As(ident, expr)),
399 }))
400 }
401 _ => Err(SyntaxError::UnexpectedToken((**name_token).clone())),
402 }
403 }
404
405 fn parse_primary_expr(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
406 match &token.kind {
407 TokenKind::Selector(_) | TokenKind::DoubleDot => self.parse_selector(token),
408 TokenKind::Let => self.parse_let(token),
409 TokenKind::Var => self.parse_var(token),
410 TokenKind::Def => self.parse_def(token),
411 TokenKind::Macro => self.parse_macro(token),
412 TokenKind::Do => self.parse_block(token),
413 TokenKind::Fn | TokenKind::Arrow => self.parse_fn(token),
414 TokenKind::While => self.parse_while(token),
415 TokenKind::Loop => self.parse_loop(token),
416 TokenKind::Foreach => self.parse_foreach(token),
417 TokenKind::Module => self.parse_module(token),
418 TokenKind::Try => self.parse_try(token),
419 TokenKind::Quote => self.parse_quote(token),
420 TokenKind::Unquote => self.parse_unquote(token),
421 TokenKind::If => self.parse_if(token),
422 TokenKind::Match => self.parse_match(token),
423 TokenKind::InterpolatedString(_) => self.parse_interpolated_string(token),
424 TokenKind::Include => self.parse_include(token),
425 TokenKind::Import => self.parse_import(token),
426 TokenKind::Self_ => self.parse_self(token),
427 TokenKind::Break => self.parse_break(token),
428 TokenKind::Continue => self.parse_continue(token),
429 TokenKind::Ident(name) => self.parse_ident(name, token),
430 TokenKind::BoolLiteral(_) => self.parse_literal(token),
431 TokenKind::StringLiteral(_) => self.parse_literal(token),
432 TokenKind::BytesLiteral(_) => self.parse_literal(token),
433 TokenKind::NumberLiteral(_) => self.parse_literal(token),
434 TokenKind::LBracket => self.parse_array(token),
435 TokenKind::LBrace => self.parse_dict(token),
436 TokenKind::LParen => self.parse_paren(token),
437 TokenKind::Not => self.parse_not(token),
438 TokenKind::Minus => self.parse_negate(token),
439 TokenKind::Env(_) => self.parse_env(token),
440 TokenKind::None => self.parse_literal(token),
441 TokenKind::Colon => self.parse_symbol(token),
442 TokenKind::Eof => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
443 _ => Err(SyntaxError::UnexpectedToken((**token).clone())),
444 }
445 }
446
447 fn parse_module(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
448 match &token.kind {
449 TokenKind::Module => match self.tokens.peek() {
450 Some(_) => {
451 let ident_token = self
452 .tokens
453 .next()
454 .ok_or(SyntaxError::UnexpectedEOFDetected(self.module_id))?;
455
456 self.consume_colon_or_do();
457
458 let program = self.parse_program(false)?;
459
460 for node in &program {
462 match &*node.expr {
463 Expr::Let(_, _) | Expr::Def(_, _, _) | Expr::Module(_, _) | Expr::Import(_) => {}
464 _ => {
465 return Err(SyntaxError::UnexpectedToken((*self.token_arena[node.token_id]).clone()));
466 }
467 }
468 }
469
470 Ok(Shared::new(Node {
471 token_id: self.token_arena.alloc(Shared::clone(token)),
472 expr: Shared::new(Expr::Module(
473 IdentWithToken::new_with_token(
474 match &ident_token.kind {
475 TokenKind::Ident(name) => name,
476 _ => {
477 return Err(SyntaxError::UnexpectedToken((**ident_token).clone()));
478 }
479 },
480 Some(Shared::clone(ident_token)),
481 ),
482 program.iter().map(Shared::clone).collect(),
483 )),
484 }))
485 }
486 None => Err(SyntaxError::UnexpectedToken((**token).clone())),
487 },
488 _ => Err(SyntaxError::UnexpectedToken((**token).clone())),
489 }
490 }
491
492 fn parse_symbol(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
493 match &token.kind {
494 TokenKind::Colon => {
495 let next_token = match self.tokens.next() {
496 Some(t) => t,
497 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
498 };
499 match &next_token.kind {
500 TokenKind::Ident(name) => Ok(Shared::new(Node {
501 token_id: self.token_arena.alloc(Shared::clone(token)),
502 expr: Shared::new(Expr::Literal(Literal::Symbol(Ident::new(name)))),
503 })),
504 TokenKind::StringLiteral(s) => Ok(Shared::new(Node {
505 token_id: self.token_arena.alloc(Shared::clone(token)),
506 expr: Shared::new(Expr::Literal(Literal::Symbol(Ident::new(s)))),
507 })),
508 _ => Err(SyntaxError::UnexpectedToken((**next_token).clone())),
509 }
510 }
511 _ => Err(SyntaxError::UnexpectedToken((**token).clone())),
512 }
513 }
514
515 fn parse_paren(&mut self, lparen_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
516 let opening = (**lparen_token).clone();
517 let token_id = self.token_arena.alloc(Shared::clone(lparen_token));
518 let expr_token = match self.tokens.next() {
519 Some(t) => t,
520 None => {
521 return Err(SyntaxError::ExpectedClosingParen(
522 Token {
523 range: opening.range,
524 kind: TokenKind::Eof,
525 module_id: self.module_id,
526 },
527 Some(Box::new(opening)),
528 ));
529 }
530 };
531
532 let expr_node = self.parse_expr(expr_token)?;
533
534 match self.tokens.next() {
535 Some(t) if t.kind == TokenKind::RParen => {}
536 Some(t) if t.kind == TokenKind::Eof => {
537 return Err(SyntaxError::ExpectedClosingParen(
538 (**t).clone(),
539 Some(Box::new(opening)),
540 ));
541 }
542 Some(t) => return Err(SyntaxError::UnexpectedToken((**t).clone())),
543 None => {
544 return Err(SyntaxError::ExpectedClosingParen(
545 Token {
546 range: opening.range,
547 kind: TokenKind::Eof,
548 module_id: self.module_id,
549 },
550 Some(Box::new(opening)),
551 ));
552 }
553 }
554
555 let paren_node = Shared::new(Node {
556 token_id,
557 expr: Shared::new(Expr::Paren(expr_node)),
558 });
559
560 self.parse_postfix_ops(paren_node, lparen_token)
562 }
563
564 fn parse_not(&mut self, not_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
565 let token_id = self.token_arena.alloc(Shared::clone(not_token));
566
567 let expr_token = match self.tokens.next() {
568 Some(t) if t.kind == TokenKind::Eof => {
569 return Err(SyntaxError::UnexpectedEOFAfterToken((**not_token).clone()));
570 }
571 Some(t) => t,
572 None => return Err(SyntaxError::UnexpectedEOFAfterToken((**not_token).clone())),
573 };
574
575 if !matches!(
576 expr_token.kind,
577 TokenKind::BoolLiteral(_)
578 | TokenKind::StringLiteral(_)
579 | TokenKind::BytesLiteral(_)
580 | TokenKind::NumberLiteral(_)
581 | TokenKind::If
582 | TokenKind::Foreach
583 | TokenKind::LBrace
584 | TokenKind::LBracket
585 | TokenKind::LParen
586 | TokenKind::While
587 | TokenKind::Loop
588 | TokenKind::Match
589 | TokenKind::Self_
590 | TokenKind::Selector(_)
591 | TokenKind::Env(_)
592 | TokenKind::Not
593 | TokenKind::Ident(_)
594 ) {
595 return Err(SyntaxError::UnexpectedToken((**expr_token).clone()));
596 }
597
598 let expr_node = self.parse_primary_expr(expr_token)?;
599
600 let not_ident = IdentWithToken::new_with_token(constants::builtins::NOT, Some(Shared::clone(not_token)));
602 let args = smallvec![expr_node];
603
604 Ok(Shared::new(Node {
605 token_id,
606 expr: Shared::new(Expr::Call(not_ident, args)),
607 }))
608 }
609
610 fn parse_negate(&mut self, minus_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
611 let token_id = self.token_arena.alloc(Shared::clone(minus_token));
612
613 let expr_token = match self.tokens.next() {
614 Some(t) if t.kind == TokenKind::Eof => {
615 return Err(SyntaxError::UnexpectedEOFAfterToken((**minus_token).clone()));
616 }
617 Some(t) => t,
618 None => return Err(SyntaxError::UnexpectedEOFAfterToken((**minus_token).clone())),
619 };
620
621 if !matches!(
622 expr_token.kind,
623 TokenKind::NumberLiteral(_)
624 | TokenKind::If
625 | TokenKind::Foreach
626 | TokenKind::LBrace
627 | TokenKind::LBracket
628 | TokenKind::While
629 | TokenKind::Loop
630 | TokenKind::Match
631 | TokenKind::Self_
632 | TokenKind::Env(_)
633 | TokenKind::Ident(_)
634 ) {
635 return Err(SyntaxError::UnexpectedToken((**expr_token).clone()));
636 }
637
638 let expr_node = self.parse_primary_expr(expr_token)?;
639 let negate_ident =
640 IdentWithToken::new_with_token(constants::builtins::NEGATE, Some(Shared::clone(minus_token)));
641 let args = smallvec![expr_node];
642
643 Ok(Shared::new(Node {
644 token_id,
645 expr: Shared::new(Expr::Call(negate_ident, args)),
646 }))
647 }
648
649 fn parse_dict(&mut self, lbrace_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
650 let opening = (**lbrace_token).clone();
651 let token_id = self.token_arena.alloc(Shared::clone(lbrace_token));
652 let mut pairs = SmallVec::new();
653
654 let eof_closing_err = |opening: &Token, module_id: ModuleId| {
655 SyntaxError::ExpectedClosingBrace(
656 Token {
657 range: opening.range,
658 kind: TokenKind::Eof,
659 module_id,
660 },
661 Some(Box::new(opening.clone())),
662 )
663 };
664
665 loop {
666 match self.tokens.peek() {
667 Some(token) if token.kind == TokenKind::RBrace => {
668 self.tokens.next();
669 break;
670 }
671 Some(token) if token.kind == TokenKind::Eof => {
672 return Err(SyntaxError::ExpectedClosingBrace(
673 (***token).clone(),
674 Some(Box::new(opening.clone())),
675 ));
676 }
677 None => {
678 return Err(eof_closing_err(&opening, self.module_id));
679 }
680 _ => {}
681 }
682
683 let key_token = match self.tokens.next() {
685 Some(t) => t,
686 None => return Err(eof_closing_err(&opening, self.module_id)),
687 };
688
689 let key_node = match &key_token.kind {
690 TokenKind::Ident(name) => Shared::new(Node {
691 token_id: self.token_arena.alloc(Shared::clone(key_token)),
692 expr: Shared::new(Expr::Literal(Literal::Symbol(Ident::new(name)))),
693 }),
694 TokenKind::StringLiteral(s) => Shared::new(Node {
695 token_id: self.token_arena.alloc(Shared::clone(key_token)),
696 expr: Shared::new(Expr::Literal(Literal::String(s.clone()))),
697 }),
698 _ => {
699 return Err(SyntaxError::UnexpectedToken((**key_token).clone()));
700 }
701 };
702
703 match self.tokens.next() {
705 Some(token) if token.kind == TokenKind::Colon => {}
706 Some(token) => return Err(SyntaxError::UnexpectedToken((**token).clone())),
707 None => return Err(eof_closing_err(&opening, self.module_id)),
708 }
709
710 let value_token = match self.tokens.next() {
712 Some(t) => t,
713 None => return Err(eof_closing_err(&opening, self.module_id)),
714 };
715 let value_node = self.parse_expr(value_token)?;
716
717 pairs.push(Shared::new(Node {
718 token_id,
719 expr: Shared::new(Expr::Call(
720 IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::clone(key_token))),
721 smallvec![key_node, value_node],
722 )),
723 }));
724
725 match self.tokens.peek() {
727 Some(token) if token.kind == TokenKind::Comma => {
728 self.tokens.next(); if let Some(next_token) = self.tokens.peek()
731 && next_token.kind == TokenKind::RBrace
732 {
733 self.tokens.next(); break;
735 }
736 }
737 Some(token) if token.kind == TokenKind::RBrace => {
738 self.tokens.next(); break;
740 }
741 Some(token) => {
742 return Err(SyntaxError::ExpectedClosingBrace(
743 (***token).clone(),
744 Some(Box::new(opening.clone())),
745 ));
746 }
747 None => return Err(eof_closing_err(&opening, self.module_id)),
748 }
749 }
750
751 Ok(Shared::new(Node {
752 token_id,
753 expr: Shared::new(Expr::Call(
754 IdentWithToken::new_with_token(constants::builtins::DICT, Some(Shared::clone(lbrace_token))),
755 pairs,
756 )),
757 }))
758 }
759
760 fn parse_env(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
761 match &token.kind {
762 TokenKind::Env(s) => Ok(Shared::new(Node {
763 token_id: self.token_arena.alloc(Shared::clone(token)),
764 expr: std::env::var(s)
765 .map_err(|_| SyntaxError::EnvNotFound((**token).clone(), SmolStr::new(s)))
766 .map(|s| Shared::new(Expr::Literal(Literal::String(s.to_owned()))))?,
767 })),
768 TokenKind::Eof => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
769 _ => Err(SyntaxError::UnexpectedToken((**token).clone())),
770 }
771 }
772
773 fn parse_attribute_access(
774 &mut self,
775 base_node: Shared<Node>,
776 token_id: TokenId,
777 ) -> Result<Shared<Node>, SyntaxError> {
778 let selector_token = match self.tokens.peek() {
779 Some(t) => Shared::clone(t),
780 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
781 };
782
783 if let TokenKind::Selector(selector) = &selector_token.kind
784 && selector.len() > 1
785 {
786 if !Selector::try_from(&*selector_token)
787 .map_err(SyntaxError::UnknownSelector)?
788 .is_attribute_selector()
789 {
790 return Err(SyntaxError::UnexpectedToken((*selector_token).clone()));
791 }
792
793 let attribute_name = &selector[1..]; let attr_literal_token_id = self.token_arena.alloc(Shared::clone(&selector_token));
795 let attr_literal = Shared::new(Node {
796 token_id: attr_literal_token_id,
797 expr: Shared::new(Expr::Literal(Literal::String(attribute_name.to_string()))),
798 });
799
800 self.tokens.next(); if self.is_next_token(|kind| matches!(kind, TokenKind::PipeEqual)) {
803 self.tokens.next(); return self.parse_set_attr_call_with_selector(base_node, attr_literal);
805 }
806
807 Ok(Shared::new(Node {
808 token_id: attr_literal_token_id,
809 expr: Shared::new(Expr::Call(
810 IdentWithToken::new_with_token(
811 constants::builtins::ATTR,
812 Some(Shared::clone(&self.token_arena[token_id])),
813 ),
814 smallvec![base_node, attr_literal],
815 )),
816 }))
817 } else {
818 Ok(base_node)
819 }
820 }
821
822 fn parse_self(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
823 let token_id = self.token_arena.alloc(Shared::clone(token));
824 let self_node = Shared::new(Node {
825 token_id,
826 expr: Shared::new(Expr::Self_),
827 });
828 let node = self.parse_attribute_access(self_node, token_id)?;
829
830 match self.tokens.peek().map(|t| &t.kind) {
831 Some(TokenKind::LBracket) => self.parse_bracket_access(node, token),
832 _ => Ok(node),
833 }
834 }
835
836 fn parse_break(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
837 let token_id = self.token_arena.alloc(Shared::clone(token));
838
839 let value = if self.tokens.peek().map(|t| &t.kind) == Some(&TokenKind::Colon) {
841 self.tokens.next(); let expr_token = self
843 .tokens
844 .next()
845 .ok_or(SyntaxError::UnexpectedEOFDetected(self.module_id))?;
846 Some(self.parse_expr(expr_token)?)
847 } else {
848 None
849 };
850
851 Ok(Shared::new(Node {
852 token_id,
853 expr: Shared::new(Expr::Break(value)),
854 }))
855 }
856
857 fn parse_continue(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
858 Ok(Shared::new(Node {
859 token_id: self.token_arena.alloc(Shared::clone(token)),
860 expr: Shared::new(Expr::Continue),
861 }))
862 }
863
864 fn parse_array(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
865 let opening = (**token).clone();
866 let token_id = self.token_arena.alloc(Shared::clone(token));
867 let mut elements: SmallVec<[Shared<Node>; 4]> = SmallVec::new();
868 let mut closed = false;
869
870 while let Some(elem_token) = self.tokens.next() {
871 match &elem_token.kind {
872 TokenKind::RBracket => {
873 closed = true;
874 break;
875 }
876 TokenKind::Eof => {
877 return Err(SyntaxError::ExpectedClosingBracket(
878 (**elem_token).clone(),
879 Some(Box::new(opening)),
880 ));
881 }
882 TokenKind::Comma => continue,
883 _ => {
884 let expr = self.parse_expr(elem_token)?;
885 elements.push(expr);
886 }
887 }
888 }
889
890 if !closed {
891 return Err(SyntaxError::ExpectedClosingBracket(
892 Token {
893 range: opening.range,
894 kind: TokenKind::Eof,
895 module_id: self.module_id,
896 },
897 Some(Box::new(opening)),
898 ));
899 }
900
901 let array_node = Shared::new(Node {
902 token_id,
903 expr: Shared::new(Expr::Call(
904 IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::clone(token))),
905 elements,
906 )),
907 });
908
909 self.parse_postfix_ops(array_node, token)
911 }
912
913 fn parse_all_nodes(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
914 Ok(Shared::new(Node {
915 token_id: self.token_arena.alloc(Shared::clone(token)),
916 expr: Shared::new(Expr::Nodes),
917 }))
918 }
919
920 fn is_binary_op(token_kind: &TokenKind) -> bool {
921 matches!(
922 token_kind,
923 TokenKind::And
924 | TokenKind::Asterisk
925 | TokenKind::Equal
926 | TokenKind::EqEq
927 | TokenKind::Coalesce
928 | TokenKind::Gte
929 | TokenKind::Gt
930 | TokenKind::Lte
931 | TokenKind::Lt
932 | TokenKind::Minus
933 | TokenKind::NeEq
934 | TokenKind::Or
935 | TokenKind::Percent
936 | TokenKind::Plus
937 | TokenKind::DoubleDot
938 | TokenKind::Slash
939 | TokenKind::PlusEqual
940 | TokenKind::MinusEqual
941 | TokenKind::SlashEqual
942 | TokenKind::PercentEqual
943 | TokenKind::DoubleSlashEqual
944 | TokenKind::StarEqual
945 | TokenKind::TildeEqual
946 | TokenKind::NotTildeEqual
947 | TokenKind::LeftShift
948 | TokenKind::RightShift
949 | TokenKind::Convert
950 )
951 }
952
953 fn is_next_token(&mut self, expected: impl Fn(&TokenKind) -> bool) -> bool {
954 self.tokens.peek().as_ref().map(|t| &t.kind).is_some_and(expected)
955 }
956
957 fn is_next_token_allowed(token_kind: Option<&TokenKind>) -> bool {
958 matches!(
959 token_kind,
960 Some(TokenKind::And)
961 | Some(TokenKind::As)
962 | Some(TokenKind::Asterisk)
963 | Some(TokenKind::Catch)
964 | Some(TokenKind::Colon)
965 | Some(TokenKind::Comma)
966 | Some(TokenKind::Eof)
967 | Some(TokenKind::Elif)
968 | Some(TokenKind::Else)
969 | Some(TokenKind::EqEq)
970 | Some(TokenKind::Equal)
971 | Some(TokenKind::Gte)
972 | Some(TokenKind::Gt)
973 | Some(TokenKind::Lte)
974 | Some(TokenKind::Lt)
975 | Some(TokenKind::Minus)
976 | Some(TokenKind::NeEq)
977 | Some(TokenKind::Or)
978 | Some(TokenKind::Percent)
979 | Some(TokenKind::Pipe)
980 | Some(TokenKind::Plus)
981 | Some(TokenKind::DoubleDot)
982 | Some(TokenKind::RBrace)
983 | Some(TokenKind::RBracket)
984 | Some(TokenKind::RParen)
985 | Some(TokenKind::SemiColon)
986 | Some(TokenKind::End)
987 | Some(TokenKind::Slash)
988 | Some(TokenKind::Coalesce)
989 | Some(TokenKind::PlusEqual)
990 | Some(TokenKind::MinusEqual)
991 | Some(TokenKind::SlashEqual)
992 | Some(TokenKind::StarEqual)
993 | Some(TokenKind::DoubleSlashEqual)
994 | Some(TokenKind::PercentEqual)
995 | Some(TokenKind::TildeEqual)
996 | Some(TokenKind::NotTildeEqual)
997 | Some(TokenKind::LeftShift)
998 | Some(TokenKind::RightShift)
999 | Some(TokenKind::Convert)
1000 | None
1001 )
1002 }
1003
1004 fn parse_literal(&mut self, literal_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1005 let literal_node = match &literal_token.kind {
1006 TokenKind::BoolLiteral(b) => Ok(Shared::new(Node {
1007 token_id: self.token_arena.alloc(Shared::clone(literal_token)),
1008 expr: Shared::new(Expr::Literal(Literal::Bool(*b))),
1009 })),
1010 TokenKind::StringLiteral(s) => Ok(Shared::new(Node {
1011 token_id: self.token_arena.alloc(Shared::clone(literal_token)),
1012 expr: Shared::new(Expr::Literal(Literal::String(s.to_owned()))),
1013 })),
1014 TokenKind::BytesLiteral(b) => Ok(Shared::new(Node {
1015 token_id: self.token_arena.alloc(Shared::clone(literal_token)),
1016 expr: Shared::new(Expr::Literal(Literal::Bytes(b.clone()))),
1017 })),
1018 TokenKind::NumberLiteral(n) => Ok(Shared::new(Node {
1019 token_id: self.token_arena.alloc(Shared::clone(literal_token)),
1020 expr: Shared::new(Expr::Literal(Literal::Number(*n))),
1021 })),
1022 TokenKind::None => Ok(Shared::new(Node {
1023 token_id: self.token_arena.alloc(Shared::clone(literal_token)),
1024 expr: Shared::new(Expr::Literal(Literal::None)),
1025 })),
1026 TokenKind::Eof => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1027 _ => Err(SyntaxError::UnexpectedToken((**literal_token).clone())),
1028 }?;
1029
1030 let token = self.tokens.peek();
1031
1032 if Self::is_next_token_allowed(token.as_ref().map(|t| &t.kind)) {
1033 Ok(literal_node)
1034 } else {
1035 Err(SyntaxError::UnexpectedToken((***token.unwrap()).clone()))
1036 }
1037 }
1038
1039 fn parse_ident(&mut self, ident: &str, ident_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1040 match self.tokens.peek().map(|t| &t.kind) {
1041 Some(TokenKind::Selector(selector)) if selector.len() > 1 => {
1042 let token_id = self.token_arena.alloc(Shared::clone(ident_token));
1043 let base_node = Shared::new(Node {
1044 token_id,
1045 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token(
1046 ident,
1047 Some(Shared::clone(ident_token)),
1048 ))),
1049 });
1050
1051 self.parse_attribute_access(base_node, token_id)
1052 }
1053 Some(TokenKind::DoubleColon) => {
1054 let mut module_path = vec![IdentWithToken::new_with_token(ident, Some(Shared::clone(ident_token)))];
1057
1058 while matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::DoubleColon)) {
1060 self.tokens.next(); let next_token = self
1063 .tokens
1064 .next()
1065 .ok_or(SyntaxError::UnexpectedEOFDetected(self.module_id))?;
1066
1067 let next_ident = match &next_token.kind {
1068 TokenKind::Ident(name) => name.clone(),
1069 _ => return Err(SyntaxError::UnexpectedToken((**next_token).clone())),
1070 };
1071
1072 match self.tokens.peek().map(|t| &t.kind) {
1074 Some(TokenKind::DoubleColon) => {
1075 module_path.push(IdentWithToken::new_with_token(
1077 &next_ident,
1078 Some(Shared::clone(next_token)),
1079 ));
1080 }
1081 Some(TokenKind::LParen) => {
1082 let args = self.parse_args()?;
1084 let access_target = AccessTarget::Call(
1085 IdentWithToken::new_with_token(&next_ident, Some(Shared::clone(next_token))),
1086 args,
1087 );
1088
1089 let token_id = self.token_arena.alloc(Shared::clone(ident_token));
1090 let qualified_node = Shared::new(Node {
1091 token_id,
1092 expr: Shared::new(Expr::QualifiedAccess(module_path, access_target)),
1093 });
1094 if matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::LBracket)) {
1096 return self.parse_bracket_access(qualified_node, ident_token);
1097 }
1098 return Ok(qualified_node);
1099 }
1100 _ => {
1101 let access_target = AccessTarget::Ident(IdentWithToken::new_with_token(
1103 &next_ident,
1104 Some(Shared::clone(next_token)),
1105 ));
1106
1107 let token_id = self.token_arena.alloc(Shared::clone(ident_token));
1108 return Ok(Shared::new(Node {
1109 token_id,
1110 expr: Shared::new(Expr::QualifiedAccess(module_path, access_target)),
1111 }));
1112 }
1113 }
1114 }
1115
1116 Err(SyntaxError::UnexpectedToken((**ident_token).clone()))
1118 }
1119 Some(TokenKind::LParen) => {
1120 let mut args = self.parse_args()?;
1121 let token_id = self.token_arena.alloc(Shared::clone(ident_token));
1122
1123 if matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::Do)) {
1125 let do_token = self.tokens.next().unwrap(); let block = self.parse_block(do_token)?;
1127 args.push(block);
1128
1129 return Ok(Shared::new(Node {
1130 token_id: self.token_arena.alloc(Shared::clone(ident_token)),
1131 expr: Shared::new(Expr::Call(
1132 IdentWithToken::new_with_token(ident, Some(Shared::clone(ident_token))),
1133 args,
1134 )),
1135 }));
1136 }
1137
1138 let call_node = Shared::new(Node {
1139 token_id,
1140 expr: Shared::new(Expr::Call(
1141 IdentWithToken::new_with_token(ident, Some(Shared::clone(ident_token))),
1142 args,
1143 )),
1144 });
1145
1146 if self.is_next_token(|token_kind| matches!(token_kind, TokenKind::Question)) {
1147 let question_token = self.tokens.next().unwrap();
1148 let question_token_id = self.token_arena.alloc(Shared::clone(question_token));
1149
1150 return Ok(Shared::new(Node {
1151 token_id: question_token_id,
1152 expr: Shared::new(Expr::Try(
1153 call_node,
1154 Shared::new(Node {
1155 token_id,
1156 expr: Shared::new(Expr::Literal(Literal::None)),
1157 }),
1158 )),
1159 }));
1160 }
1161
1162 if matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::LBracket)) {
1164 let result = self.parse_bracket_access(call_node, ident_token)?;
1165 self.parse_postfix_ops(result, ident_token)
1166 } else if matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::Selector(_))) {
1167 self.parse_attribute_access(call_node, token_id)
1168 } else if Self::is_next_token_allowed(self.tokens.peek().map(|t| &t.kind)) {
1169 Ok(call_node)
1170 } else {
1171 Err(SyntaxError::UnexpectedToken((***self.tokens.peek().unwrap()).clone()))
1172 }
1173 }
1174 Some(TokenKind::LBracket) => {
1175 let ident_node = Shared::new(Node {
1176 token_id: self.token_arena.alloc(Shared::clone(ident_token)),
1177 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token(
1178 ident,
1179 Some(Shared::clone(ident_token)),
1180 ))),
1181 });
1182
1183 let result = self.parse_bracket_access(ident_node, ident_token)?;
1184 self.parse_postfix_ops(result, ident_token)
1185 }
1186 token if Self::is_next_token_allowed(token) => Ok(Shared::new(Node {
1187 token_id: self.token_arena.alloc(Shared::clone(ident_token)),
1188 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token(
1189 ident,
1190 Some(Shared::clone(ident_token)),
1191 ))),
1192 })),
1193 _ => Err(SyntaxError::UnexpectedToken((**ident_token).clone())),
1194 }
1195 }
1196
1197 fn parse_bracket_access(
1199 &mut self,
1200 target_node: Shared<Node>,
1201 original_token: &Shared<Token>,
1202 ) -> Result<Shared<Node>, SyntaxError> {
1203 let lbracket = self.tokens.next().map(|t| (**t).clone()); let is_slice_from_start = matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::Colon))
1208 && !matches!(
1209 self.tokens.clone().nth(1).map(|t| &t.kind),
1210 Some(TokenKind::Ident(_)) | Some(TokenKind::StringLiteral(_))
1211 );
1212
1213 if is_slice_from_start {
1214 let _ = self.tokens.next(); let start_node = Shared::new(Node {
1216 token_id: self.token_arena.alloc(Shared::clone(original_token)),
1217 expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
1218 });
1219
1220 let result_node = match self.tokens.next() {
1221 Some(t) if t.kind == TokenKind::RBracket => {
1222 Shared::new(Node {
1224 token_id: self.token_arena.alloc(Shared::clone(original_token)),
1225 expr: Shared::new(Expr::Call(
1226 IdentWithToken::new_with_token(
1227 constants::builtins::SLICE,
1228 Some(Shared::clone(original_token)),
1229 ),
1230 smallvec![
1231 Shared::clone(&target_node),
1232 start_node,
1233 Shared::new(Node {
1234 token_id: self.token_arena.alloc(Shared::clone(original_token)),
1235 expr: Shared::new(Expr::Call(
1236 IdentWithToken::new_with_token(constants::builtins::LEN, None,),
1237 smallvec![target_node],
1238 )),
1239 })
1240 ],
1241 )),
1242 })
1243 }
1244 Some(t) => {
1245 let end_node = self.parse_expr(t)?;
1246 match self.tokens.peek() {
1247 Some(token) if matches!(token.kind, TokenKind::RBracket) => {
1248 let _ = self.tokens.next();
1249 }
1250 Some(token) => {
1251 return Err(SyntaxError::ExpectedClosingBracket(
1252 (***token).clone(),
1253 lbracket.clone().map(Box::new),
1254 ));
1255 }
1256 None => {
1257 return Err(SyntaxError::ExpectedClosingBracket(
1258 Token {
1259 range: original_token.range,
1260 kind: TokenKind::Eof,
1261 module_id: self.module_id,
1262 },
1263 lbracket.clone().map(Box::new),
1264 ));
1265 }
1266 }
1267 Shared::new(Node {
1268 token_id: self.token_arena.alloc(Shared::clone(original_token)),
1269 expr: Shared::new(Expr::Call(
1270 IdentWithToken::new_with_token(
1271 constants::builtins::SLICE,
1272 Some(Shared::clone(original_token)),
1273 ),
1274 smallvec![target_node, start_node, end_node],
1275 )),
1276 })
1277 }
1278 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1279 };
1280
1281 let final_result = if matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::LBracket)) {
1282 self.parse_bracket_access(result_node, original_token)?
1283 } else {
1284 result_node
1285 };
1286 return Ok(final_result);
1287 }
1288
1289 let first_token = match self.tokens.next() {
1291 Some(t) => t,
1292 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1293 };
1294
1295 let first_node = self.parse_expr(first_token)?;
1296
1297 let is_slice = matches!(self.tokens.peek(), Some(token) if matches!(token.kind, TokenKind::Colon));
1299
1300 let result_node = if is_slice {
1301 let _ = self.tokens.next();
1303
1304 match self.tokens.next() {
1305 Some(t) if t.kind == TokenKind::RBracket => Shared::new(Node {
1306 token_id: self.token_arena.alloc(Shared::clone(original_token)),
1307 expr: Shared::new(Expr::Call(
1308 IdentWithToken::new_with_token(constants::builtins::SLICE, Some(Shared::clone(original_token))),
1309 smallvec![
1310 Shared::clone(&target_node),
1311 first_node,
1312 Shared::new(Node {
1313 token_id: self.token_arena.alloc(Shared::clone(original_token)),
1314 expr: Shared::new(Expr::Call(
1315 IdentWithToken::new_with_token(constants::builtins::LEN, None),
1316 smallvec![target_node],
1317 )),
1318 })
1319 ],
1320 )),
1321 }),
1322 Some(t) => {
1323 let second_node = self.parse_expr(t)?;
1324
1325 match self.tokens.peek() {
1327 Some(token) if matches!(token.kind, TokenKind::RBracket) => {
1328 let _ = self.tokens.next(); }
1330 Some(token) => {
1331 return Err(SyntaxError::ExpectedClosingBracket(
1332 (***token).clone(),
1333 lbracket.clone().map(Box::new),
1334 ));
1335 }
1336 None => {
1337 return Err(SyntaxError::ExpectedClosingBracket(
1338 Token {
1339 range: original_token.range,
1340 kind: TokenKind::Eof,
1341 module_id: self.module_id,
1342 },
1343 lbracket.clone().map(Box::new),
1344 ));
1345 }
1346 }
1347
1348 Shared::new(Node {
1349 token_id: self.token_arena.alloc(Shared::clone(original_token)),
1350 expr: Shared::new(Expr::Call(
1351 IdentWithToken::new_with_token(
1352 constants::builtins::SLICE,
1353 Some(Shared::clone(original_token)),
1354 ),
1355 smallvec![target_node, first_node, second_node],
1356 )),
1357 })
1358 }
1359 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1360 }
1361 } else {
1362 match self.tokens.peek() {
1364 Some(token) if matches!(token.kind, TokenKind::RBracket) => {
1365 let _ = self.tokens.next(); }
1367 Some(token) => {
1368 return Err(SyntaxError::ExpectedClosingBracket(
1369 (***token).clone(),
1370 lbracket.clone().map(Box::new),
1371 ));
1372 }
1373 None => {
1374 return Err(SyntaxError::ExpectedClosingBracket(
1375 Token {
1376 range: original_token.range,
1377 kind: TokenKind::Eof,
1378 module_id: self.module_id,
1379 },
1380 lbracket.map(Box::new),
1381 ));
1382 }
1383 }
1384
1385 Shared::new(Node {
1386 token_id: self.token_arena.alloc(Shared::clone(original_token)),
1387 expr: Shared::new(Expr::Call(
1388 IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::clone(original_token))),
1389 smallvec![target_node, first_node],
1390 )),
1391 })
1392 };
1393
1394 let final_result = if matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::LBracket)) {
1396 self.parse_bracket_access(result_node, original_token)?
1397 } else {
1398 result_node
1399 };
1400
1401 if matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::LParen)) {
1404 let args = self.parse_args()?;
1405 let call_dynamic = Shared::new(Node {
1406 token_id: self.token_arena.alloc(Shared::clone(original_token)),
1407 expr: Shared::new(Expr::CallDynamic(final_result, args)),
1408 });
1409 self.parse_postfix_ops(call_dynamic, original_token)
1410 } else {
1411 Ok(final_result)
1412 }
1413 }
1414
1415 fn parse_postfix_ops(
1418 &mut self,
1419 mut current: Shared<Node>,
1420 original_token: &Shared<Token>,
1421 ) -> Result<Shared<Node>, SyntaxError> {
1422 loop {
1423 if matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::LParen)) {
1424 let args = self.parse_args()?;
1425 current = Shared::new(Node {
1426 token_id: self.token_arena.alloc(Shared::clone(original_token)),
1427 expr: Shared::new(Expr::CallDynamic(current, args)),
1428 });
1429 } else if matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::LBracket)) {
1430 current = self.parse_bracket_access(current, original_token)?;
1431 } else {
1432 break;
1433 }
1434 }
1435 Ok(current)
1436 }
1437
1438 fn parse_def(&mut self, def_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1439 let ident_token = self.tokens.next();
1440 let ident = match &ident_token {
1441 Some(token) => match &token.kind {
1442 TokenKind::Ident(ident) => Ok(ident),
1443 _ => Err(SyntaxError::UnexpectedToken((***token).clone())),
1444 },
1445 None => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1446 }?;
1447 let def_token_id = self.token_arena.alloc(Shared::clone(def_token));
1448 let params = if self.is_next_token(|token| matches!(token, TokenKind::Colon | TokenKind::Do)) {
1449 SmallVec::new()
1450 } else {
1451 self.parse_params()?
1452 };
1453
1454 self.consume_colon_or_do();
1455
1456 let program = self.parse_program(false)?;
1457
1458 Ok(Shared::new(Node {
1459 token_id: def_token_id,
1460 expr: Shared::new(Expr::Def(
1461 IdentWithToken::new_with_token(ident, ident_token.map(Shared::clone)),
1462 params,
1463 program,
1464 )),
1465 }))
1466 }
1467
1468 fn parse_macro(&mut self, macro_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1469 let ident_token = self.tokens.next();
1470 let ident = match &ident_token {
1471 Some(token) => match &token.kind {
1472 TokenKind::Ident(ident) => Ok(ident),
1473 _ => Err(SyntaxError::UnexpectedToken((***token).clone())),
1474 },
1475 None => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1476 }?;
1477 let macro_token_id = self.token_arena.alloc(Shared::clone(macro_token));
1478 let params = self.parse_params()?;
1479
1480 if params.iter().any(|p| p.default.is_some()) {
1482 return Err(SyntaxError::MacroParametersCannotHaveDefaults(
1483 (*self.token_arena[macro_token_id]).clone(),
1484 ));
1485 }
1486
1487 if params.iter().any(|p| p.is_variadic) {
1489 return Err(SyntaxError::MacroParametersCannotBeVariadic(
1490 (*self.token_arena[macro_token_id]).clone(),
1491 ));
1492 }
1493
1494 self.consume_colon();
1495
1496 let expr = match self.tokens.next() {
1497 Some(token) => self.parse_expr(token)?,
1498 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1499 };
1500
1501 Ok(Shared::new(Node {
1502 token_id: macro_token_id,
1503 expr: Shared::new(Expr::Macro(
1504 IdentWithToken::new_with_token(ident, ident_token.map(Shared::clone)),
1505 params,
1506 expr,
1507 )),
1508 }))
1509 }
1510
1511 fn parse_block(&mut self, do_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1512 let do_token_id = self.token_arena.alloc(Shared::clone(do_token));
1513 let program = self.parse_program(false)?;
1514
1515 Ok(Shared::new(Node {
1519 token_id: do_token_id,
1520 expr: Shared::new(Expr::Block(program)),
1521 }))
1522 }
1523
1524 fn parse_fn(&mut self, fn_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1525 let fn_token_id = self.token_arena.alloc(Shared::clone(fn_token));
1526 let params = self.parse_params()?;
1527
1528 self.consume_colon_or_do();
1529
1530 let program = self.parse_program(false)?;
1531
1532 let fn_node = Shared::new(Node {
1533 token_id: fn_token_id,
1534 expr: Shared::new(Expr::Fn(params, program)),
1535 });
1536
1537 self.parse_postfix_ops(fn_node, fn_token)
1539 }
1540
1541 fn parse_while(&mut self, while_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1542 let token_id = self.token_arena.alloc(Shared::clone(while_token));
1543 let args = self.parse_args()?;
1544
1545 if args.len() != 1 {
1546 return Err(SyntaxError::UnexpectedToken((**while_token).clone()));
1547 }
1548
1549 self.consume_colon_or_do();
1550
1551 match self.tokens.peek() {
1552 Some(_) => {
1553 let cond = args.first().unwrap();
1554 let body_program = self.parse_program(false)?;
1555
1556 Ok(Shared::new(Node {
1557 token_id,
1558 expr: Shared::new(Expr::While(
1559 Shared::clone(cond),
1560 body_program.iter().map(Shared::clone).collect(),
1561 )),
1562 }))
1563 }
1564 None => Err(SyntaxError::UnexpectedToken((**while_token).clone())),
1565 }
1566 }
1567
1568 fn parse_loop(&mut self, loop_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1569 let token_id = self.token_arena.alloc(Shared::clone(loop_token));
1570
1571 self.consume_colon_or_do();
1572
1573 match self.tokens.peek() {
1574 Some(_) => {
1575 let body_program = self.parse_program(false)?;
1576
1577 Ok(Shared::new(Node {
1578 token_id,
1579 expr: Shared::new(Expr::Loop(body_program.iter().map(Shared::clone).collect())),
1580 }))
1581 }
1582 None => Err(SyntaxError::UnexpectedToken((**loop_token).clone())),
1583 }
1584 }
1585
1586 fn parse_try(&mut self, try_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1587 let token_id = self.token_arena.alloc(Shared::clone(try_token));
1588
1589 self.consume_colon_or_do();
1590
1591 let try_expr = match self.tokens.next() {
1593 Some(token) => self.parse_expr(token)?,
1594 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1595 };
1596
1597 if !self.is_next_token(|token_kind| matches!(token_kind, TokenKind::Catch)) {
1598 return Ok(Shared::new(Node {
1599 token_id,
1600 expr: Shared::new(Expr::Try(
1601 try_expr,
1602 Shared::new(Node {
1603 token_id,
1604 expr: Shared::new(Expr::Literal(Literal::None)),
1605 }),
1606 )),
1607 }));
1608 }
1609
1610 self.next_token(|token_kind| matches!(token_kind, TokenKind::Catch))?;
1612 self.consume_colon_or_do();
1613
1614 let catch_expr = match self.tokens.next() {
1616 Some(token) => self.parse_expr(token)?,
1617 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1618 };
1619
1620 Ok(Shared::new(Node {
1621 token_id,
1622 expr: Shared::new(Expr::Try(try_expr, catch_expr)),
1623 }))
1624 }
1625
1626 fn parse_quote(&mut self, quote_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1627 let token_id = self.token_arena.alloc(Shared::clone(quote_token));
1628
1629 self.consume_colon();
1630
1631 let expr = match self.tokens.next() {
1632 Some(token) => self.parse_expr(token)?,
1633 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1634 };
1635
1636 Ok(Shared::new(Node {
1637 token_id,
1638 expr: Shared::new(Expr::Quote(expr)),
1639 }))
1640 }
1641
1642 fn parse_unquote(&mut self, unquote_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1643 let token_id = self.token_arena.alloc(Shared::clone(unquote_token));
1644
1645 let args = self.parse_args()?;
1646
1647 if args.len() != 1 {
1648 return Err(SyntaxError::UnexpectedToken((*self.token_arena[token_id]).clone()));
1649 }
1650
1651 let expr = Shared::clone(args.first().unwrap());
1652
1653 Ok(Shared::new(Node {
1654 token_id,
1655 expr: Shared::new(Expr::Unquote(expr)),
1656 }))
1657 }
1658
1659 fn parse_foreach(&mut self, foreach_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1660 let args = self.parse_args()?;
1661
1662 if args.len() != 2 {
1663 return Err(SyntaxError::UnexpectedToken((**foreach_token).clone()));
1664 }
1665
1666 let first_arg = &*args.first().unwrap().expr;
1667
1668 match first_arg {
1669 Expr::Ident(IdentWithToken {
1670 name: ident,
1671 token: ident_token,
1672 }) => {
1673 self.consume_colon_or_do();
1674
1675 let each_values = Shared::clone(&args[1]);
1676 let body_program = self.parse_program(false)?;
1677
1678 Ok(Shared::new(Node {
1679 token_id: self.token_arena.alloc(Shared::clone(foreach_token)),
1680 expr: Shared::new(Expr::Foreach(
1681 IdentWithToken {
1682 name: *ident,
1683 token: ident_token.clone(),
1684 },
1685 Shared::clone(&each_values),
1686 body_program.iter().map(Shared::clone).collect(),
1687 )),
1688 }))
1689 }
1690 _ => Err(SyntaxError::UnexpectedToken((**foreach_token).clone())),
1691 }
1692 }
1693
1694 fn parse_if(&mut self, if_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1695 let token_id = self.token_arena.alloc(Shared::clone(if_token));
1696 let args = self.parse_args()?;
1697
1698 if args.len() != 1 {
1699 return Err(SyntaxError::UnexpectedToken((*self.token_arena[token_id]).clone()));
1700 }
1701 let cond = args.first().unwrap();
1702
1703 self.consume_colon();
1704
1705 let then_expr = self.parse_next_expr(token_id)?;
1706
1707 let mut branches: Branches = SmallVec::new();
1708 branches.push((Some(Shared::clone(cond)), then_expr));
1709
1710 let elif_branches = self.parse_elif()?;
1711 branches.extend(elif_branches);
1712
1713 if let Some(token) = self.tokens.peek()
1714 && matches!(token.kind, TokenKind::Else)
1715 {
1716 let token_id = self.next_token(|token_kind| matches!(token_kind, TokenKind::Else))?;
1717
1718 self.consume_colon();
1719
1720 let else_expr = self.parse_next_expr(token_id)?;
1721 branches.push((None, else_expr));
1722 }
1723
1724 Ok(Shared::new(Node {
1725 token_id: self.token_arena.alloc(Shared::clone(if_token)),
1726 expr: Shared::new(Expr::If(branches)),
1727 }))
1728 }
1729
1730 fn parse_match(&mut self, match_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1731 let token_id = self.token_arena.alloc(Shared::clone(match_token));
1732
1733 let args = self.parse_args()?;
1735 if args.len() != 1 {
1736 return Err(SyntaxError::UnexpectedToken((*self.token_arena[token_id]).clone()));
1737 }
1738 let value = Shared::clone(args.first().unwrap());
1739
1740 self.consume_colon_or_do();
1741
1742 let mut arms: super::node::MatchArms = SmallVec::new();
1744
1745 while let Some(token) = self.tokens.peek() {
1746 if matches!(token.kind, TokenKind::End | TokenKind::Eof) {
1748 break;
1749 }
1750
1751 let token_id = self.next_token(|token_kind| matches!(token_kind, TokenKind::Pipe))?;
1753 let pattern = self.parse_pattern()?;
1755 let guard = if let Some(token) = self.tokens.peek() {
1757 if matches!(token.kind, TokenKind::If) {
1758 let if_token = Shared::clone(token);
1759 self.tokens.next(); let guard_args = self.parse_args()?;
1761 if guard_args.len() != 1 {
1762 return Err(SyntaxError::UnexpectedToken((*if_token).clone()));
1763 }
1764 Some(Shared::clone(guard_args.first().unwrap()))
1765 } else {
1766 None
1767 }
1768 } else {
1769 None
1770 };
1771
1772 self.consume_colon();
1773
1774 let body = self.parse_next_expr(token_id)?;
1776
1777 arms.push(MatchArm { pattern, guard, body });
1778 }
1779
1780 if let Some(token) = self.tokens.peek()
1782 && matches!(token.kind, TokenKind::End)
1783 {
1784 self.tokens.next();
1785 }
1786
1787 Ok(Shared::new(Node {
1788 token_id,
1789 expr: Shared::new(Expr::Match(value, arms)),
1790 }))
1791 }
1792
1793 fn parse_pattern(&mut self) -> Result<Pattern, SyntaxError> {
1794 let first = self.parse_single_pattern()?;
1795 if !matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::Or)) {
1796 return Ok(first);
1797 }
1798 let mut patterns = vec![first];
1799 while matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::Or)) {
1800 self.tokens.next(); patterns.push(self.parse_single_pattern()?);
1802 }
1803 Ok(Pattern::Or(patterns))
1804 }
1805
1806 fn parse_single_pattern(&mut self) -> Result<Pattern, SyntaxError> {
1807 let token = match self.tokens.next() {
1808 Some(t) => t,
1809 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1810 };
1811
1812 match &token.kind {
1813 TokenKind::Ident(name) if name == constants::identifiers::PATTERN_MATCH_WILDCARD => Ok(Pattern::Wildcard),
1815 TokenKind::Colon => {
1817 let type_token = match self.tokens.next() {
1818 Some(t) => t,
1819 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1820 };
1821 match &type_token.kind {
1822 TokenKind::Ident(type_name) => Ok(Pattern::Type(Ident::new(type_name))),
1823 _ => Err(SyntaxError::UnexpectedToken((**type_token).clone())),
1824 }
1825 }
1826 TokenKind::StringLiteral(s) => Ok(Pattern::Literal(Literal::String(s.clone()))),
1828 TokenKind::BytesLiteral(b) => Ok(Pattern::Literal(Literal::Bytes(b.clone()))),
1829 TokenKind::NumberLiteral(n) => Ok(Pattern::Literal(Literal::Number(*n))),
1830 TokenKind::BoolLiteral(b) => Ok(Pattern::Literal(Literal::Bool(*b))),
1831 TokenKind::None => Ok(Pattern::Literal(Literal::None)),
1832 TokenKind::LBracket => self.parse_array_pattern(),
1834 TokenKind::LBrace => self.parse_dict_pattern(),
1836 TokenKind::Ident(name) => Ok(Pattern::Ident(IdentWithToken::new(name))),
1838 _ => Err(SyntaxError::UnexpectedToken((**token).clone())),
1839 }
1840 }
1841
1842 fn parse_array_pattern(&mut self) -> Result<super::node::Pattern, SyntaxError> {
1843 let mut patterns = Vec::new();
1844 let mut has_rest = false;
1845 let mut rest_binding: Option<IdentWithToken> = None;
1846
1847 loop {
1848 if let Some(token) = self.tokens.peek() {
1850 if matches!(token.kind, TokenKind::RBracket) {
1851 self.tokens.next(); break;
1853 }
1854
1855 if matches!(token.kind, TokenKind::DoubleDot) {
1857 self.tokens.next();
1858 if let Some(ident_token) = self.tokens.next() {
1859 if let TokenKind::Ident(name) = &ident_token.kind {
1860 rest_binding = Some(IdentWithToken::new(name));
1861 has_rest = true;
1862 } else {
1863 return Err(SyntaxError::UnexpectedToken((**ident_token).clone()));
1864 }
1865 }
1866 if let Some(token) = self.tokens.next()
1868 && !matches!(token.kind, TokenKind::RBracket)
1869 {
1870 return Err(SyntaxError::UnexpectedToken((**token).clone()));
1871 }
1872 break;
1873 }
1874 }
1875
1876 let pattern = self.parse_pattern()?;
1877 patterns.push(pattern);
1878
1879 if let Some(token) = self.tokens.peek() {
1881 if matches!(token.kind, TokenKind::Comma) {
1882 self.tokens.next(); } else if matches!(token.kind, TokenKind::RBracket) {
1884 continue;
1886 } else {
1887 return Err(SyntaxError::UnexpectedToken((***token).clone()));
1888 }
1889 }
1890 }
1891
1892 if has_rest {
1893 Ok(Pattern::ArrayRest(patterns, rest_binding.unwrap()))
1894 } else {
1895 Ok(Pattern::Array(patterns))
1896 }
1897 }
1898
1899 fn parse_dict_pattern(&mut self) -> Result<super::node::Pattern, SyntaxError> {
1900 let mut fields = Vec::new();
1901
1902 loop {
1903 if let Some(token) = self.tokens.peek()
1905 && matches!(token.kind, TokenKind::RBrace)
1906 {
1907 self.tokens.next(); break;
1909 }
1910
1911 let key_token = match self.tokens.next() {
1913 Some(t) => t,
1914 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1915 };
1916
1917 let key = match &key_token.kind {
1918 TokenKind::Ident(name) => IdentWithToken::new(name),
1919 _ => return Err(SyntaxError::UnexpectedToken((**key_token).clone())),
1920 };
1921
1922 let pattern = if let Some(token) = self.tokens.peek() {
1924 if matches!(token.kind, TokenKind::Colon) {
1925 self.tokens.next(); self.parse_pattern()?
1927 } else {
1928 super::node::Pattern::Ident(key.clone())
1930 }
1931 } else {
1932 super::node::Pattern::Ident(key.clone())
1933 };
1934
1935 fields.push((key, pattern));
1936
1937 if let Some(token) = self.tokens.peek() {
1939 if matches!(token.kind, TokenKind::Comma) {
1940 self.tokens.next(); } else if matches!(token.kind, TokenKind::RBrace) {
1942 continue;
1944 } else {
1945 return Err(SyntaxError::UnexpectedToken((***token).clone()));
1946 }
1947 }
1948 }
1949
1950 Ok(super::node::Pattern::Dict(fields))
1951 }
1952
1953 #[inline(always)]
1954 fn parse_next_expr(&mut self, token_id: TokenId) -> Result<Shared<Node>, SyntaxError> {
1955 let expr_token = match self.tokens.next() {
1956 Some(token) => Ok(token),
1957 None => Err(SyntaxError::UnexpectedToken((*self.token_arena[token_id]).clone())),
1958 }?;
1959
1960 self.parse_expr(expr_token)
1961 }
1962
1963 fn parse_elif(&mut self) -> Result<Vec<IfExpr>, SyntaxError> {
1964 let mut nodes = Vec::with_capacity(8);
1965
1966 while let Some(token) = self.tokens.peek() {
1967 if !matches!(token.kind, TokenKind::Elif) {
1968 break;
1969 }
1970
1971 let token_id = self.next_token(|token_kind| matches!(token_kind, TokenKind::Elif))?;
1972 let args = self.parse_args()?;
1973
1974 if args.len() != 1 {
1975 return Err(SyntaxError::UnexpectedToken((*self.token_arena[token_id]).clone()));
1976 }
1977
1978 self.consume_colon();
1979
1980 let expr_token = match self.tokens.next() {
1981 Some(token) => Ok(token),
1982 None => Err(SyntaxError::UnexpectedToken((*self.token_arena[token_id]).clone())),
1983 }?;
1984
1985 let cond = args.first().unwrap();
1986 let then_expr = self.parse_expr(expr_token)?;
1987
1988 nodes.push((Some(Shared::clone(cond)), then_expr));
1989 }
1990
1991 Ok(nodes)
1992 }
1993
1994 fn parse_let_or_var_pattern(&mut self) -> Result<Pattern, SyntaxError> {
1995 let token_kind = match self.tokens.peek() {
1997 Some(t) => t.kind.clone(),
1998 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1999 };
2000 match token_kind {
2001 TokenKind::LBracket => {
2002 self.tokens.next(); self.parse_array_pattern()
2004 }
2005 TokenKind::LBrace => {
2006 self.tokens.next(); self.parse_dict_pattern()
2008 }
2009 TokenKind::Ident(ref name) => {
2010 let ident_token = self.tokens.next().unwrap();
2011 Ok(Pattern::Ident(IdentWithToken::new_with_token(
2012 name,
2013 Some(Shared::clone(ident_token)),
2014 )))
2015 }
2016 _ => {
2017 let bad_token = self.tokens.next().unwrap();
2018 Err(SyntaxError::UnexpectedToken((**bad_token).clone()))
2019 }
2020 }
2021 }
2022
2023 fn parse_let(&mut self, let_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2024 let let_token_id = self.token_arena.alloc(Shared::clone(let_token));
2025 let pattern = self.parse_let_or_var_pattern()?;
2026
2027 self.next_token(|token_kind| matches!(token_kind, TokenKind::Equal))?;
2028 let expr_token = match self.tokens.next() {
2029 Some(token) => Ok(token),
2030 None => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2031 }?;
2032
2033 if matches!(expr_token.kind, TokenKind::Let | TokenKind::Var) {
2034 return Err(SyntaxError::UnexpectedToken((**expr_token).clone()));
2035 }
2036
2037 let ast = self.parse_expr(expr_token)?;
2038
2039 if let Some(token) = self.tokens.peek()
2040 && !matches!(
2041 token.kind,
2042 TokenKind::Pipe | TokenKind::Eof | TokenKind::SemiColon | TokenKind::End
2043 )
2044 {
2045 return Err(SyntaxError::UnexpectedToken((***token).clone()));
2046 }
2047
2048 Ok(Shared::new(Node {
2049 token_id: let_token_id,
2050 expr: Shared::new(Expr::Let(pattern, ast)),
2051 }))
2052 }
2053
2054 fn parse_var(&mut self, var_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2055 let var_token_id = self.token_arena.alloc(Shared::clone(var_token));
2056 let pattern = self.parse_let_or_var_pattern()?;
2057
2058 self.next_token(|token_kind| matches!(token_kind, TokenKind::Equal))?;
2059 let expr_token = match self.tokens.next() {
2060 Some(token) => Ok(token),
2061 None => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2062 }?;
2063
2064 if matches!(expr_token.kind, TokenKind::Let | TokenKind::Var) {
2065 return Err(SyntaxError::UnexpectedToken((**expr_token).clone()));
2066 }
2067
2068 let ast = self.parse_expr(expr_token)?;
2069
2070 if let Some(token) = self.tokens.peek()
2071 && !matches!(
2072 token.kind,
2073 TokenKind::Pipe | TokenKind::Eof | TokenKind::SemiColon | TokenKind::End
2074 )
2075 {
2076 return Err(SyntaxError::UnexpectedToken((***token).clone()));
2077 }
2078
2079 Ok(Shared::new(Node {
2080 token_id: var_token_id,
2081 expr: Shared::new(Expr::Var(pattern, ast)),
2082 }))
2083 }
2084
2085 #[inline(always)]
2086 fn parse_include(&mut self, include_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2087 match self.tokens.peek() {
2088 Some(token) => match &token.kind {
2089 TokenKind::StringLiteral(module) => {
2090 self.tokens.next();
2091 Ok(Shared::new(Node {
2092 token_id: self.token_arena.alloc(Shared::clone(include_token)),
2093 expr: Shared::new(Expr::Include(Literal::String(module.to_owned()))),
2094 }))
2095 }
2096 _ => Err(SyntaxError::InsufficientTokens((***token).clone())),
2097 },
2098 None => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2099 }
2100 }
2101
2102 #[inline(always)]
2103 fn parse_import(&mut self, import_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2104 let token_id = self.token_arena.alloc(Shared::clone(import_token));
2105 let token = match self.tokens.next() {
2106 Some(token) => Ok(Shared::clone(token)),
2107 None => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2108 }?;
2109
2110 match &token.kind {
2111 TokenKind::StringLiteral(module) => {
2112 let module_name = module.to_owned();
2113 Ok(Shared::new(Node {
2114 token_id,
2115 expr: Shared::new(Expr::Import(Literal::String(module_name))),
2116 }))
2117 }
2118 _ => Err(SyntaxError::InsufficientTokens((*token).clone())),
2119 }
2120 }
2121
2122 fn parse_interpolated_string(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2123 if let TokenKind::InterpolatedString(segments) = &token.kind {
2124 let mut parsed_segments = Vec::new();
2125
2126 for segment in segments {
2127 match segment {
2128 lexer::token::StringSegment::Text(text, _) => {
2129 parsed_segments.push(super::node::StringSegment::Text(text.clone()));
2130 }
2131 lexer::token::StringSegment::Expr(expr_str, range) => {
2132 let expr_str = expr_str.trim();
2134
2135 if expr_str == constants::identifiers::SELF {
2137 parsed_segments.push(super::node::StringSegment::Self_);
2138 } else if let Some(stripped) = expr_str.strip_prefix("$") {
2139 parsed_segments.push(super::node::StringSegment::Env(SmolStr::from(stripped)));
2141 } else {
2142 let lexer = Lexer::new(crate::lexer::Options::default());
2144 let tokens = lexer.tokenize(expr_str, token.module_id).map_err(|_| {
2145 SyntaxError::UnexpectedToken(Token {
2146 range: *range,
2147 kind: TokenKind::InterpolatedString(vec![]),
2148 module_id: token.module_id,
2149 })
2150 })?;
2151
2152 let shared_tokens: Vec<Shared<Token>> = tokens.into_iter().map(Shared::new).collect();
2153 let mut parser = Parser::new(shared_tokens.iter(), self.token_arena, token.module_id);
2154 let expr_node = parser.parse_expr_from_tokens().map_err(|_| {
2155 SyntaxError::UnexpectedToken(Token {
2156 range: *range,
2157 kind: TokenKind::InterpolatedString(vec![]),
2158 module_id: token.module_id,
2159 })
2160 })?;
2161
2162 parsed_segments.push(super::node::StringSegment::Expr(expr_node));
2163 }
2164 }
2165 }
2166 }
2167
2168 Ok(Shared::new(Node {
2169 token_id: self.token_arena.alloc(Shared::clone(token)),
2170 expr: Shared::new(Expr::InterpolatedString(parsed_segments)),
2171 }))
2172 } else {
2173 Err(SyntaxError::UnexpectedToken((**token).clone()))
2174 }
2175 }
2176
2177 #[inline(always)]
2178 fn parse_expr_from_tokens(&mut self) -> Result<Shared<Node>, SyntaxError> {
2179 if let Some(token) = self.tokens.next() {
2180 self.parse_expr(token)
2181 } else {
2182 Err(SyntaxError::UnexpectedEOFDetected(self.module_id))
2183 }
2184 }
2185
2186 fn parse_params(&mut self) -> Result<Params, SyntaxError> {
2188 let opening_paren = match self.tokens.peek() {
2189 Some(token) => match &token.kind {
2190 TokenKind::LParen => {
2191 let t = (***token).clone();
2192 self.tokens.next();
2193 Some(t)
2194 }
2195 _ => return Err(SyntaxError::UnexpectedToken((***token).clone())),
2196 },
2197 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2198 };
2199
2200 let mut params: Params = SmallVec::new();
2201 let mut prev_token: Option<&TokenKind> = None;
2202 let mut seen_default = false;
2203 let mut seen_variadic = false;
2204
2205 while let Some(token) = self.tokens.next() {
2206 match &token.kind {
2207 TokenKind::RParen => match prev_token {
2208 Some(TokenKind::Comma) => {
2209 return Err(SyntaxError::UnexpectedToken((**token).clone()));
2210 }
2211 _ => break,
2212 },
2213 TokenKind::Eof => match prev_token {
2214 Some(TokenKind::RParen) => break,
2215 Some(_) | None => {
2216 return Err(SyntaxError::ExpectedClosingParen(
2217 (**token).clone(),
2218 opening_paren.clone().map(Box::new),
2219 ));
2220 }
2221 },
2222 TokenKind::Comma => match prev_token {
2223 Some(_) => {
2224 let token = match self.tokens.peek() {
2225 Some(token) => Ok(Shared::clone(token)),
2226 None => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2227 }?;
2228 match &token.kind {
2229 TokenKind::Comma => {
2230 return Err(SyntaxError::UnexpectedToken((*token).clone()));
2231 }
2232 _ => continue,
2233 }
2234 }
2235 None => return Err(SyntaxError::UnexpectedToken((**token).clone())),
2236 },
2237 TokenKind::SemiColon => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2238 TokenKind::Asterisk => {
2239 if seen_variadic {
2241 return Err(SyntaxError::MultipleVariadicParameters((**token).clone()));
2242 }
2243 let ident_token = match self.tokens.next() {
2244 Some(t) => t,
2245 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2246 };
2247 match &ident_token.kind {
2248 TokenKind::Ident(name) => {
2249 let ident = IdentWithToken::new_with_token(name, Some(Shared::clone(ident_token)));
2250 params.push(Param::variadic(ident));
2251 seen_variadic = true;
2252 }
2253 _ => {
2254 return Err(SyntaxError::UnexpectedToken((**ident_token).clone()));
2255 }
2256 }
2257 }
2258 TokenKind::Ident(name) => {
2259 if seen_variadic {
2261 return Err(SyntaxError::VariadicParameterMustBeLast((**token).clone()));
2262 }
2263
2264 let ident = IdentWithToken::new_with_token(name, Some(Shared::clone(token)));
2266
2267 let default = if let Some(next_token) = self.tokens.peek()
2269 && matches!(next_token.kind, TokenKind::Equal)
2270 {
2271 self.tokens.next(); seen_default = true;
2273
2274 let default_token = match self.tokens.next() {
2276 Some(t) => t,
2277 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2278 };
2279
2280 Some(self.parse_expr(default_token)?)
2281 } else {
2282 if seen_default {
2283 return Err(SyntaxError::ParameterWithoutDefaultAfterDefault((**token).clone()));
2284 }
2285 None
2286 };
2287
2288 params.push(Param::with_default(ident, default));
2289 }
2290 _ => {
2291 return Err(SyntaxError::UnexpectedToken((**token).clone()));
2292 }
2293 }
2294
2295 prev_token = Some(&token.kind);
2296
2297 if let Some(token) = self.tokens.peek()
2298 && !matches!(token.kind, TokenKind::RParen | TokenKind::Comma)
2299 {
2300 return Err(SyntaxError::ExpectedClosingParen(
2301 (***token).clone(),
2302 opening_paren.clone().map(Box::new),
2303 ));
2304 }
2305 }
2306
2307 Ok(params)
2308 }
2309
2310 fn parse_args(&mut self) -> Result<Args, SyntaxError> {
2311 let opening_paren = match self.tokens.peek() {
2312 Some(token) => match &token.kind {
2313 TokenKind::LParen => {
2314 let t = (***token).clone();
2315 self.tokens.next();
2316 Some(t)
2317 }
2318 _ => return Err(SyntaxError::UnexpectedToken((***token).clone())),
2319 },
2320 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2321 };
2322
2323 let mut args: Args = SmallVec::new();
2324 let mut prev_token: Option<&TokenKind> = None;
2325
2326 while let Some(token) = self.tokens.next() {
2327 match &token.kind {
2328 TokenKind::RParen => match prev_token {
2329 Some(TokenKind::Comma) => {
2330 return Err(SyntaxError::UnexpectedToken((**token).clone()));
2331 }
2332 _ => break,
2333 },
2334 TokenKind::Eof => match prev_token {
2335 Some(TokenKind::RParen) => break,
2336 Some(_) | None => {
2337 return Err(SyntaxError::ExpectedClosingParen(
2338 (**token).clone(),
2339 opening_paren.clone().map(Box::new),
2340 ));
2341 }
2342 },
2343 TokenKind::Comma => match prev_token {
2344 Some(_) => {
2345 let token = match self.tokens.peek() {
2346 Some(token) => Ok(Shared::clone(token)),
2347 None => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2348 }?;
2349 match &token.kind {
2350 TokenKind::Comma => {
2351 return Err(SyntaxError::UnexpectedToken((*token).clone()));
2352 }
2353 _ => continue,
2354 }
2355 }
2356 None => return Err(SyntaxError::UnexpectedToken((**token).clone())),
2357 },
2358 TokenKind::SemiColon => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2359 _ => {
2360 args.push(self.parse_arg_expr(token)?);
2362 }
2363 }
2364
2365 prev_token = Some(&token.kind);
2366
2367 if let Some(token) = self.tokens.peek()
2368 && !matches!(token.kind, TokenKind::RParen | TokenKind::Comma)
2369 {
2370 return Err(SyntaxError::ExpectedClosingParen(
2371 (***token).clone(),
2372 opening_paren.clone().map(Box::new),
2373 ));
2374 }
2375 }
2376
2377 Ok(args)
2378 }
2379
2380 #[inline(always)]
2383 fn parse_arg_expr(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2384 self.parse_expr(token)
2385 }
2386
2387 fn parse_set_attr_call_with_selector(
2388 &mut self,
2389 selector_node: Shared<Node>,
2390 attr_literal: Shared<Node>,
2391 ) -> Result<Shared<Node>, SyntaxError> {
2392 let token = match self.tokens.next() {
2393 Some(token) => token,
2394 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2395 };
2396 let value = self.parse_expr(token)?;
2397
2398 Ok(Shared::new(Node {
2400 token_id: self.token_arena.alloc(Shared::clone(token)),
2401 expr: Shared::new(Expr::Call(
2402 IdentWithToken::new_with_token(constants::builtins::SET_ATTR, Some(Shared::clone(token))),
2403 smallvec![selector_node, attr_literal, value],
2404 )),
2405 }))
2406 }
2407
2408 fn build_attr_call_for_node(
2410 &mut self,
2411 base_node: Shared<Node>,
2412 attr_token: Shared<Token>,
2413 token: &Shared<Token>,
2414 ) -> Result<Shared<Node>, SyntaxError> {
2415 if let TokenKind::Selector(attr_selector) = &attr_token.kind {
2416 if !Selector::try_from(&*attr_token)
2417 .map_err(SyntaxError::UnknownSelector)?
2418 .is_attribute_selector()
2419 {
2420 return Err(SyntaxError::UnexpectedToken((*attr_token).clone()));
2421 }
2422
2423 let attribute = &attr_selector[1..]; let attr_literal = Shared::new(Node {
2425 token_id: self.token_arena.alloc(Shared::clone(token)),
2426 expr: Shared::new(Expr::Literal(Literal::String(attribute.to_string()))),
2427 });
2428
2429 if self.is_next_token(|kind| matches!(kind, TokenKind::PipeEqual)) {
2430 self.tokens.next(); return self.parse_set_attr_call_with_selector(base_node, attr_literal);
2432 }
2433
2434 Ok(Shared::new(Node {
2435 token_id: self.token_arena.alloc(Shared::clone(token)),
2436 expr: Shared::new(Expr::Call(
2437 IdentWithToken::new_with_token(constants::builtins::ATTR, Some(Shared::clone(token))),
2438 smallvec![base_node, attr_literal],
2439 )),
2440 }))
2441 } else {
2442 Err(SyntaxError::UnexpectedToken((**token).clone()))
2443 }
2444 }
2445
2446 fn parse_selector_with_attribute(
2448 &mut self,
2449 token: &Shared<Token>,
2450 attr_token: Shared<Token>,
2451 ) -> Result<Shared<Node>, SyntaxError> {
2452 let base_node = self.parse_selector_direct(token)?;
2453 self.build_attr_call_for_node(base_node, attr_token, token)
2454 }
2455
2456 fn parse_selector_direct(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2458 match &token.kind {
2459 TokenKind::Selector(selector) => {
2460 if selector == "." {
2461 if self.is_next_token(|token_kind| matches!(token_kind, TokenKind::LBracket)) {
2462 self.parse_selector_table_args(Shared::clone(token))
2463 } else {
2464 Ok(Shared::new(Node {
2465 token_id: self.token_arena.alloc(Shared::clone(token)),
2466 expr: Shared::new(Expr::Self_),
2467 }))
2468 }
2469 } else {
2470 let selector = Selector::try_from(&**token).map_err(SyntaxError::UnknownSelector)?;
2471
2472 if selector.is_attribute_selector() {
2473 let token_id = self.token_arena.alloc(Shared::clone(token));
2474 let self_node = Shared::new(Node {
2475 token_id,
2476 expr: Shared::new(Expr::Self_),
2477 });
2478 let attr_literal = Shared::new(Node {
2479 token_id,
2480 expr: Shared::new(Expr::Literal(Literal::String(selector.name()))),
2481 });
2482 if self.is_next_token(|kind| matches!(kind, TokenKind::PipeEqual)) {
2483 self.tokens.next();
2484 return self.parse_set_attr_call_with_selector(self_node, attr_literal);
2485 }
2486 return Ok(Shared::new(Node {
2487 token_id,
2488 expr: Shared::new(Expr::Call(
2489 IdentWithToken::new_with_token(constants::builtins::ATTR, Some(Shared::clone(token))),
2490 smallvec![self_node, attr_literal],
2491 )),
2492 }));
2493 }
2494
2495 if matches!(selector, Selector::Property(_))
2497 && self.is_next_token(|kind| matches!(kind, TokenKind::LBracket))
2498 {
2499 let prop_node = Shared::new(Node {
2500 token_id: self.token_arena.alloc(Shared::clone(token)),
2501 expr: Shared::new(Expr::Selector(selector)),
2502 });
2503 return self.parse_property_iterator(token, vec![prop_node]);
2504 }
2505
2506 Ok(Shared::new(Node {
2507 token_id: self.token_arena.alloc(Shared::clone(token)),
2508 expr: Shared::new(Expr::Selector(selector)),
2509 }))
2510 }
2511 }
2512 TokenKind::DoubleDot => {
2513 let recursive_node = Shared::new(Node {
2514 token_id: self.token_arena.alloc(Shared::clone(token)),
2515 expr: Shared::new(Expr::Selector(Selector::Recursive)),
2516 });
2517 if let Some(next) = self.tokens.peek() {
2518 match &next.kind {
2519 TokenKind::StringLiteral(key) => {
2521 let key = key.clone();
2522 let next = self.tokens.next().unwrap();
2523 let prop_node = Shared::new(Node {
2524 token_id: self.token_arena.alloc(Shared::clone(next)),
2525 expr: Shared::new(Expr::Selector(Selector::Property(Ident::new(key.as_str())))),
2526 });
2527 return Ok(Shared::new(Node {
2528 token_id: self.token_arena.alloc(Shared::clone(token)),
2529 expr: Shared::new(Expr::Block(vec![recursive_node, prop_node])),
2530 }));
2531 }
2532 TokenKind::Ident(name) => {
2536 let selector_str = format!(".{}", name);
2537 if let Some(selector) = Selector::from_selector_str(&selector_str)
2538 && !selector.is_attribute_selector()
2539 {
2540 let next = self.tokens.next().unwrap();
2541 let sel_node = Shared::new(Node {
2542 token_id: self.token_arena.alloc(Shared::clone(next)),
2543 expr: Shared::new(Expr::Selector(selector)),
2544 });
2545
2546 return Ok(Shared::new(Node {
2547 token_id: self.token_arena.alloc(Shared::clone(token)),
2548 expr: Shared::new(Expr::Block(vec![recursive_node, sel_node])),
2549 }));
2550 }
2551 }
2552 _ => {}
2553 }
2554 }
2555 Ok(recursive_node)
2556 }
2557 _ => Err(SyntaxError::InsufficientTokens((**token).clone())),
2558 }
2559 }
2560
2561 fn parse_selector(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2562 if let TokenKind::Selector(_) = &token.kind
2564 && matches!(Selector::try_from(&**token), Ok(Selector::Property(_)))
2565 {
2566 let next_is_property = self
2567 .tokens
2568 .peek()
2569 .is_some_and(|t| matches!(Selector::try_from(&***t), Ok(Selector::Property(_))));
2570 if next_is_property {
2571 return self.parse_chained_property_selectors(token);
2572 }
2573 }
2574
2575 if self.is_next_token(|kind| matches!(kind, TokenKind::Selector(_)))
2576 && let Some(attr_token) = self.tokens.next()
2577 {
2578 return self.parse_selector_with_attribute(token, Shared::clone(attr_token));
2579 }
2580
2581 if self.is_next_token(|kind| matches!(kind, TokenKind::LParen))
2583 && let TokenKind::Selector(s) = &token.kind
2584 && s != "."
2585 {
2586 let selector = Selector::try_from(&**token).map_err(SyntaxError::UnknownSelector)?;
2587 if !selector.is_attribute_selector() {
2588 let args = self.parse_args()?;
2589 let base_node = Shared::new(Node {
2590 token_id: self.token_arena.alloc(Shared::clone(token)),
2591 expr: Shared::new(Expr::SelectorCall(selector, args)),
2592 });
2593 if self.is_next_token(|kind| matches!(kind, TokenKind::Selector(_)))
2595 && let Some(attr_token) = self.tokens.next()
2596 {
2597 return self.build_attr_call_for_node(base_node, Shared::clone(attr_token), token);
2598 }
2599 return Ok(base_node);
2600 }
2601 }
2602
2603 self.parse_selector_direct(token)
2604 }
2605
2606 fn parse_chained_property_selectors(&mut self, first_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2607 let first_sel = Selector::try_from(&**first_token).map_err(SyntaxError::UnknownSelector)?;
2608 let mut nodes: Program = vec![Shared::new(Node {
2609 token_id: self.token_arena.alloc(Shared::clone(first_token)),
2610 expr: Shared::new(Expr::Selector(first_sel)),
2611 })];
2612
2613 while self.is_next_token(|kind| matches!(kind, TokenKind::Selector(_))) {
2614 let next_is_property = self
2615 .tokens
2616 .peek()
2617 .is_some_and(|t| matches!(Selector::try_from(&***t), Ok(Selector::Property(_))));
2618 if !next_is_property {
2619 break;
2620 }
2621 let next_token = self.tokens.next().unwrap();
2622 let sel = Selector::try_from(&**next_token).map_err(SyntaxError::UnknownSelector)?;
2623 nodes.push(Shared::new(Node {
2624 token_id: self.token_arena.alloc(Shared::clone(next_token)),
2625 expr: Shared::new(Expr::Selector(sel)),
2626 }));
2627 }
2628
2629 if self.is_next_token(|kind| matches!(kind, TokenKind::LBracket)) {
2631 return self.parse_property_iterator(first_token, nodes);
2632 }
2633
2634 Ok(Shared::new(Node {
2635 token_id: self.token_arena.alloc(Shared::clone(first_token)),
2636 expr: Shared::new(Expr::Block(nodes)),
2637 }))
2638 }
2639
2640 fn parse_property_iterator(
2641 &mut self,
2642 token: &Shared<Token>,
2643 mut nodes: Program,
2644 ) -> Result<Shared<Node>, SyntaxError> {
2645 let index = self.parse_bracket_expr()?;
2646
2647 let list_selector = match &index {
2648 None => Selector::List(None, None),
2649 Some(node) => {
2650 if let Expr::Literal(Literal::Number(num)) = &*node.expr {
2651 Selector::List(Some(num.value() as usize), None)
2652 } else {
2653 let token_id = self.token_arena.alloc(Shared::clone(token));
2655 nodes.push(Shared::new(Node {
2656 token_id,
2657 expr: Shared::new(Expr::SelectorCall(
2658 Selector::List(None, None),
2659 smallvec![Shared::clone(node)],
2660 )),
2661 }));
2662 return Ok(Shared::new(Node {
2663 token_id: self.token_arena.alloc(Shared::clone(token)),
2664 expr: Shared::new(Expr::Block(nodes)),
2665 }));
2666 }
2667 }
2668 };
2669
2670 nodes.push(Shared::new(Node {
2671 token_id: self.token_arena.alloc(Shared::clone(token)),
2672 expr: Shared::new(Expr::Selector(list_selector)),
2673 }));
2674
2675 Ok(Shared::new(Node {
2676 token_id: self.token_arena.alloc(Shared::clone(token)),
2677 expr: Shared::new(Expr::Block(nodes)),
2678 }))
2679 }
2680
2681 fn parse_selector_table_args(&mut self, token: Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2683 let first = self.parse_bracket_expr()?;
2684 let has_second = self.is_next_token(|kind| matches!(kind, TokenKind::LBracket));
2685 let second = if has_second {
2686 Some(self.parse_bracket_expr()?)
2687 } else {
2688 None
2689 };
2690
2691 let is_dynamic_node = |opt: &Option<Shared<Node>>| {
2692 opt.as_ref()
2693 .is_some_and(|n| !matches!(&*n.expr, Expr::Literal(Literal::Number(_))))
2694 };
2695 let has_dynamic = is_dynamic_node(&first) || second.as_ref().is_some_and(is_dynamic_node);
2696 let has_explicit_args = self.is_next_token(|kind| matches!(kind, TokenKind::LParen));
2697
2698 if has_dynamic || has_explicit_args {
2699 let is_table = second.is_some();
2700 let selector = if is_table {
2701 Selector::Table(None, None)
2702 } else {
2703 Selector::List(None, None)
2704 };
2705
2706 let mut args: Args = SmallVec::new();
2707
2708 if is_table && first.is_none() && second.as_ref().is_some_and(|s| s.is_some()) {
2710 let placeholder_token_id = self.token_arena.alloc(Shared::clone(&token));
2711 args.push(Shared::new(Node {
2712 token_id: placeholder_token_id,
2713 expr: Shared::new(Expr::Literal(Literal::None)),
2714 }));
2715 } else if let Some(node) = first {
2716 args.push(node);
2717 }
2718
2719 if let Some(Some(node)) = second {
2720 args.push(node);
2721 }
2722 if has_explicit_args {
2723 args.extend(self.parse_args()?);
2724 }
2725
2726 let token_id = self.token_arena.alloc(Shared::clone(&token));
2727 return Ok(Shared::new(Node {
2728 token_id,
2729 expr: Shared::new(Expr::SelectorCall(selector, args)),
2730 }));
2731 }
2732
2733 let static_index = |opt: Option<Shared<Node>>| -> Option<usize> {
2734 opt.and_then(|n| {
2735 if let Expr::Literal(Literal::Number(num)) = &*n.expr {
2736 Some(num.value() as usize)
2737 } else {
2738 None
2739 }
2740 })
2741 };
2742 let i1 = static_index(first);
2743 let selector = match second {
2744 None => Selector::List(i1, None),
2745 Some(opt) => Selector::Table(i1, static_index(opt)),
2746 };
2747
2748 let token_id = self.token_arena.alloc(Shared::clone(&token));
2749 Ok(Shared::new(Node {
2750 token_id,
2751 expr: Shared::new(Expr::Selector(selector)),
2752 }))
2753 }
2754
2755 fn parse_bracket_expr(&mut self) -> Result<Option<Shared<Node>>, SyntaxError> {
2756 let bracket_token = match self.tokens.peek() {
2757 Some(t) => Shared::clone(t),
2758 None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2759 };
2760 self.next_token(|kind| matches!(kind, TokenKind::LBracket))?;
2761
2762 if self.is_next_token(|kind| matches!(kind, TokenKind::RBracket)) {
2763 self.tokens.next();
2764 return Ok(None);
2765 }
2766
2767 let expr_token = match self.tokens.next() {
2768 Some(t) => Shared::clone(t),
2769 None => return Err(SyntaxError::InsufficientTokens((*bracket_token).clone())),
2770 };
2771 let node = self.parse_expr(&expr_token)?;
2772 self.next_token(|kind| matches!(kind, TokenKind::RBracket))?;
2773 Ok(Some(node))
2774 }
2775
2776 fn next_token(&mut self, expected_kinds: fn(&TokenKind) -> bool) -> Result<TokenId, SyntaxError> {
2777 match self.tokens.peek() {
2778 Some(token) if expected_kinds(&token.kind) => {
2780 let token = self.tokens.next().unwrap();
2781 Ok(self.token_arena.alloc(Shared::clone(token)))
2782 } Some(token) => Err(SyntaxError::UnexpectedToken(Token {
2785 range: token.range,
2786 kind: token.kind.clone(),
2787 module_id: token.module_id,
2788 })),
2789 None =>
2791 {
2793 Err(SyntaxError::UnexpectedEOFDetected(self.module_id))
2794 }
2795 }
2796 }
2797
2798 #[inline(always)]
2799 fn consume_colon(&mut self) {
2800 if self.is_next_token(|token_kind| matches!(token_kind, TokenKind::Colon)) {
2801 let _ = self.next_token(|token_kind| matches!(token_kind, TokenKind::Colon));
2802 }
2803 }
2804
2805 #[inline(always)]
2806 fn consume_colon_or_do(&mut self) {
2807 if self.is_next_token(|kind| matches!(kind, TokenKind::Do)) {
2809 let _ = self.next_token(|kind| matches!(kind, TokenKind::Do));
2810 } else {
2811 self.consume_colon();
2812 }
2813 }
2814}
2815
2816#[cfg(test)]
2817mod tests {
2818 use crate::ast::node::StringSegment;
2819 use crate::{Module, ast::node::MatchArm, range::Range, selector};
2820
2821 use super::*;
2822 use rstest::rstest;
2823 use smallvec::smallvec;
2824
2825 fn token(token_kind: TokenKind) -> Token {
2826 Token {
2827 range: Range::default(),
2828 kind: token_kind,
2829 module_id: 1.into(),
2830 }
2831 }
2832
2833 #[rstest]
2834 #[case::ident1(
2835 vec![
2836 token(TokenKind::Ident(SmolStr::new("and"))),
2837 token(TokenKind::LParen),
2838 token(TokenKind::Ident(SmolStr::new("contains"))),
2839 token(TokenKind::LParen),
2840 token(TokenKind::StringLiteral("test".to_owned())),
2841 token(TokenKind::RParen),
2842 token(TokenKind::Comma),
2843 token(TokenKind::Ident(SmolStr::new("startswith"))),
2844 token(TokenKind::LParen),
2845 token(TokenKind::StringLiteral("test2".to_owned())),
2846 token(TokenKind::RParen),
2847 token(TokenKind::RParen),
2848 token(TokenKind::Eof)
2849 ],
2850 Ok(vec![
2851 Shared::new(Node {
2852 token_id: 4.into(),
2853 expr: Shared::new(Expr::Call(
2854 IdentWithToken::new_with_token("and", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("and")))))),
2855 smallvec![
2856 Shared::new(Node {
2857 token_id: 1.into(),
2858 expr: Shared::new(Expr::Call(
2859 IdentWithToken::new_with_token("contains", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("contains")))))),
2860 smallvec![Shared::new(Node {
2861 token_id: 0.into(),
2862 expr: Shared::new(Expr::Literal(Literal::String("test".to_owned())))
2863 })],
2864 ))
2865 }),
2866 Shared::new(Node {
2867 token_id: 3.into(),
2868 expr: Shared::new(Expr::Call(
2869 IdentWithToken::new_with_token("startswith", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("startswith")))))),
2870 smallvec![Shared::new(Node {
2871 token_id: 2.into(),
2872 expr: Shared::new(Expr::Literal(Literal::String("test2".to_owned())))
2873 })],
2874 ))
2875 })
2876 ],
2877 ))
2878 })
2879 ]))]
2880 #[case::ident2(
2881 vec![
2882 token(TokenKind::Ident(SmolStr::new("and"))),
2883 token(TokenKind::LParen),
2884 token(TokenKind::Selector(SmolStr::new(".h1"))),
2885 token(TokenKind::Comma),
2886 token(TokenKind::Selector(SmolStr::new("."))),
2887 token(TokenKind::LBracket),
2888 token(TokenKind::NumberLiteral(2.into())),
2889 token(TokenKind::RBracket),
2890 token(TokenKind::LBracket),
2891 token(TokenKind::RBracket),
2892 token(TokenKind::RParen),
2893 token(TokenKind::Eof)
2894 ],
2895 Ok(vec![
2896 Shared::new(Node {
2897 token_id: 8.into(),
2898 expr: Shared::new(Expr::Call(
2899 IdentWithToken::new_with_token("and", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("and")))))),
2900 smallvec![
2901 Shared::new(Node {
2902 token_id: 0.into(),
2903 expr: Shared::new(Expr::Selector(Selector::Heading(Some(1)))),
2904 }),
2905 Shared::new(Node {
2906 token_id: 5.into(),
2907 expr: Shared::new(Expr::Selector(Selector::Table(Some(2), None))),
2908 }),
2909 ],
2910 ))
2911 })
2912 ]))]
2913 #[case::ident3(
2914 vec![
2915 token(TokenKind::Def),
2916 token(TokenKind::Ident(SmolStr::new("filter"))),
2917 token(TokenKind::LParen),
2918 token(TokenKind::Ident(SmolStr::new("arg1"))),
2919 token(TokenKind::Comma),
2920 token(TokenKind::Ident(SmolStr::new("arg2"))),
2921 token(TokenKind::RParen),
2922 token(TokenKind::Colon),
2923 token(TokenKind::Ident(SmolStr::new("contains"))),
2924 token(TokenKind::LParen),
2925 token(TokenKind::StringLiteral("arg1".to_owned())),
2926 token(TokenKind::Comma),
2927 token(TokenKind::StringLiteral("arg2".to_owned())),
2928 token(TokenKind::RParen),
2929 ],
2930 Ok(vec![
2931 Shared::new(Node {
2932 token_id: 0.into(),
2933 expr: Shared::new(Expr::Def(
2934 IdentWithToken::new_with_token("filter", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("filter")))))),
2935 smallvec![
2936 Param::new(IdentWithToken::new_with_token("arg1", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arg1"))))))),
2937 Param::new(IdentWithToken::new_with_token("arg2", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arg2"))))))),
2938 ],
2939 vec![Shared::new(Node {
2940 token_id: 4.into(),
2941 expr: Shared::new(Expr::Call(
2942 IdentWithToken::new_with_token("contains", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("contains")))))),
2943 smallvec![
2944 Shared::new(Node {
2945 token_id: 2.into(),
2946 expr: Shared::new(Expr::Literal(Literal::String("arg1".to_owned()))),
2947 }),
2948 Shared::new(Node {
2949 token_id: 3.into(),
2950 expr: Shared::new(Expr::Literal(Literal::String("arg2".to_owned()))),
2951 }),
2952 ],
2953 )),
2954 })],
2955 )),
2956 }),
2957 ]))]
2958 #[case::ident4(
2959 vec![
2960 token(TokenKind::Ident(SmolStr::new("and"))),
2961 token(TokenKind::LParen),
2962 token(TokenKind::None),
2963 token(TokenKind::Comma),
2964 token(TokenKind::Self_),
2965 token(TokenKind::RParen),
2966 token(TokenKind::Eof)
2967 ],
2968 Ok(vec![
2969 Shared::new(Node {
2970 token_id: 2.into(),
2971 expr: Shared::new(Expr::Call(
2972 IdentWithToken::new_with_token("and", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("and")))))),
2973 smallvec![
2974 Shared::new(Node {
2975 token_id: 0.into(),
2976 expr: Shared::new(Expr::Literal(Literal::None)),
2977 }),
2978 Shared::new(Node {
2979 token_id: 1.into(),
2980 expr: Shared::new(Expr::Self_),
2981 }),
2982 ],
2983 ))
2984 })
2985 ]))]
2986 #[case::ident5(
2987 vec![
2988 token(TokenKind::Ident(SmolStr::new("and"))),
2989 token(TokenKind::LParen),
2990 token(TokenKind::None),
2991 token(TokenKind::Comma),
2992 token(TokenKind::Self_),
2993 token(TokenKind::RParen),
2994 token(TokenKind::Ident(SmolStr::new("and"))),
2995 ],
2996 Err(SyntaxError::UnexpectedToken(token(TokenKind::Ident(SmolStr::new("and"))))))]
2997 #[case::ident5(
2998 vec![
2999 token(TokenKind::Ident(SmolStr::new("and"))),
3000 token(TokenKind::LParen),
3001 token(TokenKind::None),
3002 token(TokenKind::Comma),
3003 token(TokenKind::Self_),
3004 token(TokenKind::RParen),
3005 token(TokenKind::Def),
3006 ],
3007 Err(SyntaxError::UnexpectedToken(token(TokenKind::Def))))]
3008 #[case::ident6(
3009 vec![
3010 token(TokenKind::Ident(SmolStr::new("and"))),
3011 token(TokenKind::Def),
3012 ],
3013 Err(SyntaxError::UnexpectedToken(token(TokenKind::Ident(SmolStr::new("and"))))))]
3014 #[case::ident_attribute_access(
3015 vec![
3016 token(TokenKind::Ident(SmolStr::new("c"))),
3017 token(TokenKind::Selector(SmolStr::new(".lang"))),
3018 token(TokenKind::Eof),
3019 ],
3020 Ok(vec![
3021 Shared::new(Node {
3022 token_id: 2.into(),
3023 expr: Shared::new(Expr::Call(
3024 IdentWithToken::new_with_token(constants::builtins::ATTR, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))),
3025 smallvec![
3026 Shared::new(Node {
3027 token_id: 0.into(),
3028 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("c", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))))),
3029 }),
3030 Shared::new(Node {
3031 token_id: 1.into(),
3032 expr: Shared::new(Expr::Literal(Literal::String("lang".to_owned()))),
3033 }),
3034 ],
3035 )),
3036 })
3037 ]))]
3038 #[case::error(
3039 vec![
3040 token(TokenKind::Ident(SmolStr::new("contains"))),
3041 token(TokenKind::LParen),
3042 token(TokenKind::Selector(SmolStr::new("inline_code"))),
3043 token(TokenKind::Eof)
3044 ],
3045 Err(SyntaxError::UnknownSelector(selector::UnknownSelector::new(token(TokenKind::Selector(SmolStr::new("inline_code")))))))]
3046 #[case::def1(
3047 vec![
3048 token(TokenKind::Def),
3049 token(TokenKind::Ident(SmolStr::new("name"))),
3050 token(TokenKind::LParen),
3051 token(TokenKind::RParen),
3052 token(TokenKind::Colon),
3053 token(TokenKind::StringLiteral("value".to_owned())),
3054 token(TokenKind::SemiColon)
3055 ],
3056 Ok(vec![
3057 Shared::new(Node {
3058 token_id: 0.into(),
3059 expr: Shared::new(Expr::Def(
3060 IdentWithToken::new_with_token("name", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("name")))))),
3061 SmallVec::new(),
3062 vec![Shared::new(Node {
3063 token_id: 2.into(),
3064 expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
3065 })],
3066 )),
3067 }),
3068 ]))]
3069 #[case::def_with_end(
3070 vec![
3071 token(TokenKind::Def),
3072 token(TokenKind::Ident(SmolStr::new("name"))),
3073 token(TokenKind::LParen),
3074 token(TokenKind::RParen),
3075 token(TokenKind::Colon),
3076 token(TokenKind::StringLiteral("value".to_owned())),
3077 token(TokenKind::End)
3078 ],
3079 Ok(vec![
3080 Shared::new(Node {
3081 token_id: 0.into(),
3082 expr: Shared::new(Expr::Def(
3083 IdentWithToken::new_with_token("name", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("name")))))),
3084 SmallVec::new(),
3085 vec![Shared::new(Node {
3086 token_id: 2.into(),
3087 expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
3088 })],
3089 )),
3090 }),
3091 ]))]
3092 #[case::def2(
3093 vec![
3094 token(TokenKind::Def),
3095 token(TokenKind::Ident(SmolStr::new("name"))),
3096 token(TokenKind::LParen),
3097 token(TokenKind::Comma),
3098 token(TokenKind::RParen),
3099 ],
3100 Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::Comma, module_id: 1.into()})))]
3101 #[case::def3(
3102 vec![
3103 token(TokenKind::Def),
3104 token(TokenKind::Ident(SmolStr::new("name"))),
3105 token(TokenKind::LParen),
3106 token(TokenKind::StringLiteral("value".to_owned())),
3107 token(TokenKind::Comma),
3108 token(TokenKind::RParen),
3109 ],
3110 Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::StringLiteral("value".to_string()), module_id: 1.into()})))]
3111 #[case::def4(
3112 vec![
3113 token(TokenKind::Def),
3114 token(TokenKind::Ident(SmolStr::new("name"))),
3115 token(TokenKind::LParen),
3116 token(TokenKind::StringLiteral("value".to_owned())),
3117 token(TokenKind::RParen),
3118 token(TokenKind::Colon),
3119 ],
3120 Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::StringLiteral("value".to_string()), module_id: 1.into()})))]
3121 #[case::def5(
3122 vec![
3123 token(TokenKind::Def),
3124 token(TokenKind::Ident(SmolStr::new("name"))),
3125 token(TokenKind::LParen),
3126 token(TokenKind::StringLiteral("value".to_owned())),
3127 token(TokenKind::RParen),
3128 token(TokenKind::Colon),
3129 token(TokenKind::Pipe),
3130 ],
3131 Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::StringLiteral("value".to_string()), module_id: 1.into()})))]
3132 #[case::def6(
3133 vec![
3134 token(TokenKind::Def),
3135 token(TokenKind::Ident(SmolStr::new("name"))),
3136 token(TokenKind::LParen),
3137 token(TokenKind::StringLiteral("value".to_owned())),
3138 token(TokenKind::RParen),
3139 token(TokenKind::Colon),
3140 token(TokenKind::SemiColon),
3141 ],
3142 Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::StringLiteral("value".to_string()), module_id: 1.into()})))]
3143 #[case::def7(
3144 vec![
3145 token(TokenKind::Def),
3146 token(TokenKind::Ident(SmolStr::new("name"))),
3147 token(TokenKind::LParen),
3148 token(TokenKind::StringLiteral("value".to_owned())),
3149 token(TokenKind::RParen),
3150 token(TokenKind::Colon),
3151 ],
3152 Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::StringLiteral("value".to_string()), module_id: 1.into()})))]
3153 #[case::def7(
3154 vec![
3155 token(TokenKind::Def),
3156 token(TokenKind::LParen),
3157 token(TokenKind::StringLiteral("value".to_owned())),
3158 token(TokenKind::RParen),
3159 token(TokenKind::Colon),
3160 ],
3161 Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind:TokenKind::LParen, module_id: 1.into()})))]
3162 #[case::def_without_colon1(
3163 vec![
3164 token(TokenKind::Def),
3165 token(TokenKind::Ident(SmolStr::new("name"))),
3166 token(TokenKind::LParen),
3167 token(TokenKind::RParen),
3168 token(TokenKind::StringLiteral("value".to_owned())),
3169 token(TokenKind::SemiColon)
3170 ],
3171 Ok(vec![
3172 Shared::new(Node {
3173 token_id: 0.into(),
3174 expr: Shared::new(Expr::Def(
3175 IdentWithToken::new_with_token("name", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("name")))))),
3176 SmallVec::new(),
3177 vec![Shared::new(Node {
3178 token_id: 1.into(),
3179 expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
3180 })],
3181 )),
3182 }),
3183 ]))]
3184 #[case::def_without_colon2(
3185 vec![
3186 token(TokenKind::Def),
3187 token(TokenKind::Ident(SmolStr::new("name"))),
3188 token(TokenKind::LParen),
3189 token(TokenKind::RParen),
3190 token(TokenKind::StringLiteral("value".to_owned())),
3191 token(TokenKind::End)
3192 ],
3193 Ok(vec![
3194 Shared::new(Node {
3195 token_id: 0.into(),
3196 expr: Shared::new(Expr::Def(
3197 IdentWithToken::new_with_token("name", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("name")))))),
3198 SmallVec::new(),
3199 vec![Shared::new(Node {
3200 token_id: 1.into(),
3201 expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
3202 })],
3203 )),
3204 }),
3205 ]))]
3206 #[case::def_without_colon_with_args(
3207 vec![
3208 token(TokenKind::Def),
3209 token(TokenKind::Ident(SmolStr::new("name"))),
3210 token(TokenKind::LParen),
3211 token(TokenKind::Ident(SmolStr::new("x"))),
3212 token(TokenKind::RParen),
3213 token(TokenKind::Ident(SmolStr::new("x"))),
3214 token(TokenKind::SemiColon)
3215 ],
3216 Ok(vec![
3217 Shared::new(Node {
3218 token_id: 0.into(),
3219 expr: Shared::new(Expr::Def(
3220 IdentWithToken::new_with_token("name", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("name")))))),
3221 smallvec![
3222 Param::new(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x"))))))),
3223 ],
3224 vec![Shared::new(Node {
3225 token_id: 1.into(),
3226 expr: Shared::new(Expr::Ident(
3227 IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))),
3228 )),
3229 })],
3230 )),
3231 }),
3232 ]))]
3233 #[case::unmatched_end_at_root(
3234 vec![
3236 token(TokenKind::Def),
3237 token(TokenKind::Ident(SmolStr::new("foo"))),
3238 token(TokenKind::Colon),
3239 token(TokenKind::If),
3240 token(TokenKind::LParen),
3241 token(TokenKind::Selector(SmolStr::new("."))),
3242 token(TokenKind::RParen),
3243 token(TokenKind::Colon),
3244 token(TokenKind::Selector(SmolStr::new("."))),
3245 token(TokenKind::End), token(TokenKind::End), token(TokenKind::Pipe), token(TokenKind::Ident(SmolStr::new("foo"))),
3249 token(TokenKind::Eof),
3250 ],
3251 Err(SyntaxError::UnmatchedEnd(token(TokenKind::End))))]
3252 #[case::unmatched_end_standalone_if(
3253 vec![
3255 token(TokenKind::If),
3256 token(TokenKind::LParen),
3257 token(TokenKind::Selector(SmolStr::new("."))),
3258 token(TokenKind::RParen),
3259 token(TokenKind::Colon),
3260 token(TokenKind::Selector(SmolStr::new("."))),
3261 token(TokenKind::End), token(TokenKind::End),
3263 token(TokenKind::Eof),
3264 ],
3265 Err(SyntaxError::UnmatchedEnd(token(TokenKind::End))))]
3266 #[case::unmatched_end_at_start(
3267 vec![
3269 token(TokenKind::End),
3270 token(TokenKind::Eof),
3271 ],
3272 Err(SyntaxError::UnmatchedEnd(token(TokenKind::End))))]
3273 #[case::let_1(
3274 vec![
3275 token(TokenKind::Let),
3276 token(TokenKind::Ident(SmolStr::new("x"))),
3277 token(TokenKind::Equal),
3278 token(TokenKind::NumberLiteral(42.into())),
3279 token(TokenKind::Eof)
3280 ],
3281 Ok(vec![
3282 Shared::new(Node {
3283 token_id: 0.into(),
3284 expr: Shared::new(Expr::Let(
3285 Pattern::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x"))))))),
3286 Shared::new(Node {
3287 token_id: 2.into(),
3288 expr: Shared::new(Expr::Literal(Literal::Number(42.into()))),
3289 }),
3290 )),
3291 })
3292 ]))]
3293 #[case::let_2(
3294 vec![
3295 token(TokenKind::Let),
3296 token(TokenKind::Ident(SmolStr::new("y"))),
3297 token(TokenKind::Equal),
3298 token(TokenKind::StringLiteral("hello".to_owned())),
3299 token(TokenKind::Eof)
3300 ],
3301 Ok(vec![
3302 Shared::new(Node {
3303 token_id: 0.into(),
3304 expr: Shared::new(Expr::Let(
3305 Pattern::Ident(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y"))))))),
3306 Shared::new(Node {
3307 token_id: 2.into(),
3308 expr: Shared::new(Expr::Literal(Literal::String("hello".to_owned()))),
3309 }),
3310 )),
3311 })
3312 ]))]
3313 #[case::let_3(
3314 vec![
3315 token(TokenKind::Let),
3316 token(TokenKind::Ident(SmolStr::new("flag"))),
3317 token(TokenKind::Equal),
3318 token(TokenKind::BoolLiteral(true)),
3319 token(TokenKind::Eof)
3320 ],
3321 Ok(vec![
3322 Shared::new(Node {
3323 token_id: 0.into(),
3324 expr: Shared::new(Expr::Let(
3325 Pattern::Ident(IdentWithToken::new_with_token("flag", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("flag"))))))),
3326 Shared::new(Node {
3327 token_id: 2.into(),
3328 expr: Shared::new(Expr::Literal(Literal::Bool(true))),
3329 }),
3330 )),
3331 })
3332 ]))]
3333 #[case::let_4(
3334 vec![
3335 token(TokenKind::Let),
3336 token(TokenKind::Ident(SmolStr::new("z"))),
3337 token(TokenKind::Equal),
3338 token(TokenKind::Ident(SmolStr::new("some_var"))),
3339 token(TokenKind::Eof)
3340 ],
3341 Ok(vec![
3342 Shared::new(Node {
3343 token_id: 0.into(),
3344 expr: Shared::new(Expr::Let(
3345 Pattern::Ident(IdentWithToken::new_with_token("z", Some(Shared::new(token(TokenKind::Ident("z".into())))))),
3346 Shared::new(Node {
3347 token_id: 2.into(),
3348 expr: Shared::new(
3349 Expr::Ident(IdentWithToken::new_with_token("some_var",
3350 Some(Shared::new(token(TokenKind::Ident(SmolStr::new("some_var"))))))))
3351 }),
3352 )),
3353 })
3354 ]))]
3355 #[case::let_5(
3356 vec![
3357 token(TokenKind::Let),
3358 token(TokenKind::Ident(SmolStr::new("z"))),
3359 token(TokenKind::Equal),
3360 token(TokenKind::Ident(SmolStr::new("some_var"))),
3361 token(TokenKind::Pipe),
3362 ],
3363 Ok(vec![
3364 Shared::new(Node {
3365 token_id: 0.into(),
3366 expr: Shared::new(Expr::Let(
3367 Pattern::Ident(IdentWithToken::new_with_token("z", Some(Shared::new(token(TokenKind::Ident("z".into())))))),
3368 Shared::new(Node {
3369 token_id: 2.into(),
3370 expr: Shared::new(
3371 Expr::Ident(IdentWithToken::new_with_token("some_var", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("some_var")))))))),
3372 }),
3373 )),
3374 })
3375 ]))]
3376 #[case::let_6(
3377 vec![
3378 token(TokenKind::Let),
3379 token(TokenKind::Ident(SmolStr::new("z"))),
3380 token(TokenKind::Equal),
3381 token(TokenKind::Ident(SmolStr::new("some_var"))),
3382 ],
3383 Ok(vec![
3384 Shared::new(Node {
3385 token_id: 0.into(),
3386 expr: Shared::new(Expr::Let(
3387 Pattern::Ident(IdentWithToken::new_with_token("z", Some(Shared::new(token(TokenKind::Ident("z".into())))))),
3388 Shared::new(Node {
3389 token_id: 2.into(),
3390 expr: Shared::new(
3391 Expr::Ident(IdentWithToken::new_with_token("some_var", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("some_var")))))))),
3392 }),
3393 )),
3394 })
3395 ]))]
3396 #[case::var_1(
3397 vec![
3398 token(TokenKind::Var),
3399 token(TokenKind::Ident(SmolStr::new("x"))),
3400 token(TokenKind::Equal),
3401 token(TokenKind::NumberLiteral(42.into())),
3402 token(TokenKind::Eof)
3403 ],
3404 Ok(vec![
3405 Shared::new(Node {
3406 token_id: 0.into(),
3407 expr: Shared::new(Expr::Var(
3408 Pattern::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x"))))))),
3409 Shared::new(Node {
3410 token_id: 2.into(),
3411 expr: Shared::new(Expr::Literal(Literal::Number(42.into()))),
3412 }),
3413 )),
3414 })
3415 ]))]
3416 #[case::var_2(
3417 vec![
3418 token(TokenKind::Var),
3419 token(TokenKind::Ident(SmolStr::new("count"))),
3420 token(TokenKind::Equal),
3421 token(TokenKind::NumberLiteral(0.into())),
3422 token(TokenKind::Eof)
3423 ],
3424 Ok(vec![
3425 Shared::new(Node {
3426 token_id: 0.into(),
3427 expr: Shared::new(Expr::Var(
3428 Pattern::Ident(IdentWithToken::new_with_token("count", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("count"))))))),
3429 Shared::new(Node {
3430 token_id: 2.into(),
3431 expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
3432 }),
3433 )),
3434 })
3435 ]))]
3436 #[case::assign_1(
3437 vec![
3438 token(TokenKind::Ident(SmolStr::new("x"))),
3439 token(TokenKind::Equal),
3440 token(TokenKind::NumberLiteral(100.into())),
3441 token(TokenKind::Eof)
3442 ],
3443 Ok(vec![
3444 Shared::new(Node {
3445 token_id: 1.into(),
3446 expr: Shared::new(Expr::Assign(
3447 IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))),
3448 Shared::new(Node {
3449 token_id: 2.into(),
3450 expr: Shared::new(Expr::Literal(Literal::Number(100.into()))),
3451 }),
3452 )),
3453 })
3454 ]))]
3455 #[case::assign_2(
3456 vec![
3457 token(TokenKind::Ident(SmolStr::new("name"))),
3458 token(TokenKind::Equal),
3459 token(TokenKind::StringLiteral("Alice".to_owned())),
3460 token(TokenKind::Eof)
3461 ],
3462 Ok(vec![
3463 Shared::new(Node {
3464 token_id: 1.into(),
3465 expr: Shared::new(Expr::Assign(
3466 IdentWithToken::new_with_token("name", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("name")))))),
3467 Shared::new(Node {
3468 token_id: 2.into(),
3469 expr: Shared::new(Expr::Literal(Literal::String("Alice".to_owned()))),
3470 }),
3471 )),
3472 })
3473 ]))]
3474 #[case::index_assign(
3475 vec![
3476 token(TokenKind::Ident(SmolStr::new("arr"))),
3477 token(TokenKind::LBracket),
3478 token(TokenKind::NumberLiteral(0.into())),
3479 token(TokenKind::RBracket),
3480 token(TokenKind::Equal),
3481 token(TokenKind::NumberLiteral(10.into())),
3482 token(TokenKind::Eof)
3483 ],
3484 Ok(vec![
3485 Shared::new(Node {
3486 token_id: 3.into(),
3487 expr: Shared::new(Expr::Assign(
3488 IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
3489 Shared::new(Node {
3490 token_id: 3.into(),
3491 expr: Shared::new(Expr::Call(
3492 IdentWithToken::new_with_token(constants::builtins::SET, Some(Shared::new(token(TokenKind::Equal)))),
3493 smallvec![
3494 Shared::new(Node {
3495 token_id: 0.into(),
3496 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
3497 }),
3498 Shared::new(Node {
3499 token_id: 1.into(),
3500 expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
3501 }),
3502 Shared::new(Node {
3503 token_id: 4.into(),
3504 expr: Shared::new(Expr::Literal(Literal::Number(10.into()))),
3505 }),
3506 ],
3507 )),
3508 }),
3509 )),
3510 })
3511 ]))]
3512 #[case::index_compound_assign(
3513 vec![
3514 token(TokenKind::Ident(SmolStr::new("arr"))),
3515 token(TokenKind::LBracket),
3516 token(TokenKind::NumberLiteral(0.into())),
3517 token(TokenKind::RBracket),
3518 token(TokenKind::PlusEqual),
3519 token(TokenKind::NumberLiteral(1.into())),
3520 token(TokenKind::Eof)
3521 ],
3522 Ok(vec![
3523 Shared::new(Node {
3524 token_id: 3.into(),
3525 expr: Shared::new(Expr::Assign(
3526 IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
3527 Shared::new(Node {
3528 token_id: 3.into(),
3529 expr: Shared::new(Expr::Call(
3530 IdentWithToken::new_with_token(constants::builtins::SET, Some(Shared::new(token(TokenKind::PlusEqual)))),
3531 smallvec![
3532 Shared::new(Node {
3533 token_id: 0.into(),
3534 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
3535 }),
3536 Shared::new(Node {
3537 token_id: 1.into(),
3538 expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
3539 }),
3540 Shared::new(Node {
3541 token_id: 3.into(),
3542 expr: Shared::new(Expr::Call(
3543 IdentWithToken::new_with_token(constants::builtins::ADD, Some(Shared::new(token(TokenKind::PlusEqual)))),
3544 smallvec![
3545 Shared::new(Node {
3546 token_id: 2.into(),
3547 expr: Shared::new(Expr::Call(
3548 IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
3549 smallvec![
3550 Shared::new(Node {
3551 token_id: 0.into(),
3552 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
3553 }),
3554 Shared::new(Node {
3555 token_id: 1.into(),
3556 expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
3557 }),
3558 ],
3559 )),
3560 }),
3561 Shared::new(Node {
3562 token_id: 4.into(),
3563 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
3564 }),
3565 ],
3566 )),
3567 }),
3568 ],
3569 )),
3570 }),
3571 )),
3572 })
3573 ]))]
3574 #[case::index_double_slash_equal(
3575 vec![
3576 token(TokenKind::Ident(SmolStr::new("arr"))),
3577 token(TokenKind::LBracket),
3578 token(TokenKind::NumberLiteral(0.into())),
3579 token(TokenKind::RBracket),
3580 token(TokenKind::DoubleSlashEqual),
3581 token(TokenKind::NumberLiteral(2.into())),
3582 token(TokenKind::Eof)
3583 ],
3584 Ok(vec![
3586 Shared::new(Node {
3587 token_id: 3.into(),
3588 expr: Shared::new(Expr::Assign(
3589 IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
3590 Shared::new(Node {
3591 token_id: 3.into(),
3592 expr: Shared::new(Expr::Call(
3593 IdentWithToken::new_with_token(constants::builtins::SET, Some(Shared::new(token(TokenKind::DoubleSlashEqual)))),
3594 smallvec![
3595 Shared::new(Node {
3596 token_id: 0.into(),
3597 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
3598 }),
3599 Shared::new(Node {
3600 token_id: 1.into(),
3601 expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
3602 }),
3603 Shared::new(Node {
3604 token_id: 3.into(),
3605 expr: Shared::new(Expr::Call(
3606 IdentWithToken::new_with_token(constants::builtins::FLOOR, Some(Shared::new(token(TokenKind::DoubleSlashEqual)))),
3607 smallvec![Shared::new(Node {
3608 token_id: 3.into(),
3609 expr: Shared::new(Expr::Call(
3610 IdentWithToken::new_with_token(constants::builtins::DIV, Some(Shared::new(token(TokenKind::DoubleSlashEqual)))),
3611 smallvec![
3612 Shared::new(Node {
3613 token_id: 2.into(),
3614 expr: Shared::new(Expr::Call(
3615 IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
3616 smallvec![
3617 Shared::new(Node {
3618 token_id: 0.into(),
3619 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
3620 }),
3621 Shared::new(Node {
3622 token_id: 1.into(),
3623 expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
3624 }),
3625 ],
3626 )),
3627 }),
3628 Shared::new(Node {
3629 token_id: 4.into(),
3630 expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
3631 }),
3632 ],
3633 )),
3634 })],
3635 )),
3636 }),
3637 ],
3638 )),
3639 }),
3640 )),
3641 })
3642 ]))]
3643 #[case::root_semicolon_error(
3644 vec![
3645 token(TokenKind::Ident(SmolStr::new("x"))),
3646 token(TokenKind::SemiColon),
3647 token(TokenKind::Ident(SmolStr::new("y"))),
3648 token(TokenKind::Eof)
3649 ],
3650 Err(SyntaxError::UnexpectedToken(token(TokenKind::Ident(SmolStr::new("y"))))))]
3651 #[case::if_1(
3652 vec![
3653 token(TokenKind::If),
3654 token(TokenKind::LParen),
3655 token(TokenKind::BoolLiteral(true)),
3656 token(TokenKind::RParen),
3657 token(TokenKind::Colon),
3658 token(TokenKind::StringLiteral("true branch".to_owned())),
3659 token(TokenKind::Else),
3660 token(TokenKind::Colon),
3661 token(TokenKind::StringLiteral("false branch".to_owned())),
3662 token(TokenKind::Eof)
3663 ],
3664 Ok(vec![
3665 Shared::new(Node {
3666 token_id: 7.into(),
3667 expr: Shared::new(Expr::If(smallvec![
3668 (
3669 Some(Shared::new(Node {
3670 token_id: 1.into(),
3671 expr: Shared::new(Expr::Literal(Literal::Bool(true))),
3672 })),
3673 Shared::new(Node {
3674 token_id: 3.into(),
3675 expr: Shared::new(Expr::Literal(Literal::String("true branch".to_owned()))),
3676 })
3677 ),
3678 (
3679 None,
3680 Shared::new(Node {
3681 token_id: 6.into(),
3682 expr: Shared::new(Expr::Literal(Literal::String("false branch".to_owned()))),
3683 })
3684 )
3685 ])),
3686 })
3687 ]))]
3688 #[case::if_elif_else(
3689 vec![
3690 token(TokenKind::If),
3691 token(TokenKind::LParen),
3692 token(TokenKind::BoolLiteral(true)),
3693 token(TokenKind::RParen),
3694 token(TokenKind::Colon),
3695 token(TokenKind::StringLiteral("true branch".to_owned())),
3696 token(TokenKind::Elif),
3697 token(TokenKind::LParen),
3698 token(TokenKind::BoolLiteral(false)),
3699 token(TokenKind::RParen),
3700 token(TokenKind::Colon),
3701 token(TokenKind::StringLiteral("elif branch".to_owned())),
3702 token(TokenKind::Else),
3703 token(TokenKind::Colon),
3704 token(TokenKind::StringLiteral("else branch".to_owned())),
3705 token(TokenKind::Eof)
3706 ],
3707 Ok(vec![
3708 Shared::new(Node {
3709 token_id: 11.into(),
3710 expr: Shared::new(Expr::If(smallvec![
3711 (
3712 Some(Shared::new(Node {
3713 token_id: 1.into(),
3714 expr: Shared::new(Expr::Literal(Literal::Bool(true))),
3715 })),
3716 Shared::new(Node {
3717 token_id: 3.into(),
3718 expr: Shared::new(Expr::Literal(Literal::String("true branch".to_owned()))),
3719 })
3720 ),
3721 (
3722 Some(Shared::new(Node {
3723 token_id: 5.into(),
3724 expr: Shared::new(Expr::Literal(Literal::Bool(false))),
3725 })),
3726 Shared::new(Node {
3727 token_id: 7.into(),
3728 expr: Shared::new(Expr::Literal(Literal::String("elif branch".to_owned()))),
3729 })
3730 ),
3731 (
3732 None,
3733 Shared::new(Node {
3734 token_id: 10.into(),
3735 expr: Shared::new(Expr::Literal(Literal::String("else branch".to_owned()))),
3736 })
3737 )
3738 ])),
3739 })
3740 ]))]
3741 #[case::if_only(
3742 vec![
3743 token(TokenKind::If),
3744 token(TokenKind::LParen),
3745 token(TokenKind::BoolLiteral(true)),
3746 token(TokenKind::RParen),
3747 token(TokenKind::Colon),
3748 token(TokenKind::StringLiteral("true branch".to_owned())),
3749 token(TokenKind::Eof)
3750 ],
3751 Ok(vec![
3752 Shared::new(Node {
3753 token_id: 4.into(),
3754 expr: Shared::new(Expr::If(smallvec![
3755 (
3756 Some(Shared::new(Node {
3757 token_id: 1.into(),
3758 expr: Shared::new(Expr::Literal(Literal::Bool(true))),
3759 })),
3760 Shared::new(Node {
3761 token_id: 3.into(),
3762 expr: Shared::new(Expr::Literal(Literal::String("true branch".to_owned()))),
3763 })
3764 ),
3765 ])),
3766 })
3767 ]))]
3768 #[case::if_elif(
3769 vec![
3770 token(TokenKind::If),
3771 token(TokenKind::LParen),
3772 token(TokenKind::BoolLiteral(true)),
3773 token(TokenKind::RParen),
3774 token(TokenKind::Colon),
3775 token(TokenKind::StringLiteral("true branch".to_owned())),
3776 token(TokenKind::Elif),
3777 token(TokenKind::LParen),
3778 token(TokenKind::BoolLiteral(true)),
3779 token(TokenKind::RParen),
3780 token(TokenKind::Colon),
3781 token(TokenKind::StringLiteral("true branch".to_owned())),
3782 token(TokenKind::Eof)
3783 ],
3784 Ok(vec![
3785 Shared::new(Node {
3786 token_id: 8.into(),
3787 expr: Shared::new(Expr::If(smallvec![
3788 (
3789 Some(Shared::new(Node {
3790 token_id: 1.into(),
3791 expr: Shared::new(Expr::Literal(Literal::Bool(true))),
3792 })),
3793 Shared::new(Node {
3794 token_id: 3.into(),
3795 expr: Shared::new(Expr::Literal(Literal::String("true branch".to_owned()))),
3796 })
3797 ),
3798 (
3799 Some(Shared::new(Node {
3800 token_id: 5.into(),
3801 expr: Shared::new(Expr::Literal(Literal::Bool(true))),
3802 })),
3803 Shared::new(Node {
3804 token_id: 7.into(),
3805 expr: Shared::new(Expr::Literal(Literal::String("true branch".to_owned()))),
3806 })
3807 ),
3808 ])),
3809 })
3810 ]))]
3811 #[case::if_error(
3812 vec![
3813 token(TokenKind::If),
3814 token(TokenKind::LParen),
3815 token(TokenKind::BoolLiteral(true)),
3816 token(TokenKind::RParen),
3817 token(TokenKind::Colon),
3818 token(TokenKind::StringLiteral("true branch".to_owned())),
3819 token(TokenKind::Elif),
3820 token(TokenKind::LParen),
3821 token(TokenKind::BoolLiteral(false)),
3822 token(TokenKind::RParen),
3823 token(TokenKind::Colon),
3824 token(TokenKind::StringLiteral("elif branch".to_owned())),
3825 token(TokenKind::Else),
3826 token(TokenKind::Colon),
3827 token(TokenKind::Eof)
3828 ],
3829 Err(SyntaxError::UnexpectedEOFDetected(0.into())))]
3830 #[case::if_error(
3831 vec![
3832 token(TokenKind::If),
3833 token(TokenKind::LParen),
3834 token(TokenKind::RParen),
3835 token(TokenKind::Colon),
3836 token(TokenKind::StringLiteral("true branch".to_owned())),
3837 token(TokenKind::Elif),
3838 token(TokenKind::LParen),
3839 token(TokenKind::BoolLiteral(false)),
3840 token(TokenKind::RParen),
3841 token(TokenKind::Colon),
3842 token(TokenKind::StringLiteral("elif branch".to_owned())),
3843 token(TokenKind::Else),
3844 token(TokenKind::Colon),
3845 token(TokenKind::Eof)
3846 ],
3847 Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind:TokenKind::If, module_id: 1.into()})))]
3848 #[case::elif_error(
3849 vec![
3850 token(TokenKind::If),
3851 token(TokenKind::LParen),
3852 token(TokenKind::BoolLiteral(true)),
3853 token(TokenKind::RParen),
3854 token(TokenKind::Colon),
3855 token(TokenKind::StringLiteral("true branch".to_owned())),
3856 token(TokenKind::Elif),
3857 token(TokenKind::LParen),
3858 token(TokenKind::RParen),
3859 token(TokenKind::Colon),
3860 token(TokenKind::StringLiteral("elif branch".to_owned())),
3861 token(TokenKind::Else),
3862 token(TokenKind::Colon),
3863 token(TokenKind::Eof)
3864 ],
3865 Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind:TokenKind::Elif, module_id: 1.into()})))]
3866 #[case::h_selector(
3867 vec![
3868 token(TokenKind::Selector(SmolStr::new(".h"))),
3869 token(TokenKind::Eof)
3870 ],
3871 Ok(vec![
3872 Shared::new(Node {
3873 token_id: 2.into(),
3874 expr: Shared::new(Expr::Selector(Selector::Heading(None))),
3875 })
3876 ]))]
3877 #[case::h_selector_without_number(
3878 vec![
3879 token(TokenKind::Selector(SmolStr::new(".h"))),
3880 token(TokenKind::Eof)
3881 ],
3882 Ok(vec![
3883 Shared::new(Node {
3884 token_id: 1.into(),
3885 expr: Shared::new(Expr::Selector(Selector::Heading(None))),
3886 })
3887 ]))]
3888 #[case::while_(
3889 vec![
3890 token(TokenKind::While),
3891 token(TokenKind::LParen),
3892 token(TokenKind::BoolLiteral(true)),
3893 token(TokenKind::RParen),
3894 token(TokenKind::Colon),
3895 token(TokenKind::StringLiteral("loop body".to_owned())),
3896 token(TokenKind::SemiColon),
3897 ],
3898 Ok(vec![Shared::new(Node {
3899 token_id: 0.into(),
3900 expr: Shared::new(Expr::While(
3901 Shared::new(Node {
3902 token_id: 1.into(),
3903 expr: Shared::new(Expr::Literal(Literal::Bool(true))),
3904 }),
3905 vec![Shared::new(Node {
3906 token_id: 3.into(),
3907 expr: Shared::new(Expr::Literal(Literal::String("loop body".to_owned()))),
3908 })],
3909 )),
3910 })]))]
3911 #[case::while_error(
3912 vec![
3913 token(TokenKind::While),
3914 token(TokenKind::LParen),
3915 token(TokenKind::RParen),
3916 token(TokenKind::Colon),
3917 token(TokenKind::StringLiteral("loop body".to_owned())),
3918 token(TokenKind::SemiColon),
3919 ],
3920 Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind:TokenKind::While, module_id: 1.into()})))]
3921 #[case::while_error(
3922 vec![
3923 token(TokenKind::While),
3924 token(TokenKind::LParen),
3925 token(TokenKind::BoolLiteral(true)),
3926 token(TokenKind::RParen),
3927 token(TokenKind::Colon),
3928 ],
3929 Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind:TokenKind::While, module_id: 1.into()})))]
3930 #[case::while_do_end(
3931 vec![
3932 token(TokenKind::While),
3933 token(TokenKind::LParen),
3934 token(TokenKind::BoolLiteral(true)),
3935 token(TokenKind::RParen),
3936 token(TokenKind::Do),
3937 token(TokenKind::StringLiteral("loop body".to_owned())),
3938 token(TokenKind::End),
3939 ],
3940 Ok(vec![Shared::new(Node {
3941 token_id: 0.into(),
3942 expr: Shared::new(Expr::While(
3943 Shared::new(Node {
3944 token_id: 1.into(),
3945 expr: Shared::new(Expr::Literal(Literal::Bool(true))),
3946 }),
3947 vec![Shared::new(Node {
3948 token_id: 3.into(),
3949 expr: Shared::new(Expr::Literal(Literal::String("loop body".to_owned()))),
3950 })],
3951 )),
3952 })]))]
3953 #[case::loop_(
3954 vec![
3955 token(TokenKind::Loop),
3956 token(TokenKind::Colon),
3957 token(TokenKind::StringLiteral("loop body".to_owned())),
3958 token(TokenKind::SemiColon),
3959 ],
3960 Ok(vec![Shared::new(Node {
3961 token_id: 1.into(),
3962 expr: Shared::new(Expr::Loop(
3963 vec![Shared::new(Node {
3964 token_id: 2.into(),
3965 expr: Shared::new(Expr::Literal(Literal::String("loop body".to_owned()))),
3966 })],
3967 )),
3968 })]))]
3969 #[case::loop_error_no_body(
3970 vec![
3971 token(TokenKind::Loop),
3972 token(TokenKind::Colon),
3973 ],
3974 Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind:TokenKind::Loop, module_id: 1.into()})))]
3975 #[case::try_catch(
3976 vec![
3977 token(TokenKind::Try),
3978 token(TokenKind::Colon),
3979 token(TokenKind::Ident(SmolStr::new("error_expr"))),
3980 token(TokenKind::Catch),
3981 token(TokenKind::Colon),
3982 token(TokenKind::StringLiteral("fallback".to_owned())),
3983 token(TokenKind::Eof),
3984 ],
3985 Ok(vec![Shared::new(Node {
3986 token_id: 2.into(),
3987 expr: Shared::new(Expr::Try(
3988 Shared::new(Node {
3989 token_id: 2.into(),
3990 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("error_expr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("error_expr")))))))),
3991 }),
3992 Shared::new(Node {
3993 token_id: 5.into(),
3994 expr: Shared::new(Expr::Literal(Literal::String("fallback".to_owned()))),
3995 }),
3996 )),
3997 })]))]
3998 #[case::foreach(
3999 vec![
4000 token(TokenKind::Foreach),
4001 token(TokenKind::LParen),
4002 token(TokenKind::Ident(SmolStr::new("item"))),
4003 token(TokenKind::Comma),
4004 token(TokenKind::StringLiteral("array".to_owned())),
4005 token(TokenKind::RParen),
4006 token(TokenKind::Colon),
4007 token(TokenKind::Ident(SmolStr::new("print"))),
4008 token(TokenKind::LParen),
4009 token(TokenKind::Ident(SmolStr::new("item"))),
4010 token(TokenKind::RParen),
4011 token(TokenKind::SemiColon),
4012 ],
4013 Ok(vec![Shared::new(Node {
4014 token_id: 6.into(),
4015 expr: Shared::new(Expr::Foreach(
4016 IdentWithToken::new_with_token(
4017 "item",
4018 Some(Shared::new(token(TokenKind::Ident(SmolStr::new("item"))))),
4019 ),
4020 Shared::new(Node {
4021 token_id: 1.into(),
4022 expr: Shared::new(Expr::Literal(Literal::String("array".to_owned()))),
4023 }),
4024 vec![Shared::new(Node {
4025 token_id: 4.into(),
4026 expr: Shared::new(Expr::Call(
4027 IdentWithToken::new_with_token(
4028 "print",
4029 Some(Shared::new(token(TokenKind::Ident(SmolStr::new(
4030 "print",
4031 ))))),
4032 ),
4033 smallvec![Shared::new(Node {
4034 token_id: 3.into(),
4035 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token(
4036 "item",
4037 Some(Shared::new(token(TokenKind::Ident(SmolStr::new("item"))))),
4038 ))),
4039 })],
4040 )),
4041 })],
4042 )),
4043 })]))]
4044 #[case::foreach(
4045 vec![
4046 token(TokenKind::Foreach),
4047 token(TokenKind::LParen),
4048 token(TokenKind::RParen),
4049 token(TokenKind::Colon),
4050 token(TokenKind::Ident(SmolStr::new("print"))),
4051 token(TokenKind::LParen),
4052 token(TokenKind::Ident(SmolStr::new("item"))),
4053 token(TokenKind::RParen),
4054 token(TokenKind::SemiColon),
4055 ],
4056 Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind:TokenKind::Foreach, module_id: 1.into()})))]
4057 #[case::foreach_do_end(
4058 vec![
4059 token(TokenKind::Foreach),
4060 token(TokenKind::LParen),
4061 token(TokenKind::Ident(SmolStr::new("item"))),
4062 token(TokenKind::Comma),
4063 token(TokenKind::StringLiteral("array".to_owned())),
4064 token(TokenKind::RParen),
4065 token(TokenKind::Do),
4066 token(TokenKind::Ident(SmolStr::new("print"))),
4067 token(TokenKind::LParen),
4068 token(TokenKind::Ident(SmolStr::new("item"))),
4069 token(TokenKind::RParen),
4070 token(TokenKind::End),
4071 ],
4072 Ok(vec![Shared::new(Node {
4073 token_id: 6.into(),
4074 expr: Shared::new(Expr::Foreach(
4075 IdentWithToken::new_with_token(
4076 "item",
4077 Some(Shared::new(token(TokenKind::Ident(SmolStr::new("item"))))),
4078 ),
4079 Shared::new(Node {
4080 token_id: 1.into(),
4081 expr: Shared::new(Expr::Literal(Literal::String("array".to_owned()))),
4082 }),
4083 vec![Shared::new(Node {
4084 token_id: 4.into(),
4085 expr: Shared::new(Expr::Call(
4086 IdentWithToken::new_with_token(
4087 "print",
4088 Some(Shared::new(token(TokenKind::Ident(SmolStr::new(
4089 "print",
4090 ))))),
4091 ),
4092 smallvec![Shared::new(Node {
4093 token_id: 3.into(),
4094 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token(
4095 "item",
4096 Some(Shared::new(token(TokenKind::Ident(SmolStr::new("item"))))),
4097 ))),
4098 })],
4099 )),
4100 })],
4101 )),
4102 })]))]
4103 #[case::self_(
4104 vec![token(TokenKind::Self_), token(TokenKind::Eof)],
4105 Ok(vec![Shared::new(Node {
4106 token_id: 0.into(),
4107 expr: Shared::new(Expr::Self_),
4108 })]))]
4109 #[case::include(
4110 vec![
4111 token(TokenKind::Include),
4112 token(TokenKind::StringLiteral("module_name".to_owned())),
4113 token(TokenKind::Eof),
4114 ],
4115 Ok(vec![Shared::new(Node {
4116 token_id: 0.into(),
4117 expr: Shared::new(Expr::Include(Literal::String("module_name".to_owned()))),
4118 })]))]
4119 #[case::code_selector_with_language(
4120 vec![
4121 token(TokenKind::Selector(SmolStr::new(".code"))),
4122 token(TokenKind::Eof),
4123 ],
4124 Ok(vec![Shared::new(Node {
4125 token_id: 2.into(),
4126 expr: Shared::new(Expr::Selector(Selector::Code)),
4127 })]))]
4128 #[case::selector_call_heading_single_arg(
4129 vec![
4130 token(TokenKind::Selector(SmolStr::new(".h"))),
4131 token(TokenKind::LParen),
4132 token(TokenKind::NumberLiteral(1.into())),
4133 token(TokenKind::RParen),
4134 token(TokenKind::Eof),
4135 ],
4136 Ok(vec![Shared::new(Node {
4137 token_id: 1.into(),
4138 expr: Shared::new(Expr::SelectorCall(
4139 Selector::Heading(None),
4140 smallvec![Shared::new(Node {
4142 token_id: 0.into(),
4143 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
4144 })],
4145 )),
4146 })]))]
4147 #[case::selector_call_heading_multi_arg(
4148 vec![
4149 token(TokenKind::Selector(SmolStr::new(".h"))),
4150 token(TokenKind::LParen),
4151 token(TokenKind::NumberLiteral(1.into())),
4152 token(TokenKind::Comma),
4153 token(TokenKind::NumberLiteral(2.into())),
4154 token(TokenKind::RParen),
4155 token(TokenKind::Eof),
4156 ],
4157 Ok(vec![Shared::new(Node {
4158 token_id: 2.into(),
4159 expr: Shared::new(Expr::SelectorCall(
4160 Selector::Heading(None),
4161 smallvec![
4163 Shared::new(Node {
4164 token_id: 0.into(),
4165 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
4166 }),
4167 Shared::new(Node {
4168 token_id: 1.into(),
4169 expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
4170 }),
4171 ],
4172 )),
4173 })]))]
4174 #[case::selector_call_code_lang(
4175 vec![
4176 token(TokenKind::Selector(SmolStr::new(".code"))),
4177 token(TokenKind::LParen),
4178 token(TokenKind::StringLiteral("rust".to_owned())),
4179 token(TokenKind::RParen),
4180 token(TokenKind::Eof),
4181 ],
4182 Ok(vec![Shared::new(Node {
4183 token_id: 1.into(),
4184 expr: Shared::new(Expr::SelectorCall(
4185 Selector::Code,
4186 smallvec![Shared::new(Node {
4188 token_id: 0.into(),
4189 expr: Shared::new(Expr::Literal(Literal::String("rust".to_owned()))),
4190 })],
4191 )),
4192 })]))]
4193 #[case::selector_call_with_attribute(
4194 vec![
4195 token(TokenKind::Selector(SmolStr::new(".h"))),
4196 token(TokenKind::LParen),
4197 token(TokenKind::NumberLiteral(1.into())),
4198 token(TokenKind::RParen),
4199 token(TokenKind::Selector(SmolStr::new(".level"))),
4200 token(TokenKind::Eof),
4201 ],
4202 Ok(vec![Shared::new(Node {
4203 token_id: 3.into(),
4205 expr: Shared::new(Expr::Call(
4206 IdentWithToken::new_with_token(
4207 constants::builtins::ATTR,
4208 Some(Shared::new(token(TokenKind::Selector(SmolStr::new(".h"))))),
4209 ),
4210 smallvec![
4211 Shared::new(Node {
4212 token_id: 1.into(),
4213 expr: Shared::new(Expr::SelectorCall(
4214 Selector::Heading(None),
4215 smallvec![Shared::new(Node {
4216 token_id: 0.into(),
4217 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
4218 })],
4219 )),
4220 }),
4221 Shared::new(Node {
4222 token_id: 2.into(),
4223 expr: Shared::new(Expr::Literal(Literal::String("level".to_owned()))),
4224 }),
4225 ],
4226 )),
4227 })]))]
4228 #[case::selector_call_code_with_lang_attribute(
4229 vec![
4230 token(TokenKind::Selector(SmolStr::new(".code"))),
4231 token(TokenKind::LParen),
4232 token(TokenKind::StringLiteral("rust".to_owned())),
4233 token(TokenKind::RParen),
4234 token(TokenKind::Selector(SmolStr::new(".lang"))),
4235 token(TokenKind::Eof),
4236 ],
4237 Ok(vec![Shared::new(Node {
4238 token_id: 3.into(),
4240 expr: Shared::new(Expr::Call(
4241 IdentWithToken::new_with_token(
4242 constants::builtins::ATTR,
4243 Some(Shared::new(token(TokenKind::Selector(SmolStr::new(".code"))))),
4244 ),
4245 smallvec![
4246 Shared::new(Node {
4247 token_id: 1.into(),
4248 expr: Shared::new(Expr::SelectorCall(
4249 Selector::Code,
4250 smallvec![Shared::new(Node {
4251 token_id: 0.into(),
4252 expr: Shared::new(Expr::Literal(Literal::String("rust".to_owned()))),
4253 })],
4254 )),
4255 }),
4256 Shared::new(Node {
4257 token_id: 2.into(),
4258 expr: Shared::new(Expr::Literal(Literal::String("lang".to_owned()))),
4259 }),
4260 ],
4261 )),
4262 })]))]
4263 #[case::table_selector(
4264 vec![
4265 token(TokenKind::Selector(SmolStr::new("."))),
4266 token(TokenKind::LBracket),
4267 token(TokenKind::NumberLiteral(1.into())),
4268 token(TokenKind::RBracket),
4269 token(TokenKind::LBracket),
4270 token(TokenKind::NumberLiteral(2.into())),
4271 token(TokenKind::RBracket),
4272 token(TokenKind::Eof),
4273 ],
4274 Ok(vec![Shared::new(Node {
4275 token_id: 8.into(),
4276 expr: Shared::new(Expr::Selector(Selector::Table(Some(1), Some(2)))),
4277 })]))]
4278 #[case::selector_call_list_bracket_single_arg(
4279 vec![
4280 token(TokenKind::Selector(SmolStr::new("."))),
4281 token(TokenKind::LBracket),
4282 token(TokenKind::RBracket),
4283 token(TokenKind::LParen),
4284 token(TokenKind::NumberLiteral(2.into())),
4285 token(TokenKind::RParen),
4286 token(TokenKind::Eof),
4287 ],
4288 Ok(vec![Shared::new(Node {
4289 token_id: 2.into(),
4290 expr: Shared::new(Expr::SelectorCall(
4291 Selector::List(None, None),
4292 smallvec![Shared::new(Node {
4293 token_id: 1.into(),
4294 expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
4295 })],
4296 )),
4297 })]))]
4298 #[case::selector_call_table_bracket_single_arg(
4299 vec![
4300 token(TokenKind::Selector(SmolStr::new("."))),
4301 token(TokenKind::LBracket),
4302 token(TokenKind::RBracket),
4303 token(TokenKind::LBracket),
4304 token(TokenKind::RBracket),
4305 token(TokenKind::LParen),
4306 token(TokenKind::NumberLiteral(1.into())),
4307 token(TokenKind::RParen),
4308 token(TokenKind::Eof),
4309 ],
4310 Ok(vec![Shared::new(Node {
4311 token_id: 3.into(),
4312 expr: Shared::new(Expr::SelectorCall(
4313 Selector::Table(None, None),
4314 smallvec![Shared::new(Node {
4315 token_id: 2.into(),
4316 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
4317 })],
4318 )),
4319 })]))]
4320 #[case::selector_call_list_bracket_variable(
4321 vec![
4322 token(TokenKind::Selector(SmolStr::new("."))),
4323 token(TokenKind::LBracket),
4324 token(TokenKind::Ident(SmolStr::new("v"))),
4325 token(TokenKind::RBracket),
4326 token(TokenKind::Eof),
4327 ],
4328 Ok(vec![Shared::new(Node {
4329 token_id: 3.into(),
4330 expr: Shared::new(Expr::SelectorCall(
4331 Selector::List(None, None),
4332 smallvec![Shared::new(Node {
4333 token_id: 1.into(),
4334 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token(
4335 "v",
4336 Some(Shared::new(token(TokenKind::Ident(SmolStr::new("v"))))),
4337 ))),
4338 })],
4339 )),
4340 })]))]
4341 #[case::selector_call_table_bracket_column_variable(
4342 vec![
4343 token(TokenKind::Selector(SmolStr::new("."))),
4344 token(TokenKind::LBracket),
4345 token(TokenKind::RBracket),
4346 token(TokenKind::LBracket),
4347 token(TokenKind::Ident(SmolStr::new("v"))),
4348 token(TokenKind::RBracket),
4349 token(TokenKind::Eof),
4350 ],
4351 Ok(vec![Shared::new(Node {
4352 token_id: 5.into(),
4353 expr: Shared::new(Expr::SelectorCall(
4354 Selector::Table(None, None),
4355 smallvec![
4356 Shared::new(Node {
4357 token_id: 4.into(),
4358 expr: Shared::new(Expr::Literal(Literal::None)),
4359 }),
4360 Shared::new(Node {
4361 token_id: 2.into(),
4362 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token(
4363 "v",
4364 Some(Shared::new(token(TokenKind::Ident(SmolStr::new("v"))))),
4365 ))),
4366 }),
4367 ],
4368 )),
4369 })]))]
4370 #[case::selector_call_table_bracket_variable(
4371 vec![
4372 token(TokenKind::Selector(SmolStr::new("."))),
4373 token(TokenKind::LBracket),
4374 token(TokenKind::Ident(SmolStr::new("v"))),
4375 token(TokenKind::RBracket),
4376 token(TokenKind::LBracket),
4377 token(TokenKind::RBracket),
4378 token(TokenKind::Eof),
4379 ],
4380 Ok(vec![Shared::new(Node {
4381 token_id: 4.into(),
4382 expr: Shared::new(Expr::SelectorCall(
4383 Selector::Table(None, None),
4384 smallvec![Shared::new(Node {
4385 token_id: 1.into(),
4386 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token(
4387 "v",
4388 Some(Shared::new(token(TokenKind::Ident(SmolStr::new("v"))))),
4389 ))),
4390 })],
4391 )),
4392 })]))]
4393 #[case::selector_call_table_bracket_row_col_args(
4394 vec![
4395 token(TokenKind::Selector(SmolStr::new("."))),
4396 token(TokenKind::LBracket),
4397 token(TokenKind::RBracket),
4398 token(TokenKind::LBracket),
4399 token(TokenKind::RBracket),
4400 token(TokenKind::LParen),
4401 token(TokenKind::NumberLiteral(1.into())),
4402 token(TokenKind::Comma),
4403 token(TokenKind::NumberLiteral(2.into())),
4404 token(TokenKind::RParen),
4405 token(TokenKind::Eof),
4406 ],
4407 Ok(vec![Shared::new(Node {
4408 token_id: 4.into(),
4409 expr: Shared::new(Expr::SelectorCall(
4410 Selector::Table(None, None),
4411 smallvec![
4412 Shared::new(Node {
4413 token_id: 2.into(),
4414 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
4415 }),
4416 Shared::new(Node {
4417 token_id: 3.into(),
4418 expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
4419 }),
4420 ],
4421 )),
4422 })]))]
4423 #[case::foreach_error(
4424 vec![
4425 token(TokenKind::Foreach),
4426 token(TokenKind::LParen),
4427 token(TokenKind::Ident(SmolStr::new("item"))),
4428 token(TokenKind::Comma),
4429 token(TokenKind::StringLiteral("array".to_owned())),
4430 token(TokenKind::RParen),
4431 token(TokenKind::Colon),
4432 token(TokenKind::Eof),
4433 ],
4434 Err(SyntaxError::UnexpectedEOFDetected(Module::TOP_LEVEL_MODULE_ID)))]
4435 #[case::while_error(
4436 vec![
4437 token(TokenKind::While),
4438 token(TokenKind::LParen),
4439 token(TokenKind::BoolLiteral(true)),
4440 token(TokenKind::RParen),
4441 token(TokenKind::Colon),
4442 token(TokenKind::Eof),
4443 ],
4444 Err(SyntaxError::UnexpectedEOFDetected(Module::TOP_LEVEL_MODULE_ID)))]
4445 #[case::using_reserved_keyword_let(
4446 vec![
4447 token(TokenKind::Let),
4448 token(TokenKind::If), token(TokenKind::Equal),
4450 token(TokenKind::NumberLiteral(42.into())),
4451 token(TokenKind::Eof)
4452 ],
4453 Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::If, module_id: 1.into()})))]
4454 #[case::using_reserved_keyword_while(
4455 vec![
4456 token(TokenKind::Let),
4457 token(TokenKind::While), token(TokenKind::Equal),
4459 token(TokenKind::NumberLiteral(42.into())),
4460 token(TokenKind::Eof)
4461 ],
4462 Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::While, module_id: 1.into()})))]
4463 #[case::using_reserved_keyword_def(
4464 vec![
4465 token(TokenKind::Let),
4466 token(TokenKind::Def), token(TokenKind::Equal),
4468 token(TokenKind::NumberLiteral(42.into())),
4469 token(TokenKind::Eof)
4470 ],
4471 Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::Def, module_id: 1.into()})))]
4472 #[case::using_reserved_keyword_include(
4473 vec![
4474 token(TokenKind::Let),
4475 token(TokenKind::Include), token(TokenKind::Equal),
4477 token(TokenKind::NumberLiteral(42.into())),
4478 token(TokenKind::Eof)
4479 ],
4480 Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::Include, module_id: 1.into()})))]
4481 #[case::nodes(
4482 vec![
4483 token(TokenKind::Nodes),
4484 token(TokenKind::Eof)
4485 ],
4486 Ok(vec![
4487 Shared::new(Node {
4488 token_id: 0.into(),
4489 expr: Shared::new(Expr::Nodes),
4490 })
4491 ]))]
4492 #[case::nodes_error_in_subprogram(
4493 vec![
4494 token(TokenKind::Def),
4495 token(TokenKind::Ident(SmolStr::new("test"))),
4496 token(TokenKind::LParen),
4497 token(TokenKind::RParen),
4498 token(TokenKind::Colon),
4499 token(TokenKind::Nodes),
4500 token(TokenKind::SemiColon)
4501 ],
4502 Err(SyntaxError::UnexpectedToken(token(TokenKind::Nodes))))]
4503 #[case::nodes_then_selector(
4504 vec![
4505 token(TokenKind::Nodes),
4506 token(TokenKind::Pipe),
4507 token(TokenKind::Selector(SmolStr::new(".h1"))),
4508 token(TokenKind::Eof)
4509 ],
4510 Ok(vec![
4511 Shared::new(Node {
4512 token_id: 0.into(),
4513 expr: Shared::new(Expr::Nodes),
4514 }),
4515 Shared::new(Node {
4516 token_id: 1.into(),
4517 expr: Shared::new(Expr::Selector(Selector::Heading(Some(1)))),
4518 })
4519 ]))]
4520 #[case::root_level_with_multiple_pipes(
4521 vec![
4522 token(TokenKind::Nodes),
4523 token(TokenKind::Pipe),
4524 token(TokenKind::Nodes),
4525 token(TokenKind::Pipe),
4526 token(TokenKind::Selector(SmolStr::new(".h1"))),
4527 token(TokenKind::Pipe),
4528 token(TokenKind::Selector(SmolStr::new(".text"))),
4529 token(TokenKind::Eof)
4530 ],
4531 Ok(vec![
4532 Shared::new(Node {
4533 token_id: 0.into(),
4534 expr: Shared::new(Expr::Nodes),
4535 }),
4536 Shared::new(Node {
4537 token_id: 1.into(),
4538 expr: Shared::new(Expr::Nodes),
4539 }),
4540 Shared::new(Node {
4541 token_id: 2.into(),
4542 expr: Shared::new(Expr::Selector(Selector::Heading(Some(1)))),
4543 }),
4544 Shared::new(Node {
4545 token_id: 3.into(),
4546 expr: Shared::new(Expr::Selector(Selector::Text)),
4547 })
4548 ]))]
4549 #[case::fn_simple(
4550 vec![
4551 token(TokenKind::Fn),
4552 token(TokenKind::LParen),
4553 token(TokenKind::RParen),
4554 token(TokenKind::Colon),
4555 token(TokenKind::StringLiteral("result".to_owned())),
4556 token(TokenKind::SemiColon),
4557 ],
4558 Ok(vec![
4559 Shared::new(Node {
4560 token_id: 0.into(),
4561 expr: Shared::new(Expr::Fn(
4562 SmallVec::new(),
4563 vec![
4564 Shared::new(Node {
4565 token_id: 2.into(),
4566 expr: Shared::new(Expr::Literal(Literal::String("result".to_owned()))),
4567 })
4568 ],
4569 )),
4570 })
4571 ]))]
4572 #[case::fn_with_args(
4573 vec![
4574 token(TokenKind::Fn),
4575 token(TokenKind::LParen),
4576 token(TokenKind::Ident(SmolStr::new("x"))),
4577 token(TokenKind::Comma),
4578 token(TokenKind::Ident(SmolStr::new("y"))),
4579 token(TokenKind::RParen),
4580 token(TokenKind::Colon),
4581 token(TokenKind::Ident(SmolStr::new("contains"))),
4582 token(TokenKind::LParen),
4583 token(TokenKind::Ident(SmolStr::new("x"))),
4584 token(TokenKind::Comma),
4585 token(TokenKind::Ident(SmolStr::new("y"))),
4586 token(TokenKind::RParen),
4587 token(TokenKind::SemiColon),
4588 ],
4589 Ok(vec![
4590 Shared::new(Node {
4591 token_id: 0.into(),
4592 expr: Shared::new(Expr::Fn(
4593 smallvec![
4594 Param::new(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x"))))))),
4595 Param::new(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y"))))))),
4596 ],
4597 vec![
4598 Shared::new(Node {
4599 token_id: 4.into(),
4600 expr: Shared::new(Expr::Call(
4601 IdentWithToken::new_with_token("contains", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("contains")))))),
4602 smallvec![
4603 Shared::new(Node {
4604 token_id: 2.into(),
4605 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
4606 }),
4607 Shared::new(Node {
4608 token_id: 3.into(),
4609 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y")))))))),
4610 }),
4611 ],
4612 )),
4613 })
4614 ],
4615 )),
4616 })
4617 ]))]
4618 #[case::fn_with_multiple_statements(
4619 vec![
4620 token(TokenKind::Fn),
4621 token(TokenKind::LParen),
4622 token(TokenKind::Ident(SmolStr::new("x"))),
4623 token(TokenKind::RParen),
4624 token(TokenKind::Colon),
4625 token(TokenKind::StringLiteral("first".to_owned())),
4626 token(TokenKind::Pipe),
4627 token(TokenKind::StringLiteral("second".to_owned())),
4628 token(TokenKind::SemiColon),
4629 ],
4630 Ok(vec![
4631 Shared::new(Node {
4632 token_id: 0.into(),
4633 expr: Shared::new(Expr::Fn(
4634 smallvec![
4635 Param::new(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x"))))))),
4636 ],
4637 vec![
4638 Shared::new(Node {
4639 token_id: 2.into(),
4640 expr: Shared::new(Expr::Literal(Literal::String("first".to_owned()))),
4641 }),
4642 Shared::new(Node {
4643 token_id: 3.into(),
4644 expr: Shared::new(Expr::Literal(Literal::String("second".to_owned()))),
4645 })
4646 ],
4647 )),
4648 })
4649 ]))]
4650 #[case::fn_with_invalid_args(
4651 vec![
4652 token(TokenKind::Fn),
4653 token(TokenKind::LParen),
4654 token(TokenKind::StringLiteral("invalid".to_owned())),
4655 token(TokenKind::RParen),
4656 token(TokenKind::Colon),
4657 token(TokenKind::StringLiteral("result".to_owned())),
4658 token(TokenKind::SemiColon),
4659 ],
4660 Err(SyntaxError::UnexpectedToken(token(TokenKind::StringLiteral("invalid".to_owned())))))]
4661 #[case::fn_without_body(
4662 vec![
4663 token(TokenKind::Fn),
4664 token(TokenKind::LParen),
4665 token(TokenKind::RParen),
4666 token(TokenKind::Colon),
4667 token(TokenKind::SemiColon),
4668 ],
4669 Err(SyntaxError::UnexpectedToken(token(TokenKind::SemiColon))))]
4670 #[case::fn_nested_in_call(
4671 vec![
4672 token(TokenKind::Ident(SmolStr::new("apply"))),
4673 token(TokenKind::LParen),
4674 token(TokenKind::Fn),
4675 token(TokenKind::LParen),
4676 token(TokenKind::Ident(SmolStr::new("x"))),
4677 token(TokenKind::RParen),
4678 token(TokenKind::Colon),
4679 token(TokenKind::StringLiteral("processed".to_owned())),
4680 token(TokenKind::SemiColon),
4681 token(TokenKind::RParen),
4682 token(TokenKind::Eof),
4683 ],
4684 Ok(vec![
4685 Shared::new(Node {
4686 token_id: 4.into(),
4687 expr: Shared::new(Expr::Call(
4688 IdentWithToken::new_with_token("apply", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("apply")))))),
4689 smallvec![
4690 Shared::new(Node {
4691 token_id: 0.into(),
4692 expr: Shared::new(Expr::Fn(
4693 smallvec![
4694 Param::new(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x"))))))),
4695 ],
4696 vec![
4697 Shared::new(Node {
4698 token_id: 2.into(),
4699 expr: Shared::new(Expr::Literal(Literal::String("processed".to_owned()))),
4700 })
4701 ],
4702 )),
4703 })
4704 ],
4705 )),
4706 })
4707 ]))]
4708 #[case::empty_array(
4709 vec![
4710 token(TokenKind::LBracket),
4711 token(TokenKind::RBracket),
4712 token(TokenKind::Eof)
4713 ],
4714 Ok(vec![
4715 Shared::new(Node {
4716 token_id: 0.into(),
4717 expr: Shared::new(Expr::Call(
4718 IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::LBracket)))),
4719 SmallVec::new(),
4720 )),
4721 })
4722 ]))]
4723 #[case::array_with_elements(
4724 vec![
4725 token(TokenKind::LBracket),
4726 token(TokenKind::StringLiteral("first".to_owned())),
4727 token(TokenKind::Comma),
4728 token(TokenKind::NumberLiteral(42.into())),
4729 token(TokenKind::RBracket),
4730 token(TokenKind::Eof)
4731 ],
4732 Ok(vec![
4733 Shared::new(Node {
4734 token_id: 0.into(),
4735 expr: Shared::new(Expr::Call(
4736 IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::LBracket)))),
4737 smallvec![
4738 Shared::new(Node {
4739 token_id: 1.into(),
4740 expr: Shared::new(Expr::Literal(Literal::String("first".to_owned()))),
4741 }),
4742 Shared::new(Node {
4743 token_id: 2.into(),
4744 expr: Shared::new(Expr::Literal(Literal::Number(42.into()))),
4745 }),
4746 ],
4747 )),
4748 })
4749 ]))]
4750 #[case::array_with_mixed_elements(
4751 vec![
4752 token(TokenKind::LBracket),
4753 token(TokenKind::StringLiteral("text".to_owned())),
4754 token(TokenKind::Comma),
4755 token(TokenKind::BoolLiteral(true)),
4756 token(TokenKind::Comma),
4757 token(TokenKind::None),
4758 token(TokenKind::RBracket),
4759 token(TokenKind::Eof)
4760 ],
4761 Ok(vec![
4762 Shared::new(Node {
4763 token_id: 0.into(),
4764 expr: Shared::new(Expr::Call(
4765 IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::LBracket)))),
4766 smallvec![
4767 Shared::new(Node {
4768 token_id: 1.into(),
4769 expr: Shared::new(Expr::Literal(Literal::String("text".to_owned()))),
4770 }),
4771 Shared::new(Node {
4772 token_id: 2.into(),
4773 expr: Shared::new(Expr::Literal(Literal::Bool(true))),
4774 }),
4775 Shared::new(Node {
4776 token_id: 3.into(),
4777 expr: Shared::new(Expr::Literal(Literal::None)),
4778 }),
4779 ],
4780 )),
4781 })
4782 ]))]
4783 #[case::array_with_nested_array(
4784 vec![
4785 token(TokenKind::LBracket),
4786 token(TokenKind::LBracket),
4787 token(TokenKind::NumberLiteral(1.into())),
4788 token(TokenKind::RBracket),
4789 token(TokenKind::Comma),
4790 token(TokenKind::LBracket),
4791 token(TokenKind::NumberLiteral(2.into())),
4792 token(TokenKind::RBracket),
4793 token(TokenKind::RBracket),
4794 token(TokenKind::Eof)
4795 ],
4796 Ok(vec![
4797 Shared::new(Node {
4798 token_id: 0.into(),
4799 expr: Shared::new(Expr::Call(
4800 IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::LBracket)))),
4801 smallvec![
4802 Shared::new(Node {
4803 token_id: 1.into(),
4804 expr: Shared::new(Expr::Call(
4805 IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::LBracket)))),
4806 smallvec![
4807 Shared::new(Node {
4808 token_id: 2.into(),
4809 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
4810 }),
4811 ],
4812 )),
4813 }),
4814 Shared::new(Node {
4815 token_id: 3.into(),
4816 expr: Shared::new(Expr::Call(
4817 IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::LBracket)))),
4818 smallvec![
4819 Shared::new(Node {
4820 token_id: 4.into(),
4821 expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
4822 }),
4823 ],
4824 )),
4825 }),
4826 ],
4827 )),
4828 })
4829 ]))]
4830 #[case::array_with_trailing_comma(
4831 vec![
4832 token(TokenKind::LBracket),
4833 token(TokenKind::StringLiteral("value".to_owned())),
4834 token(TokenKind::Comma),
4835 token(TokenKind::RBracket),
4836 token(TokenKind::Eof)
4837 ],
4838 Ok(vec![
4839 Shared::new(Node {
4840 token_id: 0.into(),
4841 expr: Shared::new(Expr::Call(
4842 IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::LBracket)))),
4843 smallvec![
4844 Shared::new(Node {
4845 token_id: 1.into(),
4846 expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
4847 }),
4848 ],
4849 )),
4850 })
4851 ]))]
4852 #[case::array_unclosed(
4853 vec![
4854 token(TokenKind::LBracket),
4855 token(TokenKind::StringLiteral("value".to_owned())),
4856 token(TokenKind::Eof)
4857 ],
4858 Err(SyntaxError::ExpectedClosingBracket(token(TokenKind::Eof), Some(Box::new(token(TokenKind::LBracket))))))]
4859 #[case::array_invalid_token(
4860 vec![
4861 token(TokenKind::LBracket),
4862 token(TokenKind::Pipe),
4863 token(TokenKind::RBracket),
4864 token(TokenKind::Eof)
4865 ],
4866 Err(SyntaxError::UnexpectedToken(token(TokenKind::Pipe))))]
4867 #[case::array_nested_unclosed(
4868 vec![
4869 token(TokenKind::LBracket),
4870 token(TokenKind::LBracket),
4871 token(TokenKind::StringLiteral("inner".to_owned())),
4872 token(TokenKind::RBracket),
4873 token(TokenKind::Eof)
4874 ],
4875 Err(SyntaxError::ExpectedClosingBracket(token(TokenKind::Eof), Some(Box::new(token(TokenKind::LBracket))))))]
4876 #[case::array_with_ident(
4877 vec![
4878 token(TokenKind::LBracket),
4879 token(TokenKind::Ident(SmolStr::new("foo"))),
4880 token(TokenKind::Comma),
4881 token(TokenKind::Ident(SmolStr::new("bar"))),
4882 token(TokenKind::RBracket),
4883 token(TokenKind::Eof)
4884 ],
4885 Ok(vec![
4886 Shared::new(Node {
4887 token_id: 0.into(),
4888 expr: Shared::new(Expr::Call(
4889 IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::LBracket)))),
4890 smallvec![
4891 Shared::new(Node {
4892 token_id: 1.into(),
4893 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("foo", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("foo")))))))),
4894 }),
4895 Shared::new(Node {
4896 token_id: 2.into(),
4897 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("bar", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("bar")))))))),
4898 }),
4899 ],
4900 )),
4901 })
4902 ]))]
4903 #[case::equality_simple(
4904 vec![
4905 token(TokenKind::StringLiteral("hello".to_owned())),
4906 token(TokenKind::EqEq),
4907 token(TokenKind::StringLiteral("world".to_owned())),
4908 token(TokenKind::Eof)
4909 ],
4910 Ok(vec![
4911 Shared::new(Node {
4912 token_id: 1.into(),
4913 expr: Shared::new(Expr::Call(
4914 IdentWithToken::new_with_token(constants::builtins::EQ, Some(Shared::new(token(TokenKind::EqEq)))),
4915 smallvec![
4916 Shared::new(Node {
4917 token_id: 0.into(),
4918 expr: Shared::new(Expr::Literal(Literal::String("hello".to_owned()))),
4919 }),
4920 Shared::new(Node {
4921 token_id: 2.into(),
4922 expr: Shared::new(Expr::Literal(Literal::String("world".to_owned()))),
4923 }),
4924 ],
4925 )),
4926 })
4927 ]))]
4928 #[case::equality_numbers(
4929 vec![
4930 token(TokenKind::NumberLiteral(42.into())),
4931 token(TokenKind::EqEq),
4932 token(TokenKind::NumberLiteral(42.into())),
4933 token(TokenKind::Eof)
4934 ],
4935 Ok(vec![
4936 Shared::new(Node {
4937 token_id: 1.into(),
4938 expr: Shared::new(Expr::Call(
4939 IdentWithToken::new_with_token(constants::builtins::EQ, Some(Shared::new(token(TokenKind::EqEq)))),
4940 smallvec![
4941 Shared::new(Node {
4942 token_id: 0.into(),
4943 expr: Shared::new(Expr::Literal(Literal::Number(42.into()))),
4944 }),
4945 Shared::new(Node {
4946 token_id: 2.into(),
4947 expr: Shared::new(Expr::Literal(Literal::Number(42.into()))),
4948 }),
4949 ],
4950 )),
4951 })
4952 ]))]
4953 #[case::equality_booleans(
4954 vec![
4955 token(TokenKind::BoolLiteral(true)),
4956 token(TokenKind::EqEq),
4957 token(TokenKind::BoolLiteral(false)),
4958 token(TokenKind::Eof)
4959 ],
4960 Ok(vec![
4961 Shared::new(Node {
4962 token_id: 1.into(),
4963 expr: Shared::new(Expr::Call(
4964 IdentWithToken::new_with_token(constants::builtins::EQ, Some(Shared::new(token(TokenKind::EqEq)))),
4965 smallvec![
4966 Shared::new(Node {
4967 token_id: 0.into(),
4968 expr: Shared::new(Expr::Literal(Literal::Bool(true))),
4969 }),
4970 Shared::new(Node {
4971 token_id: 2.into(),
4972 expr: Shared::new(Expr::Literal(Literal::Bool(false))),
4973 }),
4974 ],
4975 )),
4976 })
4977 ]))]
4978 #[case::equality_with_identifiers(
4979 vec![
4980 token(TokenKind::Ident(SmolStr::new("x"))),
4981 token(TokenKind::EqEq),
4982 token(TokenKind::Ident(SmolStr::new("y"))),
4983 token(TokenKind::Eof)
4984 ],
4985 Ok(vec![
4986 Shared::new(Node {
4987 token_id: 1.into(),
4988 expr: Shared::new(Expr::Call(
4989 IdentWithToken::new_with_token(constants::builtins::EQ, Some(Shared::new(token(TokenKind::EqEq)))),
4990 smallvec![
4991 Shared::new(Node {
4992 token_id: 0.into(),
4993 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
4994 }),
4995 Shared::new(Node {
4996 token_id: 2.into(),
4997 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y")))))))),
4998 }),
4999 ],
5000 )),
5001 })
5002 ]))]
5003 #[case::equality_with_function_call(
5004 vec![
5005 token(TokenKind::Ident(SmolStr::new("foo"))),
5006 token(TokenKind::LParen),
5007 token(TokenKind::StringLiteral("arg".to_owned())),
5008 token(TokenKind::RParen),
5009 token(TokenKind::EqEq),
5010 token(TokenKind::StringLiteral("result".to_owned())),
5011 token(TokenKind::Eof)
5012 ],
5013 Ok(vec![
5014 Shared::new(Node {
5015 token_id: 2.into(),
5016 expr: Shared::new(Expr::Call(
5017 IdentWithToken::new_with_token(constants::builtins::EQ, Some(Shared::new(token(TokenKind::EqEq)))),
5018 smallvec![
5019 Shared::new(Node {
5020 token_id: 1.into(),
5021 expr: Shared::new(Expr::Call(
5022 IdentWithToken::new_with_token("foo", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("foo")))))),
5023 smallvec![
5024 Shared::new(Node {
5025 token_id: 0.into(),
5026 expr: Shared::new(Expr::Literal(Literal::String("arg".to_owned()))),
5027 }),
5028 ],
5029 )),
5030 }),
5031 Shared::new(Node {
5032 token_id: 3.into(),
5033 expr: Shared::new(Expr::Literal(Literal::String("result".to_owned()))),
5034 }),
5035 ],
5036 )),
5037 })
5038 ]))]
5039 #[case::equality_with_selectors(
5040 vec![
5041 token(TokenKind::Selector(SmolStr::new(".h1"))),
5042 token(TokenKind::EqEq),
5043 token(TokenKind::Selector(SmolStr::new(".text"))),
5044 token(TokenKind::Eof)
5045 ],
5046 Ok(vec![
5047 Shared::new(Node {
5048 token_id: 1.into(),
5049 expr: Shared::new(Expr::Call(
5050 IdentWithToken::new_with_token(constants::builtins::EQ, Some(Shared::new(token(TokenKind::EqEq)))),
5051 smallvec![
5052 Shared::new(Node {
5053 token_id: 0.into(),
5054 expr: Shared::new(Expr::Selector(Selector::Heading(Some(1)))),
5055 }),
5056 Shared::new(Node {
5057 token_id: 2.into(),
5058 expr: Shared::new(Expr::Selector(Selector::Text)),
5059 }),
5060 ],
5061 )),
5062 })
5063 ]))]
5064 #[case::equality_with_none(
5065 vec![
5066 token(TokenKind::None),
5067 token(TokenKind::EqEq),
5068 token(TokenKind::None),
5069 token(TokenKind::Eof)
5070 ],
5071 Ok(vec![
5072 Shared::new(Node {
5073 token_id: 1.into(),
5074 expr: Shared::new(Expr::Call(
5075 IdentWithToken::new_with_token(constants::builtins::EQ, Some(Shared::new(token(TokenKind::EqEq)))),
5076 smallvec![
5077 Shared::new(Node {
5078 token_id: 0.into(),
5079 expr: Shared::new(Expr::Literal(Literal::None)),
5080 }),
5081 Shared::new(Node {
5082 token_id: 2.into(),
5083 expr: Shared::new(Expr::Literal(Literal::None)),
5084 }),
5085 ],
5086 )),
5087 })
5088 ]))]
5089 #[case::equality_error_missing_rhs(
5090 vec![
5091 token(TokenKind::StringLiteral("hello".to_owned())),
5092 token(TokenKind::EqEq),
5093 token(TokenKind::Eof)
5094 ],
5095 Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::EqEq))))]
5096 #[case::equality_in_if_condition(
5097 vec![
5098 token(TokenKind::If),
5099 token(TokenKind::LParen),
5100 token(TokenKind::Ident(SmolStr::new("x"))),
5101 token(TokenKind::EqEq),
5102 token(TokenKind::NumberLiteral(5.into())),
5103 token(TokenKind::RParen),
5104 token(TokenKind::Colon),
5105 token(TokenKind::StringLiteral("equal".to_owned())),
5106 token(TokenKind::Eof)
5107 ],
5108 Ok(vec![
5109 Shared::new(Node {
5110 token_id: 6.into(),
5111 expr: Shared::new(Expr::If(smallvec![
5112 (
5113 Some(Shared::new(Node {
5114 token_id: 2.into(),
5115 expr: Shared::new(Expr::Call(
5116 IdentWithToken::new_with_token(constants::builtins::EQ, Some(Shared::new(token(TokenKind::EqEq)))),
5117 smallvec![
5118 Shared::new(Node {
5119 token_id: 1.into(),
5120 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
5121 }),
5122 Shared::new(Node {
5123 token_id: 3.into(),
5124 expr: Shared::new(Expr::Literal(Literal::Number(5.into()))),
5125 }),
5126 ],
5127 )),
5128 })),
5129 Shared::new(Node {
5130 token_id: 5.into(),
5131 expr: Shared::new(Expr::Literal(Literal::String("equal".to_owned()))),
5132 })
5133 ),
5134 ])),
5135 })
5136 ]))]
5137 #[case::not_equality_simple(
5138 vec![
5139 token(TokenKind::StringLiteral("hello".to_owned())),
5140 token(TokenKind::NeEq),
5141 token(TokenKind::StringLiteral("world".to_owned())),
5142 token(TokenKind::Eof)
5143 ],
5144 Ok(vec![
5145 Shared::new(Node {
5146 token_id: 1.into(),
5147 expr: Shared::new(Expr::Call(
5148 IdentWithToken::new_with_token(constants::builtins::NE, Some(Shared::new(token(TokenKind::NeEq)))),
5149 smallvec![
5150 Shared::new(Node {
5151 token_id: 0.into(),
5152 expr: Shared::new(Expr::Literal(Literal::String("hello".to_owned()))),
5153 }),
5154 Shared::new(Node {
5155 token_id: 2.into(),
5156 expr: Shared::new(Expr::Literal(Literal::String("world".to_owned()))),
5157 }),
5158 ],
5159 )),
5160 })
5161 ]))]
5162 #[case::not_equality_numbers(
5163 vec![
5164 token(TokenKind::NumberLiteral(42.into())),
5165 token(TokenKind::NeEq),
5166 token(TokenKind::NumberLiteral(24.into())),
5167 token(TokenKind::Eof)
5168 ],
5169 Ok(vec![
5170 Shared::new(Node {
5171 token_id: 1.into(),
5172 expr: Shared::new(Expr::Call(
5173 IdentWithToken::new_with_token(constants::builtins::NE, Some(Shared::new(token(TokenKind::NeEq)))),
5174 smallvec![
5175 Shared::new(Node {
5176 token_id: 0.into(),
5177 expr: Shared::new(Expr::Literal(Literal::Number(42.into()))),
5178 }),
5179 Shared::new(Node {
5180 token_id: 2.into(),
5181 expr: Shared::new(Expr::Literal(Literal::Number(24.into()))),
5182 }),
5183 ],
5184 )),
5185 })
5186 ]))]
5187 #[case::not_equality_booleans(
5188 vec![
5189 token(TokenKind::BoolLiteral(true)),
5190 token(TokenKind::NeEq),
5191 token(TokenKind::BoolLiteral(false)),
5192 token(TokenKind::Eof)
5193 ],
5194 Ok(vec![
5195 Shared::new(Node {
5196 token_id: 1.into(),
5197 expr: Shared::new(Expr::Call(
5198 IdentWithToken::new_with_token(constants::builtins::NE, Some(Shared::new(token(TokenKind::NeEq)))),
5199 smallvec![
5200 Shared::new(Node {
5201 token_id: 0.into(),
5202 expr: Shared::new(Expr::Literal(Literal::Bool(true))),
5203 }),
5204 Shared::new(Node {
5205 token_id: 2.into(),
5206 expr: Shared::new(Expr::Literal(Literal::Bool(false))),
5207 }),
5208 ],
5209 )),
5210 })
5211 ]))]
5212 #[case::not_equality_with_identifiers(
5213 vec![
5214 token(TokenKind::Ident(SmolStr::new("x"))),
5215 token(TokenKind::NeEq),
5216 token(TokenKind::Ident(SmolStr::new("y"))),
5217 token(TokenKind::Eof)
5218 ],
5219 Ok(vec![
5220 Shared::new(Node {
5221 token_id: 1.into(),
5222 expr: Shared::new(Expr::Call(
5223 IdentWithToken::new_with_token(constants::builtins::NE, Some(Shared::new(token(TokenKind::NeEq)))),
5224 smallvec![
5225 Shared::new(Node {
5226 token_id: 0.into(),
5227 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
5228 }),
5229 Shared::new(Node {
5230 token_id: 2.into(),
5231 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y")))))))),
5232 }),
5233 ],
5234 )),
5235 })
5236 ]))]
5237 #[case::not_equality_with_function_call(
5238 vec![
5239 token(TokenKind::Ident(SmolStr::new("foo"))),
5240 token(TokenKind::LParen),
5241 token(TokenKind::StringLiteral("arg".to_owned())),
5242 token(TokenKind::RParen),
5243 token(TokenKind::NeEq),
5244 token(TokenKind::StringLiteral("result".to_owned())),
5245 token(TokenKind::Eof)
5246 ],
5247 Ok(vec![
5248 Shared::new(Node {
5249 token_id: 2.into(),
5250 expr: Shared::new(Expr::Call(
5251 IdentWithToken::new_with_token(constants::builtins::NE, Some(Shared::new(token(TokenKind::NeEq)))),
5252 smallvec![
5253 Shared::new(Node {
5254 token_id: 1.into(),
5255 expr: Shared::new(Expr::Call(
5256 IdentWithToken::new_with_token("foo", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("foo")))))),
5257 smallvec![
5258 Shared::new(Node {
5259 token_id: 0.into(),
5260 expr: Shared::new(Expr::Literal(Literal::String("arg".to_owned()))),
5261 }),
5262 ],
5263 )),
5264 }),
5265 Shared::new(Node {
5266 token_id: 3.into(),
5267 expr: Shared::new(Expr::Literal(Literal::String("result".to_owned()))),
5268 }),
5269 ],
5270 )),
5271 })
5272 ]))]
5273 #[case::not_equality_with_selectors(
5274 vec![
5275 token(TokenKind::Selector(SmolStr::new(".h1"))),
5276 token(TokenKind::NeEq),
5277 token(TokenKind::Selector(SmolStr::new(".text"))),
5278 token(TokenKind::Eof)
5279 ],
5280 Ok(vec![
5281 Shared::new(Node {
5282 token_id: 1.into(),
5283 expr: Shared::new(Expr::Call(
5284 IdentWithToken::new_with_token(constants::builtins::NE, Some(Shared::new(token(TokenKind::NeEq)))),
5285 smallvec![
5286 Shared::new(Node {
5287 token_id: 0.into(),
5288 expr: Shared::new(Expr::Selector(Selector::Heading(Some(1)))),
5289 }),
5290 Shared::new(Node {
5291 token_id: 2.into(),
5292 expr: Shared::new(Expr::Selector(Selector::Text)),
5293 }),
5294 ],
5295 )),
5296 })
5297 ]))]
5298 #[case::not_equality_with_none(
5299 vec![
5300 token(TokenKind::None),
5301 token(TokenKind::NeEq),
5302 token(TokenKind::StringLiteral("something".to_owned())),
5303 token(TokenKind::Eof)
5304 ],
5305 Ok(vec![
5306 Shared::new(Node {
5307 token_id: 1.into(),
5308 expr: Shared::new(Expr::Call(
5309 IdentWithToken::new_with_token(constants::builtins::NE, Some(Shared::new(token(TokenKind::NeEq)))),
5310 smallvec![
5311 Shared::new(Node {
5312 token_id: 0.into(),
5313 expr: Shared::new(Expr::Literal(Literal::None)),
5314 }),
5315 Shared::new(Node {
5316 token_id: 2.into(),
5317 expr: Shared::new(Expr::Literal(Literal::String("something".to_owned()))),
5318 }),
5319 ],
5320 )),
5321 })
5322 ]))]
5323 #[case::not_equality_error_missing_rhs(
5324 vec![
5325 token(TokenKind::StringLiteral("hello".to_owned())),
5326 token(TokenKind::NeEq),
5327 token(TokenKind::Eof)
5328 ],
5329 Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::NeEq))))]
5330 #[case::not_equality_in_if_condition(
5331 vec![
5332 token(TokenKind::If),
5333 token(TokenKind::LParen),
5334 token(TokenKind::Ident(SmolStr::new("x"))),
5335 token(TokenKind::NeEq),
5336 token(TokenKind::NumberLiteral(5.into())),
5337 token(TokenKind::RParen),
5338 token(TokenKind::Colon),
5339 token(TokenKind::StringLiteral("not equal".to_owned())),
5340 token(TokenKind::Eof)
5341 ],
5342 Ok(vec![
5343 Shared::new(Node {
5344 token_id: 6.into(),
5345 expr: Shared::new(Expr::If(smallvec![
5346 (
5347 Some(Shared::new(Node {
5348 token_id: 2.into(),
5349 expr: Shared::new(Expr::Call(
5350 IdentWithToken::new_with_token(constants::builtins::NE, Some(Shared::new(token(TokenKind::NeEq)))),
5351 smallvec![
5352 Shared::new(Node {
5353 token_id: 1.into(),
5354 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
5355 }),
5356 Shared::new(Node {
5357 token_id: 3.into(),
5358 expr: Shared::new(Expr::Literal(Literal::Number(5.into()))),
5359 }),
5360 ],
5361 )),
5362 })),
5363 Shared::new(Node {
5364 token_id: 5.into(),
5365 expr: Shared::new(Expr::Literal(Literal::String("not equal".to_owned()))),
5366 })
5367 ),
5368 ])),
5369 })
5370 ]))]
5371 #[case::plus_simple(
5372 vec![
5373 token(TokenKind::NumberLiteral(1.into())),
5374 token(TokenKind::Plus),
5375 token(TokenKind::NumberLiteral(2.into())),
5376 token(TokenKind::Eof)
5377 ],
5378 Ok(vec![
5379 Shared::new(Node {
5380 token_id: 1.into(),
5381 expr: Shared::new(Expr::Call(
5382 IdentWithToken::new_with_token(constants::builtins::ADD, Some(Shared::new(token(TokenKind::Plus)))),
5383 smallvec![
5384 Shared::new(Node {
5385 token_id: 0.into(),
5386 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
5387 }),
5388 Shared::new(Node {
5389 token_id: 2.into(),
5390 expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
5391 }),
5392 ],
5393 )),
5394 })
5395 ]))]
5396 #[case::plus_with_identifiers(
5397 vec![
5398 token(TokenKind::Ident(SmolStr::new("x"))),
5399 token(TokenKind::Plus),
5400 token(TokenKind::Ident(SmolStr::new("y"))),
5401 token(TokenKind::Eof)
5402 ],
5403 Ok(vec![
5404 Shared::new(Node {
5405 token_id: 1.into(),
5406 expr: Shared::new(Expr::Call(
5407 IdentWithToken::new_with_token(constants::builtins::ADD, Some(Shared::new(token(TokenKind::Plus)))),
5408 smallvec![
5409 Shared::new(Node {
5410 token_id: 0.into(),
5411 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
5412 }),
5413 Shared::new(Node {
5414 token_id: 2.into(),
5415 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y")))))))),
5416 }),
5417 ],
5418 )),
5419 })
5420 ]))]
5421 #[case::plus_error_missing_rhs(
5422 vec![
5423 token(TokenKind::NumberLiteral(1.into())),
5424 token(TokenKind::Plus),
5425 token(TokenKind::Eof)
5426 ],
5427 Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::Plus))))]
5428 #[case::lt_simple(
5429 vec![
5430 token(TokenKind::NumberLiteral(1.into())),
5431 token(TokenKind::Lt),
5432 token(TokenKind::NumberLiteral(2.into())),
5433 token(TokenKind::Eof)
5434 ],
5435 Ok(vec![
5436 Shared::new(Node {
5437 token_id: 1.into(),
5438 expr: Shared::new(Expr::Call(
5439 IdentWithToken::new_with_token(constants::builtins::LT, Some(Shared::new(token(TokenKind::Lt)))),
5440 smallvec![
5441 Shared::new(Node {
5442 token_id: 0.into(),
5443 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
5444 }),
5445 Shared::new(Node {
5446 token_id: 2.into(),
5447 expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
5448 }),
5449 ],
5450 )),
5451 })
5452 ]))]
5453 #[case::lte_simple(
5454 vec![
5455 token(TokenKind::NumberLiteral(1.into())),
5456 token(TokenKind::Lte),
5457 token(TokenKind::NumberLiteral(2.into())),
5458 token(TokenKind::Eof)
5459 ],
5460 Ok(vec![
5461 Shared::new(Node {
5462 token_id: 1.into(),
5463 expr: Shared::new(Expr::Call(
5464 IdentWithToken::new_with_token(constants::builtins::LTE, Some(Shared::new(token(TokenKind::Lte)))),
5465 smallvec![
5466 Shared::new(Node {
5467 token_id: 0.into(),
5468 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
5469 }),
5470 Shared::new(Node {
5471 token_id: 2.into(),
5472 expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
5473 }),
5474 ],
5475 )),
5476 })
5477 ]))]
5478 #[case::gt_simple(
5479 vec![
5480 token(TokenKind::NumberLiteral(3.into())),
5481 token(TokenKind::Gt),
5482 token(TokenKind::NumberLiteral(2.into())),
5483 token(TokenKind::Eof)
5484 ],
5485 Ok(vec![
5486 Shared::new(Node {
5487 token_id: 1.into(),
5488 expr: Shared::new(Expr::Call(
5489 IdentWithToken::new_with_token(constants::builtins::GT, Some(Shared::new(token(TokenKind::Gt)))),
5490 smallvec![
5491 Shared::new(Node {
5492 token_id: 0.into(),
5493 expr: Shared::new(Expr::Literal(Literal::Number(3.into()))),
5494 }),
5495 Shared::new(Node {
5496 token_id: 2.into(),
5497 expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
5498 }),
5499 ],
5500 )),
5501 })
5502 ]))]
5503 #[case::gte_simple(
5504 vec![
5505 token(TokenKind::NumberLiteral(3.into())),
5506 token(TokenKind::Gte),
5507 token(TokenKind::NumberLiteral(2.into())),
5508 token(TokenKind::Eof)
5509 ],
5510 Ok(vec![
5511 Shared::new(Node {
5512 token_id: 1.into(),
5513 expr: Shared::new(Expr::Call(
5514 IdentWithToken::new_with_token(constants::builtins::GTE, Some(Shared::new(token(TokenKind::Gte)))),
5515 smallvec![
5516 Shared::new(Node {
5517 token_id: 0.into(),
5518 expr: Shared::new(Expr::Literal(Literal::Number(3.into()))),
5519 }),
5520 Shared::new(Node {
5521 token_id: 2.into(),
5522 expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
5523 }),
5524 ],
5525 )),
5526 })
5527 ]))]
5528 #[case::dict_empty(
5529 vec![
5530 token(TokenKind::LBrace),
5531 token(TokenKind::RBrace),
5532 token(TokenKind::Eof)
5533 ],
5534 Ok(vec![
5535 Shared::new(Node {
5536 token_id: 0.into(),
5537 expr: Shared::new(Expr::Call(
5538 IdentWithToken::new_with_token(constants::builtins::DICT, Some(Shared::new(token(TokenKind::LBrace)))),
5539 SmallVec::new(),
5540 )),
5541 })
5542 ]))]
5543 #[case::dict_single_pair(
5544 vec![
5545 token(TokenKind::LBrace),
5546 token(TokenKind::Ident(SmolStr::new("key"))),
5547 token(TokenKind::Colon),
5548 token(TokenKind::StringLiteral("value".to_owned())),
5549 token(TokenKind::RBrace),
5550 token(TokenKind::Eof)
5551 ],
5552 Ok(vec![
5553 Shared::new(Node {
5554 token_id: 0.into(),
5555 expr: Shared::new(Expr::Call(
5556 IdentWithToken::new_with_token(constants::builtins::DICT, Some(Shared::new(token(TokenKind::LBrace)))),
5557 smallvec![
5558 Shared::new(Node {
5559 token_id: 0.into(),
5560 expr: Shared::new(Expr::Call(
5561 IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("key")))))),
5562 smallvec![
5563 Shared::new(Node {
5564 token_id: 1.into(),
5565 expr: Shared::new(Expr::Literal(Literal::Symbol(Ident::new("key")))),
5566 }),
5567 Shared::new(Node {
5568 token_id: 2.into(),
5569 expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
5570 }),
5571 ],
5572 )),
5573 }),
5574 ],
5575 )),
5576 })
5577 ]))]
5578 #[case::dict_multiple_pairs(
5579 vec![
5580 token(TokenKind::LBrace),
5581 token(TokenKind::Ident(SmolStr::new("a"))),
5582 token(TokenKind::Colon),
5583 token(TokenKind::NumberLiteral(1.into())),
5584 token(TokenKind::Comma),
5585 token(TokenKind::StringLiteral("b".to_owned())),
5586 token(TokenKind::Colon),
5587 token(TokenKind::BoolLiteral(true)),
5588 token(TokenKind::RBrace),
5589 token(TokenKind::Eof)
5590 ],
5591 Ok(vec![
5592 Shared::new(Node {
5593 token_id: 0.into(),
5594 expr: Shared::new(Expr::Call(
5595 IdentWithToken::new_with_token(constants::builtins::DICT, Some(Shared::new(token(TokenKind::LBrace)))),
5596 smallvec![
5597 Shared::new(Node {
5598 token_id: 0.into(),
5599 expr: Shared::new(Expr::Call(
5600 IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))),
5601 smallvec![
5602 Shared::new(Node {
5603 token_id: 1.into(),
5604 expr: Shared::new(Expr::Literal(Literal::Symbol(Ident::new("a")))),
5605 }),
5606 Shared::new(Node {
5607 token_id: 2.into(),
5608 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
5609 }),
5610 ],
5611 )),
5612 }),
5613 Shared::new(Node {
5614 token_id: 0.into(),
5615 expr: Shared::new(Expr::Call(
5616 IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::StringLiteral("b".to_owned()))))),
5617 smallvec![
5618 Shared::new(Node {
5619 token_id: 3.into(),
5620 expr: Shared::new(Expr::Literal(Literal::String("b".to_owned()))),
5621 }),
5622 Shared::new(Node {
5623 token_id: 4.into(),
5624 expr: Shared::new(Expr::Literal(Literal::Bool(true))),
5625 }),
5626 ],
5627 )),
5628 }),
5629 ],
5630 )),
5631 })
5632 ]))]
5633 #[case::dict_trailing_comma(
5634 vec![
5635 token(TokenKind::LBrace),
5636 token(TokenKind::Ident(SmolStr::new("x"))),
5637 token(TokenKind::Colon),
5638 token(TokenKind::NumberLiteral(10.into())),
5639 token(TokenKind::Comma),
5640 token(TokenKind::RBrace),
5641 token(TokenKind::Eof)
5642 ],
5643 Ok(vec![
5644 Shared::new(Node {
5645 token_id: 0.into(),
5646 expr: Shared::new(Expr::Call(
5647 IdentWithToken::new_with_token(constants::builtins::DICT, Some(Shared::new(token(TokenKind::LBrace)))),
5648 smallvec![
5649 Shared::new(Node {
5650 token_id: 0.into(),
5651 expr: Shared::new(Expr::Call(
5652 IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))),
5653 smallvec![
5654 Shared::new(Node {
5655 token_id: 1.into(),
5656 expr: Shared::new(Expr::Literal(Literal::Symbol(Ident::new("x")))),
5657 }),
5658 Shared::new(Node {
5659 token_id: 2.into(),
5660 expr: Shared::new(Expr::Literal(Literal::Number(10.into()))),
5661 }),
5662 ],
5663 )),
5664 }),
5665 ],
5666 )),
5667 })
5668 ]))]
5669 #[case::dict_unclosed(
5670 vec![
5671 token(TokenKind::LBrace),
5672 token(TokenKind::Ident(SmolStr::new("k"))),
5673 token(TokenKind::Colon),
5674 token(TokenKind::NumberLiteral(1.into())),
5675 token(TokenKind::Eof)
5676 ],
5677 Err(SyntaxError::ExpectedClosingBrace(token(TokenKind::Eof), Some(Box::new(token(TokenKind::LBrace))))))]
5678 #[case::dict_missing_colon(
5679 vec![
5680 token(TokenKind::LBrace),
5681 token(TokenKind::Ident(SmolStr::new("k"))),
5682 token(TokenKind::NumberLiteral(1.into())),
5683 token(TokenKind::RBrace),
5684 token(TokenKind::Eof)
5685 ],
5686 Err(SyntaxError::UnexpectedToken(token(TokenKind::NumberLiteral(1.into())))))]
5687 #[case::dict_invalid_key(
5688 vec![
5689 token(TokenKind::LBrace),
5690 token(TokenKind::NumberLiteral(1.into())),
5691 token(TokenKind::Colon),
5692 token(TokenKind::StringLiteral("v".to_owned())),
5693 token(TokenKind::RBrace),
5694 token(TokenKind::Eof)
5695 ],
5696 Err(SyntaxError::UnexpectedToken(token(TokenKind::NumberLiteral(1.into())))))]
5697 #[case::attr_h_value(
5698 vec![
5699 token(TokenKind::Selector(".h".into())),
5700 token(TokenKind::Selector(".value".into())),
5701 ],
5702 Ok(vec![
5703 Shared::new(Node {
5704 token_id: 2.into(),
5705 expr: Shared::new(Expr::Call(IdentWithToken::new_with_token(constants::builtins::ATTR, Some(Shared::new(token(TokenKind::Selector(".h".into()))))),
5706 smallvec![
5707 Shared::new(Node {
5708 token_id: 0.into(),
5709 expr: Shared::new(Expr::Selector(Selector::Heading(None))),
5710 }),
5711 Shared::new(Node {
5712 token_id: 1.into(),
5713 expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
5714 }),
5715
5716 ],
5717 ))})]))]
5718 #[case::attr(
5719 vec![
5720 token(TokenKind::Selector(".list".into())),
5721 token(TokenKind::Selector(".checked".into())),
5722 ],
5723 Ok(vec![
5724 Shared::new(Node {
5725 token_id: 2.into(),
5726 expr: Shared::new(Expr::Call(IdentWithToken::new_with_token(constants::builtins::ATTR, Some(Shared::new(token(TokenKind::Selector(".list".into()))))),
5727 smallvec![
5728 Shared::new(Node {
5729 token_id: 0.into(),
5730 expr: Shared::new(Expr::Selector(Selector::List(None, None))),
5731 }),
5732 Shared::new(Node {
5733 token_id: 1.into(),
5734 expr: Shared::new(Expr::Literal(Literal::String("checked".to_owned()))),
5735 }),
5736
5737 ],
5738 ))})]))]
5739 #[case::paren(
5740 vec![
5741 token(TokenKind::LParen),
5742 token(TokenKind::NumberLiteral(1.into())),
5743 token(TokenKind::Plus),
5744 token(TokenKind::NumberLiteral(2.into())),
5745 token(TokenKind::RParen),
5746 ],
5747 Ok(vec![
5748 Shared::new(Node {
5749 token_id: 0.into(),
5750 expr: Shared::new(Expr::Paren(
5751 Shared::new(Node {
5752 token_id: 2.into(),
5753 expr: Shared::new(Expr::Call(
5754 IdentWithToken::new_with_token(constants::builtins::ADD, Some(Shared::new(token(TokenKind::Plus)))),
5755 smallvec![
5756 Shared::new(Node {
5757 token_id: 1.into(),
5758 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
5759 }),
5760 Shared::new(Node {
5761 token_id: 3.into(),
5762 expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
5763 }),
5764 ],
5765 )),
5766 })
5767 )),
5768 })
5769 ]))]
5770 #[case::minus_simple(
5771 vec![
5772 token(TokenKind::NumberLiteral(5.into())),
5773 token(TokenKind::Minus),
5774 token(TokenKind::NumberLiteral(3.into())),
5775 token(TokenKind::Eof)
5776 ],
5777 Ok(vec![
5778 Shared::new(Node {
5779 token_id: 1.into(),
5780 expr: Shared::new(Expr::Call(
5781 IdentWithToken::new_with_token(constants::builtins::SUB, Some(Shared::new(token(TokenKind::Minus)))),
5782 smallvec![
5783 Shared::new(Node {
5784 token_id: 0.into(),
5785 expr: Shared::new(Expr::Literal(Literal::Number(5.into()))),
5786 }),
5787 Shared::new(Node {
5788 token_id: 2.into(),
5789 expr: Shared::new(Expr::Literal(Literal::Number(3.into()))),
5790 }),
5791 ],
5792 )),
5793 })
5794 ]))]
5795 #[case::minus_with_identifiers(
5796 vec![
5797 token(TokenKind::Ident(SmolStr::new("a"))),
5798 token(TokenKind::Minus),
5799 token(TokenKind::Ident(SmolStr::new("b"))),
5800 token(TokenKind::Eof)
5801 ],
5802 Ok(vec![
5803 Shared::new(Node {
5804 token_id: 1.into(),
5805 expr: Shared::new(Expr::Call(
5806 IdentWithToken::new_with_token(constants::builtins::SUB, Some(Shared::new(token(TokenKind::Minus)))),
5807 smallvec![
5808 Shared::new(Node {
5809 token_id: 0.into(),
5810 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
5811 }),
5812 Shared::new(Node {
5813 token_id: 2.into(),
5814 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
5815 }),
5816 ],
5817 )),
5818 })
5819 ]))]
5820 #[case::slash_simple(
5821 vec![
5822 token(TokenKind::NumberLiteral(6.into())),
5823 token(TokenKind::Slash),
5824 token(TokenKind::NumberLiteral(2.into())),
5825 token(TokenKind::Eof)
5826 ],
5827 Ok(vec![
5828 Shared::new(Node {
5829 token_id: 1.into(),
5830 expr: Shared::new(Expr::Call(
5831 IdentWithToken::new_with_token(constants::builtins::DIV, Some(Shared::new(token(TokenKind::Slash)))),
5832 smallvec![
5833 Shared::new(Node {
5834 token_id: 0.into(),
5835 expr: Shared::new(Expr::Literal(Literal::Number(6.into()))),
5836 }),
5837 Shared::new(Node {
5838 token_id: 2.into(),
5839 expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
5840 }),
5841 ],
5842 )),
5843 })
5844 ]))]
5845 #[case::percent_simple(
5846 vec![
5847 token(TokenKind::NumberLiteral(10.into())),
5848 token(TokenKind::Percent),
5849 token(TokenKind::NumberLiteral(3.into())),
5850 token(TokenKind::Eof)
5851 ],
5852 Ok(vec![
5853 Shared::new(Node {
5854 token_id: 1.into(),
5855 expr: Shared::new(Expr::Call(
5856 IdentWithToken::new_with_token(constants::builtins::MOD, Some(Shared::new(token(TokenKind::Percent)))),
5857 smallvec![
5858 Shared::new(Node {
5859 token_id: 0.into(),
5860 expr: Shared::new(Expr::Literal(Literal::Number(10.into()))),
5861 }),
5862 Shared::new(Node {
5863 token_id: 2.into(),
5864 expr: Shared::new(Expr::Literal(Literal::Number(3.into()))),
5865 }),
5866 ],
5867 )),
5868 })
5869 ]))]
5870 #[case::percent_with_identifiers(
5871 vec![
5872 token(TokenKind::Ident(SmolStr::new("a"))),
5873 token(TokenKind::Percent),
5874 token(TokenKind::Ident(SmolStr::new("b"))),
5875 token(TokenKind::Eof)
5876 ],
5877 Ok(vec![
5878 Shared::new(Node {
5879 token_id: 1.into(),
5880 expr: Shared::new(Expr::Call(
5881 IdentWithToken::new_with_token(constants::builtins::MOD, Some(Shared::new(token(TokenKind::Percent)))),
5882 smallvec![
5883 Shared::new(Node {
5884 token_id: 0.into(),
5885 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
5886 }),
5887 Shared::new(Node {
5888 token_id: 2.into(),
5889 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
5890 }),
5891 ],
5892 )),
5893 })
5894 ]))]
5895 #[case::percent_error_missing_rhs(
5896 vec![
5897 token(TokenKind::NumberLiteral(10.into())),
5898 token(TokenKind::Percent),
5899 token(TokenKind::Eof)
5900 ],
5901 Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::Percent))))]
5902 #[case::mul_simple(
5903 vec![
5904 token(TokenKind::NumberLiteral(3.into())),
5905 token(TokenKind::Asterisk),
5906 token(TokenKind::NumberLiteral(4.into())),
5907 token(TokenKind::Eof)
5908 ],
5909 Ok(vec![
5910 Shared::new(Node {
5911 token_id: 1.into(),
5912 expr: Shared::new(Expr::Call(
5913 IdentWithToken::new_with_token(constants::builtins::MUL, Some(Shared::new(token(TokenKind::Asterisk)))),
5914 smallvec![
5915 Shared::new(Node {
5916 token_id: 0.into(),
5917 expr: Shared::new(Expr::Literal(Literal::Number(3.into()))),
5918 }),
5919 Shared::new(Node {
5920 token_id: 2.into(),
5921 expr: Shared::new(Expr::Literal(Literal::Number(4.into()))),
5922 }),
5923 ],
5924 )),
5925 })
5926 ]))]
5927 #[case::mul_with_identifiers(
5928 vec![
5929 token(TokenKind::Ident(SmolStr::new("a"))),
5930 token(TokenKind::Asterisk),
5931 token(TokenKind::Ident(SmolStr::new("b"))),
5932 token(TokenKind::Eof)
5933 ],
5934 Ok(vec![
5935 Shared::new(Node {
5936 token_id: 1.into(),
5937 expr: Shared::new(Expr::Call(
5938 IdentWithToken::new_with_token(constants::builtins::MUL, Some(Shared::new(token(TokenKind::Asterisk)))),
5939 smallvec![
5940 Shared::new(Node {
5941 token_id: 0.into(),
5942 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
5943 }),
5944 Shared::new(Node {
5945 token_id: 2.into(),
5946 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
5947 }),
5948 ],
5949 )),
5950 })
5951 ]))]
5952 #[case::mul_error_missing_rhs(
5953 vec![
5954 token(TokenKind::NumberLiteral(5.into())),
5955 token(TokenKind::Asterisk),
5956 token(TokenKind::Eof)
5957 ],
5958 Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::Asterisk))))]
5959 #[case::convert_simple(
5960 vec![
5961 token(TokenKind::Ident(SmolStr::new("a"))),
5962 token(TokenKind::Convert),
5963 token(TokenKind::Ident(SmolStr::new("b"))),
5964 token(TokenKind::Eof)
5965 ],
5966 Ok(vec![
5967 Shared::new(Node {
5968 token_id: 1.into(),
5969 expr: Shared::new(Expr::Call(
5970 IdentWithToken::new_with_token(constants::builtins::CONVERT, Some(Shared::new(token(TokenKind::Convert)))),
5971 smallvec![
5972 Shared::new(Node {
5973 token_id: 0.into(),
5974 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
5975 }),
5976 Shared::new(Node {
5977 token_id: 2.into(),
5978 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
5979 }),
5980 ],
5981 )),
5982 })
5983 ]))]
5984 #[case::convert_error_missing_rhs(
5985 vec![
5986 token(TokenKind::Ident(SmolStr::new("a"))),
5987 token(TokenKind::Convert),
5988 token(TokenKind::Eof)
5989 ],
5990 Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::Convert))))]
5991 #[case::multiple_binary_operators(
5992 vec![
5993 token(TokenKind::NumberLiteral(1.into())),
5994 token(TokenKind::Asterisk),
5995 token(TokenKind::NumberLiteral(2.into())),
5996 token(TokenKind::Asterisk),
5997 token(TokenKind::NumberLiteral(3.into())),
5998 token(TokenKind::Eof)
5999 ],
6000 Ok(vec![
6001 Shared::new(Node {
6002 token_id: 3.into(),
6003 expr: Shared::new(Expr::Call(
6004 IdentWithToken::new_with_token(constants::builtins::MUL, Some(Shared::new(token(TokenKind::Asterisk)))),
6005 smallvec![
6006 Shared::new(Node {
6007 token_id: 1.into(),
6008 expr: Shared::new(Expr::Call(
6009 IdentWithToken::new_with_token(constants::builtins::MUL, Some(Shared::new(token(TokenKind::Asterisk)))),
6010 smallvec![
6011 Shared::new(Node {
6012 token_id: 0.into(),
6013 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
6014 }),
6015 Shared::new(Node {
6016 token_id: 2.into(),
6017 expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
6018 }),
6019 ],
6020 )),
6021 }),
6022 Shared::new(Node {
6023 token_id: 4.into(),
6024 expr: Shared::new(Expr::Literal(Literal::Number(3.into()))),
6025 }),
6026 ],
6027 )),
6028 })
6029 ]))]
6030 #[case::multiple_binary_operators_eq(
6031 vec![
6032 token(TokenKind::NumberLiteral(1.into())),
6033 token(TokenKind::Plus),
6034 token(TokenKind::NumberLiteral(2.into())),
6035 token(TokenKind::EqEq),
6036 token(TokenKind::NumberLiteral(3.into())),
6037 token(TokenKind::Eof)
6038 ],
6039 Ok(vec![
6040 Shared::new(Node {
6041 token_id: 3.into(),
6042 expr: Shared::new(Expr::Call(
6043 IdentWithToken::new_with_token(constants::builtins::EQ, Some(Shared::new(token(TokenKind::EqEq)))),
6044 smallvec![
6045 Shared::new(Node {
6046 token_id: 1.into(),
6047 expr: Shared::new(Expr::Call(
6048 IdentWithToken::new_with_token(constants::builtins::ADD, Some(Shared::new(token(TokenKind::Plus)))),
6049 smallvec![
6050 Shared::new(Node {
6051 token_id: 0.into(),
6052 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
6053 }),
6054 Shared::new(Node {
6055 token_id: 2.into(),
6056 expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
6057 }),
6058 ],
6059 )),
6060 }),
6061 Shared::new(Node {
6062 token_id: 4.into(),
6063 expr: Shared::new(Expr::Literal(Literal::Number(3.into()))),
6064 }),
6065 ],
6066 )),
6067 })
6068 ]))]
6069 #[case::multiple_and_operators(
6070 vec![
6071 token(TokenKind::Ident(SmolStr::new("a"))),
6072 token(TokenKind::And),
6073 token(TokenKind::Ident(SmolStr::new("b"))),
6074 token(TokenKind::And),
6075 token(TokenKind::Ident(SmolStr::new("c"))),
6076 token(TokenKind::Eof)
6077 ],
6078 Ok(vec![
6079 Shared::new(Node {
6080 token_id: 3.into(),
6081 expr: Shared::new(Expr::And(vec![
6082 Shared::new(Node {
6083 token_id: 0.into(),
6084 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
6085 }),
6086 Shared::new(Node {
6087 token_id: 2.into(),
6088 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
6089 }),
6090 Shared::new(Node {
6091 token_id: 4.into(),
6092 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("c", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))))),
6093 }),
6094 ])),
6095 })
6096 ]))]
6097 #[case::multiple_or_operators(
6098 vec![
6099 token(TokenKind::Ident(SmolStr::new("x"))),
6100 token(TokenKind::Or),
6101 token(TokenKind::Ident(SmolStr::new("y"))),
6102 token(TokenKind::Or),
6103 token(TokenKind::Ident(SmolStr::new("z"))),
6104 token(TokenKind::Eof)
6105 ],
6106 Ok(vec![
6107 Shared::new(Node {
6108 token_id: 3.into(),
6109 expr: Shared::new(Expr::Or(vec![
6110 Shared::new(Node {
6111 token_id: 0.into(),
6112 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
6113 }),
6114 Shared::new(Node {
6115 token_id: 2.into(),
6116 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y")))))))),
6117 }),
6118 Shared::new(Node {
6119 token_id: 4.into(),
6120 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("z", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("z")))))))),
6121 }),
6122 ])),
6123 })
6124 ]))]
6125 #[case::and_or_mixed(
6126 vec![
6127 token(TokenKind::Ident(SmolStr::new("a"))),
6128 token(TokenKind::And),
6129 token(TokenKind::Ident(SmolStr::new("b"))),
6130 token(TokenKind::Or),
6131 token(TokenKind::Ident(SmolStr::new("c"))),
6132 token(TokenKind::Eof)
6133 ],
6134 Ok(vec![
6135 Shared::new(Node {
6136 token_id: 3.into(),
6137 expr: Shared::new(Expr::Or(vec![
6138 Shared::new(Node {
6139 token_id: 1.into(),
6140 expr: Shared::new(Expr::And(vec![
6141 Shared::new(Node {
6142 token_id: 0.into(),
6143 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
6144 }),
6145 Shared::new(Node {
6146 token_id: 2.into(),
6147 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
6148 }),
6149 ])),
6150 }),
6151 Shared::new(Node {
6152 token_id: 4.into(),
6153 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("c", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))))),
6154 }),
6155 ])),
6156 })
6157 ]))]
6158 #[case::four_and_operators(
6159 vec![
6160 token(TokenKind::Ident(SmolStr::new("a"))),
6161 token(TokenKind::And),
6162 token(TokenKind::Ident(SmolStr::new("b"))),
6163 token(TokenKind::And),
6164 token(TokenKind::Ident(SmolStr::new("c"))),
6165 token(TokenKind::And),
6166 token(TokenKind::Ident(SmolStr::new("d"))),
6167 token(TokenKind::Eof)
6168 ],
6169 Ok(vec![
6170 Shared::new(Node {
6171 token_id: 5.into(),
6172 expr: Shared::new(Expr::And(vec![
6173 Shared::new(Node {
6174 token_id: 0.into(),
6175 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
6176 }),
6177 Shared::new(Node {
6178 token_id: 2.into(),
6179 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
6180 }),
6181 Shared::new(Node {
6182 token_id: 4.into(),
6183 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("c", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))))),
6184 }),
6185 Shared::new(Node {
6186 token_id: 6.into(),
6187 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("d", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("d")))))))),
6188 }),
6189 ])),
6190 })
6191 ]))]
6192 #[case::four_or_operators(
6193 vec![
6194 token(TokenKind::Ident(SmolStr::new("a"))),
6195 token(TokenKind::Or),
6196 token(TokenKind::Ident(SmolStr::new("b"))),
6197 token(TokenKind::Or),
6198 token(TokenKind::Ident(SmolStr::new("c"))),
6199 token(TokenKind::Or),
6200 token(TokenKind::Ident(SmolStr::new("d"))),
6201 token(TokenKind::Eof)
6202 ],
6203 Ok(vec![
6204 Shared::new(Node {
6205 token_id: 5.into(),
6206 expr: Shared::new(Expr::Or(vec![
6207 Shared::new(Node {
6208 token_id: 0.into(),
6209 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
6210 }),
6211 Shared::new(Node {
6212 token_id: 2.into(),
6213 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
6214 }),
6215 Shared::new(Node {
6216 token_id: 4.into(),
6217 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("c", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))))),
6218 }),
6219 Shared::new(Node {
6220 token_id: 6.into(),
6221 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("d", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("d")))))))),
6222 }),
6223 ])),
6224 })
6225 ]))]
6226 #[case::or_with_and_in_middle(
6227 vec![
6228 token(TokenKind::Ident(SmolStr::new("a"))),
6229 token(TokenKind::Or),
6230 token(TokenKind::Ident(SmolStr::new("b"))),
6231 token(TokenKind::And),
6232 token(TokenKind::Ident(SmolStr::new("c"))),
6233 token(TokenKind::Or),
6234 token(TokenKind::Ident(SmolStr::new("d"))),
6235 token(TokenKind::Eof)
6236 ],
6237 Ok(vec![
6238 Shared::new(Node {
6239 token_id: 5.into(),
6240 expr: Shared::new(Expr::Or(vec![
6241 Shared::new(Node {
6242 token_id: 0.into(),
6243 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
6244 }),
6245 Shared::new(Node {
6246 token_id: 3.into(),
6247 expr: Shared::new(Expr::And(vec![
6248 Shared::new(Node {
6249 token_id: 2.into(),
6250 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
6251 }),
6252 Shared::new(Node {
6253 token_id: 4.into(),
6254 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("c", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))))),
6255 }),
6256 ])),
6257 }),
6258 Shared::new(Node {
6259 token_id: 6.into(),
6260 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("d", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("d")))))))),
6261 }),
6262 ])),
6263 })
6264 ]))]
6265 #[case::and_or_and_mixed(
6266 vec![
6268 token(TokenKind::Ident(SmolStr::new("a"))),
6269 token(TokenKind::And),
6270 token(TokenKind::Ident(SmolStr::new("b"))),
6271 token(TokenKind::Or),
6272 token(TokenKind::Ident(SmolStr::new("c"))),
6273 token(TokenKind::And),
6274 token(TokenKind::Ident(SmolStr::new("d"))),
6275 token(TokenKind::Eof)
6276 ],
6277 Ok(vec![
6278 Shared::new(Node {
6279 token_id: 3.into(),
6280 expr: Shared::new(Expr::Or(vec![
6281 Shared::new(Node {
6282 token_id: 1.into(),
6283 expr: Shared::new(Expr::And(vec![
6284 Shared::new(Node {
6285 token_id: 0.into(),
6286 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
6287 }),
6288 Shared::new(Node {
6289 token_id: 2.into(),
6290 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
6291 }),
6292 ])),
6293 }),
6294 Shared::new(Node {
6295 token_id: 5.into(),
6296 expr: Shared::new(Expr::And(vec![
6297 Shared::new(Node {
6298 token_id: 4.into(),
6299 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("c", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))))),
6300 }),
6301 Shared::new(Node {
6302 token_id: 6.into(),
6303 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("d", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("d")))))))),
6304 }),
6305 ])),
6306 }),
6307 ])),
6308 })
6309 ]))]
6310 #[case::or_and_or_mixed(
6311 vec![
6313 token(TokenKind::Ident(SmolStr::new("a"))),
6314 token(TokenKind::Or),
6315 token(TokenKind::Ident(SmolStr::new("b"))),
6316 token(TokenKind::And),
6317 token(TokenKind::Ident(SmolStr::new("c"))),
6318 token(TokenKind::Or),
6319 token(TokenKind::Ident(SmolStr::new("d"))),
6320 token(TokenKind::Eof)
6321 ],
6322 Ok(vec![
6323 Shared::new(Node {
6324 token_id: 5.into(),
6325 expr: Shared::new(Expr::Or(vec![
6326 Shared::new(Node {
6327 token_id: 0.into(),
6328 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
6329 }),
6330 Shared::new(Node {
6331 token_id: 3.into(),
6332 expr: Shared::new(Expr::And(vec![
6333 Shared::new(Node {
6334 token_id: 2.into(),
6335 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
6336 }),
6337 Shared::new(Node {
6338 token_id: 4.into(),
6339 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("c", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))))),
6340 }),
6341 ])),
6342 }),
6343 Shared::new(Node {
6344 token_id: 6.into(),
6345 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("d", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("d")))))))),
6346 }),
6347 ])),
6348 })
6349 ]))]
6350 #[case::and_and_or_and_and_mixed(
6351 vec![
6353 token(TokenKind::Ident(SmolStr::new("a"))),
6354 token(TokenKind::And),
6355 token(TokenKind::Ident(SmolStr::new("b"))),
6356 token(TokenKind::And),
6357 token(TokenKind::Ident(SmolStr::new("c"))),
6358 token(TokenKind::Or),
6359 token(TokenKind::Ident(SmolStr::new("d"))),
6360 token(TokenKind::And),
6361 token(TokenKind::Ident(SmolStr::new("e"))),
6362 token(TokenKind::And),
6363 token(TokenKind::Ident(SmolStr::new("f"))),
6364 token(TokenKind::Eof)
6365 ],
6366 Ok(vec![
6367 Shared::new(Node {
6368 token_id: 5.into(),
6369 expr: Shared::new(Expr::Or(vec![
6370 Shared::new(Node {
6371 token_id: 3.into(),
6372 expr: Shared::new(Expr::And(vec![
6373 Shared::new(Node {
6374 token_id: 0.into(),
6375 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
6376 }),
6377 Shared::new(Node {
6378 token_id: 2.into(),
6379 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
6380 }),
6381 Shared::new(Node {
6382 token_id: 4.into(),
6383 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("c", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))))),
6384 }),
6385 ])),
6386 }),
6387 Shared::new(Node {
6388 token_id: 9.into(),
6389 expr: Shared::new(Expr::And(vec![
6390 Shared::new(Node {
6391 token_id: 6.into(),
6392 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("d", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("d")))))))),
6393 }),
6394 Shared::new(Node {
6395 token_id: 8.into(),
6396 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("e", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("e")))))))),
6397 }),
6398 Shared::new(Node {
6399 token_id: 10.into(),
6400 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("f", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("f")))))))),
6401 }),
6402 ])),
6403 }),
6404 ])),
6405 })
6406 ]))]
6407 #[case::range_simple(
6408 vec![
6409 token(TokenKind::NumberLiteral(1.into())),
6410 token(TokenKind::DoubleDot),
6411 token(TokenKind::NumberLiteral(5.into())),
6412 token(TokenKind::Eof)
6413 ],
6414 Ok(vec![
6415 Shared::new(Node {
6416 token_id: 1.into(),
6417 expr: Shared::new(Expr::Call(
6418 IdentWithToken::new_with_token(constants::builtins::RANGE, Some(Shared::new(token(TokenKind::DoubleDot)))),
6419 smallvec![
6420 Shared::new(Node {
6421 token_id: 0.into(),
6422 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
6423 }),
6424 Shared::new(Node {
6425 token_id: 2.into(),
6426 expr: Shared::new(Expr::Literal(Literal::Number(5.into()))),
6427 }),
6428 ],
6429 )),
6430 })
6431 ]))]
6432 #[case::range_with_identifiers(
6433 vec![
6434 token(TokenKind::Ident(SmolStr::new("start"))),
6435 token(TokenKind::DoubleDot),
6436 token(TokenKind::Ident(SmolStr::new("end"))),
6437 token(TokenKind::Eof)
6438 ],
6439 Ok(vec![
6440 Shared::new(Node {
6441 token_id: 1.into(),
6442 expr: Shared::new(Expr::Call(
6443 IdentWithToken::new_with_token(constants::builtins::RANGE, Some(Shared::new(token(TokenKind::DoubleDot)))),
6444 smallvec![
6445 Shared::new(Node {
6446 token_id: 0.into(),
6447 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("start", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("start")))))))),
6448 }),
6449 Shared::new(Node {
6450 token_id: 2.into(),
6451 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("end", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("end")))))))),
6452 }),
6453 ],
6454 )),
6455 })
6456 ]))]
6457 #[case::range_error_missing_rhs(
6458 vec![
6459 token(TokenKind::NumberLiteral(1.into())),
6460 token(TokenKind::DoubleDot),
6461 token(TokenKind::Eof)
6462 ],
6463 Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::DoubleDot))))]
6464 #[case::args_missing_rparen(
6465 vec![
6466 token(TokenKind::Ident(SmolStr::new("foo"))),
6467 token(TokenKind::LParen),
6468 token(TokenKind::StringLiteral("bar".to_owned())),
6469 token(TokenKind::Eof)
6471 ],
6472 Err(SyntaxError::ExpectedClosingParen(
6473 token(TokenKind::Eof),
6474 Some(Box::new(token(TokenKind::LParen))),
6475 ))
6476 )]
6477 #[case::args_unexpected_token(
6478 vec![
6479 token(TokenKind::Ident(SmolStr::new("foo"))),
6480 token(TokenKind::LParen),
6481 token(TokenKind::NumberLiteral(1.into())),
6482 token(TokenKind::Colon), token(TokenKind::RParen),
6484 token(TokenKind::Eof)
6485 ],
6486 Err(SyntaxError::ExpectedClosingParen(
6487 token(TokenKind::Colon),
6488 Some(Box::new(token(TokenKind::LParen))),
6489 ))
6490 )]
6491 #[case::args_leading_comma(
6492 vec![
6493 token(TokenKind::Ident(SmolStr::new("foo"))),
6494 token(TokenKind::LParen),
6495 token(TokenKind::Comma),
6496 token(TokenKind::Ident(SmolStr::new("bar"))),
6497 token(TokenKind::RParen),
6498 token(TokenKind::Eof)
6499 ],
6500 Err(SyntaxError::UnexpectedToken(token(TokenKind::Comma)))
6501 )]
6502 #[case::args_double_comma(
6503 vec![
6504 token(TokenKind::Ident(SmolStr::new("foo"))),
6505 token(TokenKind::LParen),
6506 token(TokenKind::Ident(SmolStr::new("bar"))),
6507 token(TokenKind::Comma),
6508 token(TokenKind::Comma),
6509 token(TokenKind::Ident(SmolStr::new("baz"))),
6510 token(TokenKind::RParen),
6511 token(TokenKind::Eof)
6512 ],
6513 Err(SyntaxError::UnexpectedToken(token(TokenKind::Comma)))
6514 )]
6515 #[case::binary_operator_chaining(
6516 vec![
6517 token(TokenKind::NumberLiteral(2.into())),
6518 token(TokenKind::Gt),
6519 token(TokenKind::NumberLiteral(1.into())),
6520 token(TokenKind::Or),
6521 token(TokenKind::NumberLiteral(2.into())),
6522 token(TokenKind::Gt),
6523 token(TokenKind::NumberLiteral(1.into())),
6524 token(TokenKind::Eof)
6525 ],
6526 Ok(vec![
6527 Shared::new(Node {
6528 token_id: 3.into(),
6529 expr: Shared::new(Expr::Or(vec![
6530 Shared::new(Node {
6531 token_id: 1.into(),
6532 expr: Shared::new(Expr::Call(
6533 IdentWithToken::new_with_token(constants::builtins::GT, Some(Shared::new(token(TokenKind::Gt)))),
6534 smallvec![
6535 Shared::new(Node {
6536 token_id: 0.into(),
6537 expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
6538 }),
6539 Shared::new(Node {
6540 token_id: 2.into(),
6541 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
6542 }),
6543 ],
6544 )),
6545 }),
6546 Shared::new(Node {
6547 token_id: 5.into(),
6548 expr: Shared::new(Expr::Call(
6549 IdentWithToken::new_with_token(constants::builtins::GT, Some(Shared::new(token(TokenKind::Gt)))),
6550 smallvec![
6551 Shared::new(Node {
6552 token_id: 4.into(),
6553 expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
6554 }),
6555 Shared::new(Node {
6556 token_id: 6.into(),
6557 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
6558 }),
6559 ],
6560 )),
6561 }),
6562 ])),
6563 })
6564 ]))]
6565 #[case::not_simple(
6566 vec![
6567 token(TokenKind::Not),
6568 token(TokenKind::BoolLiteral(false)),
6569 token(TokenKind::Eof)
6570 ],
6571 Ok(vec![
6572 Shared::new(Node {
6573 token_id: 0.into(),
6574 expr: Shared::new(Expr::Call(
6575 IdentWithToken::new_with_token(constants::builtins::NOT, Some(Shared::new(token(TokenKind::Not)))),
6576 smallvec![
6577 Shared::new(Node {
6578 token_id: 1.into(),
6579 expr: Shared::new(Expr::Literal(Literal::Bool(false))),
6580 }),
6581 ],
6582 )),
6583 })
6584 ]))]
6585 #[case::not_with_expr(
6586 vec![
6587 token(TokenKind::Not),
6588 token(TokenKind::Ident(SmolStr::new("x"))),
6589 token(TokenKind::Eof)
6590 ],
6591 Ok(vec![
6592 Shared::new(Node {
6593 token_id: 0.into(),
6594 expr: Shared::new(Expr::Call(
6595 IdentWithToken::new_with_token(constants::builtins::NOT, Some(Shared::new(token(TokenKind::Not)))),
6596 smallvec![
6597 Shared::new(Node {
6598 token_id: 1.into(),
6599 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
6600 }),
6601 ],
6602 )),
6603 })
6604 ]))]
6605 #[case::bracket_access_with_number(
6606 vec![
6607 token(TokenKind::Ident(SmolStr::new("arr"))),
6608 token(TokenKind::LBracket),
6609 token(TokenKind::NumberLiteral(5.into())),
6610 token(TokenKind::RBracket),
6611 token(TokenKind::Eof)
6612 ],
6613 Ok(vec![
6614 Shared::new(Node {
6615 token_id: 2.into(),
6616 expr: Shared::new(Expr::Call(
6617 IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
6618 smallvec![
6619 Shared::new(Node {
6620 token_id: 0.into(),
6621 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
6622 }),
6623 Shared::new(Node {
6624 token_id: 1.into(),
6625 expr: Shared::new(Expr::Literal(Literal::Number(5.into()))),
6626 }),
6627 ],
6628 )),
6629 })
6630 ]))]
6631 #[case::bracket_access_with_string(
6632 vec![
6633 token(TokenKind::Ident(SmolStr::new("dict"))),
6634 token(TokenKind::LBracket),
6635 token(TokenKind::StringLiteral("key".to_owned())),
6636 token(TokenKind::RBracket),
6637 token(TokenKind::Eof)
6638 ],
6639 Ok(vec![
6640 Shared::new(Node {
6641 token_id: 2.into(),
6642 expr: Shared::new(Expr::Call(
6643 IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("dict")))))),
6644 smallvec![
6645 Shared::new(Node {
6646 token_id: 0.into(),
6647 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token(constants::builtins::DICT, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("dict")))))))),
6648 }),
6649 Shared::new(Node {
6650 token_id: 1.into(),
6651 expr: Shared::new(Expr::Literal(Literal::String("key".to_owned()))),
6652 }),
6653 ],
6654 )),
6655 })
6656 ]))]
6657 #[case::bracket_access_error_missing_rbracket(
6658 vec![
6659 token(TokenKind::Ident(SmolStr::new("arr"))),
6660 token(TokenKind::LBracket),
6661 token(TokenKind::NumberLiteral(5.into())),
6662 token(TokenKind::Eof)
6663 ],
6664 Err(SyntaxError::ExpectedClosingBracket(
6665 token(TokenKind::Eof),
6666 Some(Box::new(token(TokenKind::LBracket))),
6667 )))]
6668 #[case::slice_access_with_numbers(
6669 vec![
6670 token(TokenKind::Ident(SmolStr::new("arr"))),
6671 token(TokenKind::LBracket),
6672 token(TokenKind::NumberLiteral(1.into())),
6673 token(TokenKind::Colon),
6674 token(TokenKind::NumberLiteral(3.into())),
6675 token(TokenKind::RBracket),
6676 token(TokenKind::Eof)
6677 ],
6678 Ok(vec![
6679 Shared::new(Node {
6680 token_id: 5.into(),
6681 expr: Shared::new(Expr::Call(
6682 IdentWithToken::new_with_token(constants::builtins::SLICE, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
6683 smallvec![
6684 Shared::new(Node {
6685 token_id: 0.into(),
6686 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
6687 }),
6688 Shared::new(Node {
6689 token_id: 1.into(),
6690 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
6691 }),
6692 Shared::new(Node {
6693 token_id: 2.into(),
6694 expr: Shared::new(Expr::Literal(Literal::Number(3.into()))),
6695 }),
6696 ],
6697 )),
6698 })
6699 ]))]
6700 #[case::slice_access_with_variables(
6701 vec![
6702 token(TokenKind::Ident(SmolStr::new("items"))),
6703 token(TokenKind::LBracket),
6704 token(TokenKind::Ident(SmolStr::new("start"))),
6705 token(TokenKind::Colon),
6706 token(TokenKind::Ident(SmolStr::new("end"))),
6707 token(TokenKind::RBracket),
6708 token(TokenKind::Eof)
6709 ],
6710 Ok(vec![
6711 Shared::new(Node {
6712 token_id: 5.into(),
6713 expr: Shared::new(Expr::Call(
6714 IdentWithToken::new_with_token(constants::builtins::SLICE, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("items")))))),
6715 smallvec![
6716 Shared::new(Node {
6717 token_id: 0.into(),
6718 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("items", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("items")))))))),
6719 }),
6720 Shared::new(Node {
6721 token_id: 1.into(),
6722 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("start", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("start")))))))),
6723 }),
6724 Shared::new(Node {
6725 token_id: 2.into(),
6726 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("end", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("end")))))))),
6727 }),
6728 ],
6729 )),
6730 })
6731 ]))]
6732 #[case::not_with_paren_expr(
6733 vec![
6734 token(TokenKind::Not),
6735 token(TokenKind::LParen),
6736 token(TokenKind::BoolLiteral(false)),
6737 token(TokenKind::RParen),
6738 token(TokenKind::Eof)
6739 ],
6740 Ok(vec![
6741 Shared::new(Node {
6742 token_id: 0.into(),
6743 expr: Shared::new(Expr::Call(
6744 IdentWithToken::new_with_token(constants::builtins::NOT, Some(Shared::new(token(TokenKind::Not)))),
6745 smallvec![
6746 Shared::new(Node {
6747 token_id: 1.into(),
6748 expr: Shared::new(Expr::Paren(
6749 Shared::new(Node {
6750 token_id: 2.into(),
6751 expr: Shared::new(Expr::Literal(Literal::Bool(false))),
6752 })
6753 )),
6754 }),
6755 ],
6756 )),
6757 })
6758 ]))]
6759 #[case::not_error_missing_rhs(
6760 vec![
6761 token(TokenKind::Not),
6762 token(TokenKind::Eof)
6763 ],
6764 Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::Not))))]
6765 #[case::break_(
6766 vec![
6767 token(TokenKind::Break),
6768 token(TokenKind::Eof)
6769 ],
6770 Ok(vec![
6771 Shared::new(Node {
6772 token_id: 0.into(),
6773 expr: Shared::new(Expr::Break(None)),
6774 })
6775 ]))]
6776 #[case::continue_(
6777 vec![
6778 token(TokenKind::Continue),
6779 token(TokenKind::Eof)
6780 ],
6781 Ok(vec![
6782 Shared::new(Node {
6783 token_id: 0.into(),
6784 expr: Shared::new(Expr::Continue),
6785 })
6786 ]))]
6787 #[case::self_bracket_access_with_number(
6788 vec![
6789 token(TokenKind::Self_),
6790 token(TokenKind::LBracket),
6791 token(TokenKind::NumberLiteral(5.into())),
6792 token(TokenKind::RBracket),
6793 token(TokenKind::Eof)
6794 ],
6795 Ok(vec![
6796 Shared::new(Node {
6797 token_id: 2.into(),
6798 expr: Shared::new(Expr::Call(
6799 IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Self_)))),
6800 smallvec![
6801 Shared::new(Node {
6802 token_id: 0.into(),
6803 expr: Shared::new(Expr::Self_),
6804 }),
6805 Shared::new(Node {
6806 token_id: 1.into(),
6807 expr: Shared::new(Expr::Literal(Literal::Number(5.into()))),
6808 }),
6809 ],
6810 )),
6811 })
6812 ]))]
6813 #[case::self_bracket_access_with_string(
6814 vec![
6815 token(TokenKind::Self_),
6816 token(TokenKind::LBracket),
6817 token(TokenKind::StringLiteral("key".to_owned())),
6818 token(TokenKind::RBracket),
6819 token(TokenKind::Eof)
6820 ],
6821 Ok(vec![
6822 Shared::new(Node {
6823 token_id: 2.into(),
6824 expr: Shared::new(Expr::Call(
6825 IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Self_)))),
6826 smallvec![
6827 Shared::new(Node {
6828 token_id: 0.into(),
6829 expr: Shared::new(Expr::Self_),
6830 }),
6831 Shared::new(Node {
6832 token_id: 1.into(),
6833 expr: Shared::new(Expr::Literal(Literal::String("key".to_owned()))),
6834 }),
6835 ],
6836 )),
6837 })
6838 ]))]
6839 #[case::function_call_with_index_access(
6841 vec![
6842 token(TokenKind::Ident(SmolStr::new("foo"))),
6843 token(TokenKind::LParen),
6844 token(TokenKind::RParen),
6845 token(TokenKind::LBracket),
6846 token(TokenKind::NumberLiteral(0.into())),
6847 token(TokenKind::RBracket),
6848 token(TokenKind::Eof)
6849 ],
6850 Ok(vec![
6851 Shared::new(Node {
6852 token_id: 2.into(),
6853 expr: Shared::new(Expr::Call(
6854 IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("foo")))))),
6855 smallvec![
6856 Shared::new(Node {
6857 token_id: 0.into(),
6858 expr: Shared::new(Expr::Call(
6859 IdentWithToken::new_with_token("foo", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("foo")))))),
6860 SmallVec::new(),
6861 )),
6862 }),
6863 Shared::new(Node {
6864 token_id: 1.into(),
6865 expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
6866 }),
6867 ],
6868 )),
6869 })
6870 ]))]
6871 #[case::function_call_with_args_and_index_access(
6873 vec![
6874 token(TokenKind::Ident(SmolStr::new("bar"))),
6875 token(TokenKind::LParen),
6876 token(TokenKind::StringLiteral("arg".to_owned())),
6877 token(TokenKind::RParen),
6878 token(TokenKind::LBracket),
6879 token(TokenKind::StringLiteral("key".to_owned())),
6880 token(TokenKind::RBracket),
6881 token(TokenKind::Eof)
6882 ],
6883 Ok(vec![
6884 Shared::new(Node {
6885 token_id: 1.into(),
6886 expr: Shared::new(Expr::Call(
6887 IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("bar")))))),
6888 smallvec![
6889 Shared::new(Node {
6890 token_id: 1.into(),
6891 expr: Shared::new(Expr::Call(
6892 IdentWithToken::new_with_token("bar", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("bar")))))),
6893 smallvec![
6894 Shared::new(Node {
6895 token_id: 0.into(),
6896 expr: Shared::new(Expr::Literal(Literal::String("arg".to_owned()))),
6897 })
6898 ],
6899 )),
6900 }),
6901 Shared::new(Node {
6902 token_id: 2.into(),
6903 expr: Shared::new(Expr::Literal(Literal::String("key".to_owned()))),
6904 }),
6905 ],
6906 )),
6907 })
6908 ]))]
6909 #[case::function_call_with_chained_index_access(
6911 vec![
6912 token(TokenKind::Ident(SmolStr::new("baz"))),
6913 token(TokenKind::LParen),
6914 token(TokenKind::RParen),
6915 token(TokenKind::LBracket),
6916 token(TokenKind::NumberLiteral(0.into())),
6917 token(TokenKind::RBracket),
6918 token(TokenKind::LBracket),
6919 token(TokenKind::NumberLiteral(1.into())),
6920 token(TokenKind::RBracket),
6921 token(TokenKind::Eof)
6922 ],
6923 Ok(vec![
6924 Shared::new(Node {
6925 token_id: 2.into(),
6926 expr: Shared::new(Expr::Call(
6927 IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("baz")))))),
6928 smallvec![
6929 Shared::new(Node {
6930 token_id: 2.into(),
6931 expr: Shared::new(Expr::Call(
6932 IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("baz")))))),
6933 smallvec![
6934 Shared::new(Node {
6935 token_id: 0.into(),
6936 expr: Shared::new(Expr::Call(
6937 IdentWithToken::new_with_token("baz", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("baz")))))),
6938 SmallVec::new(),
6939 )),
6940 }),
6941 Shared::new(Node {
6942 token_id: 1.into(),
6943 expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
6944 }),
6945 ],
6946 )),
6947 }),
6948 Shared::new(Node {
6949 token_id: 3.into(),
6950 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
6951 }),
6952 ],
6953 )),
6954 })
6955 ]))]
6956 #[case::try_without_catch(
6957 vec![
6958 token(TokenKind::Try),
6959 token(TokenKind::Colon),
6960 token(TokenKind::Ident(SmolStr::new("error_expr"))),
6961 token(TokenKind::Eof),
6962 ],
6963 Ok(vec![Shared::new(Node {
6964 token_id: 2.into(),
6965 expr: Shared::new(Expr::Try(
6966 Shared::new(Node {
6967 token_id: 2.into(),
6968 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("error_expr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("error_expr")))))))),
6969 }),
6970 Shared::new(Node {
6971 token_id: 0.into(),
6972 expr: Shared::new(Expr::Literal(Literal::None)),
6973 }),
6974 )),
6975 })])
6976 )]
6977 #[case::index_access_with_function_call(
6979 vec![
6980 token(TokenKind::Ident(SmolStr::new("arr"))),
6981 token(TokenKind::LBracket),
6982 token(TokenKind::NumberLiteral(0.into())),
6983 token(TokenKind::RBracket),
6984 token(TokenKind::LParen),
6985 token(TokenKind::RParen),
6986 token(TokenKind::Eof)
6987 ],
6988 Ok(vec![
6989 Shared::new(Node {
6990 token_id: 2.into(),
6991 expr: Shared::new(Expr::CallDynamic(
6992 Shared::new(Node {
6993 token_id: 2.into(),
6994 expr: Shared::new(Expr::Call(
6995 IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
6996 smallvec![
6997 Shared::new(Node {
6998 token_id: 0.into(),
6999 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
7000 }),
7001 Shared::new(Node {
7002 token_id: 1.into(),
7003 expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
7004 }),
7005 ],
7006 )),
7007 }),
7008 SmallVec::new(),
7009 )),
7010 })
7011 ]))]
7012 #[case::index_access_with_function_call_and_args(
7014 vec![
7015 token(TokenKind::Ident(SmolStr::new("arr"))),
7016 token(TokenKind::LBracket),
7017 token(TokenKind::NumberLiteral(0.into())),
7018 token(TokenKind::RBracket),
7019 token(TokenKind::LParen),
7020 token(TokenKind::StringLiteral("test".to_owned())),
7021 token(TokenKind::RParen),
7022 token(TokenKind::Eof)
7023 ],
7024 Ok(vec![
7025 Shared::new(Node {
7026 token_id: 2.into(),
7027 expr: Shared::new(Expr::CallDynamic(
7028 Shared::new(Node {
7029 token_id: 2.into(),
7030 expr: Shared::new(Expr::Call(
7031 IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
7032 smallvec![
7033 Shared::new(Node {
7034 token_id: 0.into(),
7035 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
7036 }),
7037 Shared::new(Node {
7038 token_id: 1.into(),
7039 expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
7040 }),
7041 ],
7042 )),
7043 }),
7044 smallvec![
7045 Shared::new(Node {
7046 token_id: 3.into(),
7047 expr: Shared::new(Expr::Literal(Literal::String("test".to_owned()))),
7048 })
7049 ],
7050 )),
7051 })
7052 ]))]
7053 #[case::group_expr_with_index_access(
7055 vec![
7056 token(TokenKind::LParen),
7057 token(TokenKind::Ident(SmolStr::new("x"))),
7058 token(TokenKind::RParen),
7059 token(TokenKind::LBracket),
7060 token(TokenKind::NumberLiteral(0.into())),
7061 token(TokenKind::RBracket),
7062 token(TokenKind::Eof),
7063 ],
7064 Ok(vec![
7065 Shared::new(Node {
7066 token_id: 0.into(),
7067 expr: Shared::new(Expr::Call(
7068 IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::LParen)))),
7069 smallvec![
7070 Shared::new(Node {
7071 token_id: 0.into(),
7072 expr: Shared::new(Expr::Paren(
7073 Shared::new(Node {
7074 token_id: 1.into(),
7075 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
7076 }),
7077 )),
7078 }),
7079 Shared::new(Node {
7080 token_id: 2.into(),
7081 expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
7082 }),
7083 ],
7084 )),
7085 })
7086 ]))]
7087 #[case::group_expr_with_dynamic_call(
7089 vec![
7090 token(TokenKind::LParen),
7091 token(TokenKind::Ident(SmolStr::new("x"))),
7092 token(TokenKind::RParen),
7093 token(TokenKind::LParen),
7094 token(TokenKind::StringLiteral("test".to_owned())),
7095 token(TokenKind::RParen),
7096 token(TokenKind::Eof),
7097 ],
7098 Ok(vec![
7099 Shared::new(Node {
7100 token_id: 0.into(),
7101 expr: Shared::new(Expr::CallDynamic(
7102 Shared::new(Node {
7103 token_id: 0.into(),
7104 expr: Shared::new(Expr::Paren(
7105 Shared::new(Node {
7106 token_id: 1.into(),
7107 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
7108 }),
7109 )),
7110 }),
7111 smallvec![
7112 Shared::new(Node {
7113 token_id: 2.into(),
7114 expr: Shared::new(Expr::Literal(Literal::String("test".to_owned()))),
7115 }),
7116 ],
7117 )),
7118 })
7119 ]))]
7120 #[case::group_expr_with_chained_call_and_index(
7122 vec![
7123 token(TokenKind::LParen),
7124 token(TokenKind::Ident(SmolStr::new("f"))),
7125 token(TokenKind::RParen),
7126 token(TokenKind::LParen),
7127 token(TokenKind::StringLiteral("a".to_owned())),
7128 token(TokenKind::RParen),
7129 token(TokenKind::LBracket),
7130 token(TokenKind::NumberLiteral(0.into())),
7131 token(TokenKind::RBracket),
7132 token(TokenKind::Eof),
7133 ],
7134 Ok(vec![
7135 Shared::new(Node {
7136 token_id: 0.into(),
7137 expr: Shared::new(Expr::Call(
7138 IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::LParen)))),
7139 smallvec![
7140 Shared::new(Node {
7141 token_id: 3.into(),
7142 expr: Shared::new(Expr::CallDynamic(
7143 Shared::new(Node {
7144 token_id: 0.into(),
7145 expr: Shared::new(Expr::Paren(
7146 Shared::new(Node {
7147 token_id: 1.into(),
7148 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("f", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("f")))))))),
7149 }),
7150 )),
7151 }),
7152 smallvec![
7153 Shared::new(Node {
7154 token_id: 2.into(),
7155 expr: Shared::new(Expr::Literal(Literal::String("a".to_owned()))),
7156 }),
7157 ],
7158 )),
7159 }),
7160 Shared::new(Node {
7161 token_id: 4.into(),
7162 expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
7163 }),
7164 ],
7165 )),
7166 })
7167 ]))]
7168 #[case::array_literal_with_index_access(
7170 vec![
7171 token(TokenKind::LBracket),
7172 token(TokenKind::NumberLiteral(1.into())),
7173 token(TokenKind::Comma),
7174 token(TokenKind::NumberLiteral(2.into())),
7175 token(TokenKind::RBracket),
7176 token(TokenKind::LBracket),
7177 token(TokenKind::NumberLiteral(0.into())),
7178 token(TokenKind::RBracket),
7179 token(TokenKind::Eof),
7180 ],
7181 Ok(vec![
7182 Shared::new(Node {
7183 token_id: 0.into(),
7184 expr: Shared::new(Expr::Call(
7185 IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::LBracket)))),
7186 smallvec![
7187 Shared::new(Node {
7188 token_id: 0.into(),
7189 expr: Shared::new(Expr::Call(
7190 IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::LBracket)))),
7191 smallvec![
7192 Shared::new(Node {
7193 token_id: 1.into(),
7194 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
7195 }),
7196 Shared::new(Node {
7197 token_id: 2.into(),
7198 expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
7199 }),
7200 ],
7201 )),
7202 }),
7203 Shared::new(Node {
7204 token_id: 3.into(),
7205 expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
7206 }),
7207 ],
7208 )),
7209 })
7210 ]))]
7211 #[case::chained_index_access_with_function_call(
7213 vec![
7214 token(TokenKind::Ident(SmolStr::new("arr"))),
7215 token(TokenKind::LBracket),
7216 token(TokenKind::NumberLiteral(0.into())),
7217 token(TokenKind::RBracket),
7218 token(TokenKind::LBracket),
7219 token(TokenKind::NumberLiteral(1.into())),
7220 token(TokenKind::RBracket),
7221 token(TokenKind::LParen),
7222 token(TokenKind::RParen),
7223 token(TokenKind::Eof)
7224 ],
7225 Ok(vec![
7226 Shared::new(Node {
7227 token_id: 4.into(),
7228 expr: Shared::new(Expr::CallDynamic(
7229 Shared::new(Node {
7230 token_id: 4.into(),
7231 expr: Shared::new(Expr::Call(
7232 IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
7233 smallvec![
7234 Shared::new(Node {
7235 token_id: 2.into(),
7236 expr: Shared::new(Expr::Call(
7237 IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
7238 smallvec![
7239 Shared::new(Node {
7240 token_id: 0.into(),
7241 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
7242 }),
7243 Shared::new(Node {
7244 token_id: 1.into(),
7245 expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
7246 }),
7247 ],
7248 )),
7249 }),
7250 Shared::new(Node {
7251 token_id: 3.into(),
7252 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
7253 }),
7254 ],
7255 )),
7256 }),
7257 SmallVec::new(),
7258 )),
7259 })
7260 ]))]
7261 #[case::function_call_with_question_mark(
7262 vec![
7263 token(TokenKind::Ident(SmolStr::new("foo"))),
7264 token(TokenKind::LParen),
7265 token(TokenKind::StringLiteral("arg".to_owned())),
7266 token(TokenKind::RParen),
7267 token(TokenKind::Question),
7268 token(TokenKind::Eof),
7269 ],
7270 Ok(vec![Shared::new(Node {
7271 token_id: 1.into(),
7272 expr: Shared::new(Expr::Try(
7273 Shared::new(Node {
7274 token_id: 1.into(),
7275 expr: Shared::new(Expr::Call(
7276 IdentWithToken::new_with_token("foo", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("foo")))))),
7277 smallvec![
7278 Shared::new(Node {
7279 token_id: 0.into(),
7280 expr: Shared::new(Expr::Literal(Literal::String("arg".to_owned()))),
7281 }),
7282 ],
7283 )),
7284 }),
7285 Shared::new(Node {
7286 token_id: 1.into(),
7287 expr: Shared::new(Expr::Literal(Literal::None)),
7288 }),
7289 )),
7290 })])
7291 )]
7292 #[case::question_mark_after_call(
7293 vec![
7294 token(TokenKind::Ident(SmolStr::new("foo"))),
7295 token(TokenKind::LParen),
7296 token(TokenKind::RParen),
7297 token(TokenKind::Question),
7298 token(TokenKind::Eof),
7299 ],
7300 Ok(vec![
7301 Shared::new(Node {
7302 token_id: 1.into(),
7303 expr: Shared::new(Expr::Try(
7304 Shared::new(Node {
7305 token_id: 0.into(),
7306 expr: Shared::new(Expr::Call(
7307 IdentWithToken::new_with_token("foo", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("foo")))))),
7308 SmallVec::new(),
7309 )),
7310 }),
7311 Shared::new(Node {
7312 token_id: 0.into(),
7313 expr: Shared::new(Expr::Literal(Literal::None)),
7314 }),
7315 )),
7316 })
7317 ]))]
7318 #[case::question_mark_after_call_with_args(
7319 vec![
7320 token(TokenKind::Ident(SmolStr::new("bar"))),
7321 token(TokenKind::LParen),
7322 token(TokenKind::StringLiteral("arg".to_owned())),
7323 token(TokenKind::RParen),
7324 token(TokenKind::Question),
7325 token(TokenKind::Eof),
7326 ],
7327 Ok(vec![
7328 Shared::new(Node {
7329 token_id: 1.into(),
7330 expr: Shared::new(Expr::Try(
7331 Shared::new(Node {
7332 token_id: 1.into(),
7333 expr: Shared::new(Expr::Call(
7334 IdentWithToken::new_with_token("bar", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("bar")))))),
7335 smallvec![
7336 Shared::new(Node {
7337 token_id: 0.into(),
7338 expr: Shared::new(Expr::Literal(Literal::String("arg".to_owned()))),
7339 }),
7340 ],
7341 )),
7342 }),
7343 Shared::new(Node {
7344 token_id: 1.into(),
7345 expr: Shared::new(Expr::Literal(Literal::None)),
7346 }),
7347 )),
7348 })
7349 ]))]
7350 #[case::question_mark_after_call_error(
7351 vec![
7352 token(TokenKind::Ident(SmolStr::new("foo"))),
7353 token(TokenKind::Question),
7354 token(TokenKind::Eof),
7355 ],
7356 Err(SyntaxError::UnexpectedToken(token(TokenKind::Ident("foo".into())))))]
7357 #[case::coalesce_simple(
7358 vec![
7359 token(TokenKind::StringLiteral("foo".to_owned())),
7360 token(TokenKind::Coalesce),
7361 token(TokenKind::StringLiteral("bar".to_owned())),
7362 token(TokenKind::Eof)
7363 ],
7364 Ok(vec![
7365 Shared::new(Node {
7366 token_id: 1.into(),
7367 expr: Shared::new(Expr::Call(
7368 IdentWithToken::new_with_token(constants::builtins::COALESCE, Some(Shared::new(token(TokenKind::Coalesce)))),
7369 smallvec![
7370 Shared::new(Node {
7371 token_id: 0.into(),
7372 expr: Shared::new(Expr::Literal(Literal::String("foo".to_owned()))),
7373 }),
7374 Shared::new(Node {
7375 token_id: 2.into(),
7376 expr: Shared::new(Expr::Literal(Literal::String("bar".to_owned()))),
7377 }),
7378 ],
7379 )),
7380 })
7381 ]))]
7382 #[case::coalesce_with_none(
7383 vec![
7384 token(TokenKind::None),
7385 token(TokenKind::Coalesce),
7386 token(TokenKind::StringLiteral("default".to_owned())),
7387 token(TokenKind::Eof)
7388 ],
7389 Ok(vec![
7390 Shared::new(Node {
7391 token_id: 1.into(),
7392 expr: Shared::new(Expr::Call(
7393 IdentWithToken::new_with_token(constants::builtins::COALESCE, Some(Shared::new(token(TokenKind::Coalesce)))),
7394 smallvec![
7395 Shared::new(Node {
7396 token_id: 0.into(),
7397 expr: Shared::new(Expr::Literal(Literal::None)),
7398 }),
7399 Shared::new(Node {
7400 token_id: 2.into(),
7401 expr: Shared::new(Expr::Literal(Literal::String("default".to_owned()))),
7402 }),
7403 ],
7404 )),
7405 })
7406 ]))]
7407 #[case::coalesce_with_identifiers(
7408 vec![
7409 token(TokenKind::Ident(SmolStr::new("x"))),
7410 token(TokenKind::Coalesce),
7411 token(TokenKind::Ident(SmolStr::new("y"))),
7412 token(TokenKind::Eof)
7413 ],
7414 Ok(vec![
7415 Shared::new(Node {
7416 token_id: 1.into(),
7417 expr: Shared::new(Expr::Call(
7418 IdentWithToken::new_with_token(constants::builtins::COALESCE, Some(Shared::new(token(TokenKind::Coalesce)))),
7419 smallvec![
7420 Shared::new(Node {
7421 token_id: 0.into(),
7422 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
7423 }),
7424 Shared::new(Node {
7425 token_id: 2.into(),
7426 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y")))))))),
7427 }),
7428 ],
7429 )),
7430 })
7431 ]))]
7432 #[case::coalesce_error_missing_rhs(
7433 vec![
7434 token(TokenKind::StringLiteral("foo".to_owned())),
7435 token(TokenKind::Coalesce),
7436 token(TokenKind::Eof)
7437 ],
7438 Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::Coalesce))))]
7439 #[case::negate_simple(
7440 vec![
7441 token(TokenKind::Minus),
7442 token(TokenKind::NumberLiteral(42.into())),
7443 token(TokenKind::Eof)
7444 ],
7445 Ok(vec![
7446 Shared::new(Node {
7447 token_id: 0.into(),
7448 expr: Shared::new(Expr::Call(
7449 IdentWithToken::new_with_token(constants::builtins::NEGATE, Some(Shared::new(token(TokenKind::Minus)))),
7450 smallvec![
7451 Shared::new(Node {
7452 token_id: 1.into(),
7453 expr: Shared::new(Expr::Literal(Literal::Number(42.into()))),
7454 }),
7455 ],
7456 )),
7457 })
7458 ]))]
7459 #[case::negate_with_identifier(
7460 vec![
7461 token(TokenKind::Minus),
7462 token(TokenKind::Ident(SmolStr::new("x"))),
7463 token(TokenKind::Eof)
7464 ],
7465 Ok(vec![
7466 Shared::new(Node {
7467 token_id: 0.into(),
7468 expr: Shared::new(Expr::Call(
7469 IdentWithToken::new_with_token(constants::builtins::NEGATE, Some(Shared::new(token(TokenKind::Minus)))),
7470 smallvec![
7471 Shared::new(Node {
7472 token_id: 1.into(),
7473 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
7474 }),
7475 ],
7476 )),
7477 })
7478 ]))]
7479 #[case::negate_error_missing_rhs(
7480 vec![
7481 token(TokenKind::Minus),
7482 token(TokenKind::Eof)
7483 ],
7484 Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::Minus))))]
7485 #[case::import_simple(
7486 vec![
7487 token(TokenKind::Import),
7488 token(TokenKind::StringLiteral("name".to_owned())),
7489 token(TokenKind::Eof),
7490 ],
7491 Ok(vec![
7492 Shared::new(Node {
7493 token_id: 0.into(),
7494 expr: Shared::new(Expr::Import(
7495 Literal::String("name".to_owned()),
7496 )),
7497 })
7498 ]))]
7499 #[case::import_as(
7500 vec![
7501 token(TokenKind::Import),
7502 token(TokenKind::StringLiteral("name".to_owned())),
7503 token(TokenKind::Eof),
7504 ],
7505 Ok(vec![
7506 Shared::new(Node {
7507 token_id: 0.into(),
7508 expr: Shared::new(Expr::Import(
7509 Literal::String("name".to_owned()),
7510 )),
7511 })
7512 ]))]
7513 #[case::qualified_access(
7514 vec![
7515 token(TokenKind::Ident(SmolStr::new("test"))),
7516 token(TokenKind::DoubleColon),
7517 token(TokenKind::Ident(SmolStr::new("foo"))),
7518 token(TokenKind::Eof),
7519 ],
7520 Ok(vec![
7521 Shared::new(Node {
7522 token_id: 1.into(),
7523 expr: Shared::new(Expr::QualifiedAccess(
7524 vec![IdentWithToken::new_with_token("test", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("test"))))))],
7525 AccessTarget::Ident(IdentWithToken::new_with_token("foo", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("foo")))))),
7526 ))),
7527 })
7528 ]))]
7529 #[case::qualified_access_with_call(
7530 vec![
7531 token(TokenKind::Ident(SmolStr::new("mod"))),
7532 token(TokenKind::DoubleColon),
7533 token(TokenKind::Ident(SmolStr::new("func"))),
7534 token(TokenKind::LParen),
7535 token(TokenKind::StringLiteral("arg".to_owned())),
7536 token(TokenKind::RParen),
7537 token(TokenKind::Eof),
7538 ],
7539 Ok(vec![
7540 Shared::new(Node {
7541 token_id: 4.into(),
7542 expr: Shared::new(Expr::QualifiedAccess(
7543 vec![IdentWithToken::new_with_token("mod", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("mod"))))))],
7544 AccessTarget::Call(
7545 IdentWithToken::new_with_token("func", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("func")))))),
7546 smallvec![
7547 Shared::new(Node {
7548 token_id: 0.into(),
7549 expr: Shared::new(Expr::Literal(Literal::String("arg".to_owned()))),
7550 }),
7551 ],
7552 ),
7553 )),
7554 })
7555 ]))]
7556 #[case::qualified_access_multi_level(
7557 vec![
7558 token(TokenKind::Ident(SmolStr::new("mod1"))),
7559 token(TokenKind::DoubleColon),
7560 token(TokenKind::Ident(SmolStr::new("mod2"))),
7561 token(TokenKind::DoubleColon),
7562 token(TokenKind::Ident(SmolStr::new("func"))),
7563 token(TokenKind::LParen),
7564 token(TokenKind::RParen),
7565 token(TokenKind::Eof),
7566 ],
7567 Ok(vec![
7568 Shared::new(Node {
7569 token_id: 4.into(),
7570 expr: Shared::new(Expr::QualifiedAccess(
7571 vec![
7572 IdentWithToken::new_with_token("mod1", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("mod1")))))),
7573 IdentWithToken::new_with_token("mod2", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("mod2")))))),
7574 ],
7575 AccessTarget::Call(
7576 IdentWithToken::new_with_token("func", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("func")))))),
7577 smallvec![],
7578 ),
7579 )),
7580 })
7581 ]))]
7582 #[case::slice_access_with_start_only(
7583 vec![
7584 token(TokenKind::Ident(SmolStr::new("arr"))),
7585 token(TokenKind::LBracket),
7586 token(TokenKind::NumberLiteral(1.into())),
7587 token(TokenKind::Colon),
7588 token(TokenKind::RBracket),
7589 token(TokenKind::Eof)
7590 ],
7591 Ok(vec![
7592 Shared::new(Node {
7593 token_id: 4.into(),
7594 expr: Shared::new(Expr::Call(
7595 IdentWithToken::new_with_token(constants::builtins::SLICE, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
7596 smallvec![
7597 Shared::new(Node {
7598 token_id: 0.into(),
7599 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
7600 }),
7601 Shared::new(Node {
7602 token_id: 1.into(),
7603 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
7604 }),
7605 Shared::new(Node {
7606 token_id: 3.into(),
7607 expr: Shared::new(Expr::Call(
7608 IdentWithToken::new_with_token("len", None),
7609 smallvec![
7610 Shared::new(Node {
7611 token_id: 0.into(),
7612 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
7613 }),
7614 ],
7615 )),
7616 }),
7617 ],
7618 )),
7619 })
7620 ]))]
7621 #[case::slice_access_with_end_only(
7622 vec![
7623 token(TokenKind::Ident(SmolStr::new("arr"))),
7624 token(TokenKind::LBracket),
7625 token(TokenKind::Colon),
7626 token(TokenKind::NumberLiteral(2.into())),
7627 token(TokenKind::RBracket),
7628 token(TokenKind::Eof),
7629 ],
7630 Ok(vec![
7631 Shared::new(Node {
7632 token_id: 3.into(),
7633 expr: Shared::new(Expr::Call(
7634 IdentWithToken::new_with_token(constants::builtins::SLICE, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
7635 smallvec![
7636 Shared::new(Node {
7637 token_id: 0.into(),
7638 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
7639 }),
7640 Shared::new(Node {
7641 token_id: 1.into(),
7642 expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
7643 }),
7644 Shared::new(Node {
7645 token_id: 2.into(),
7646 expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
7647 }),
7648 ],
7649 )),
7650 })
7651 ]))]
7652 #[case::qualified_access_with_call_and_slice(
7653 vec![
7654 token(TokenKind::Ident(SmolStr::new("mod"))),
7655 token(TokenKind::DoubleColon),
7656 token(TokenKind::Ident(SmolStr::new("func"))),
7657 token(TokenKind::LParen),
7658 token(TokenKind::RParen),
7659 token(TokenKind::LBracket),
7660 token(TokenKind::NumberLiteral(0.into())),
7661 token(TokenKind::Colon),
7662 token(TokenKind::NumberLiteral(2.into())),
7663 token(TokenKind::RBracket),
7664 token(TokenKind::Eof),
7665 ],
7666 Ok(vec![
7667 Shared::new(Node {
7668 token_id: 3.into(),
7669 expr: Shared::new(Expr::Call(
7670 IdentWithToken::new_with_token(constants::builtins::SLICE, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("mod")))))),
7671 smallvec![
7672 Shared::new(Node {
7673 token_id: 0.into(),
7674 expr: Shared::new(Expr::QualifiedAccess(
7675 vec![IdentWithToken::new_with_token("mod", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("mod"))))))],
7676 AccessTarget::Call(
7677 IdentWithToken::new_with_token("func", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("func")))))),
7678 smallvec![],
7679 ),
7680 )),
7681 }),
7682 Shared::new(Node {
7683 token_id: 1.into(),
7684 expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
7685 }),
7686 Shared::new(Node {
7687 token_id: 2.into(),
7688 expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
7689 }),
7690 ],
7691 )),
7692 })
7693 ]))]
7694 #[case::qualified_access_with_call_and_end_only_slice(
7695 vec![
7696 token(TokenKind::Ident(SmolStr::new("mod"))),
7697 token(TokenKind::DoubleColon),
7698 token(TokenKind::Ident(SmolStr::new("func"))),
7699 token(TokenKind::LParen),
7700 token(TokenKind::RParen),
7701 token(TokenKind::LBracket),
7702 token(TokenKind::Colon),
7703 token(TokenKind::NumberLiteral(1.into())),
7704 token(TokenKind::RBracket),
7705 token(TokenKind::Eof),
7706 ],
7707 Ok(vec![
7708 Shared::new(Node {
7709 token_id: 3.into(),
7710 expr: Shared::new(Expr::Call(
7711 IdentWithToken::new_with_token(constants::builtins::SLICE, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("mod")))))),
7712 smallvec![
7713 Shared::new(Node {
7714 token_id: 0.into(),
7715 expr: Shared::new(Expr::QualifiedAccess(
7716 vec![IdentWithToken::new_with_token("mod", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("mod"))))))],
7717 AccessTarget::Call(
7718 IdentWithToken::new_with_token("func", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("func")))))),
7719 smallvec![],
7720 ),
7721 )),
7722 }),
7723 Shared::new(Node {
7724 token_id: 1.into(),
7725 expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
7726 }),
7727 Shared::new(Node {
7728 token_id: 2.into(),
7729 expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
7730 }),
7731 ],
7732 )),
7733 })
7734 ]))]
7735 #[case::selector_dot_is_self(
7736 vec![
7737 token(TokenKind::Selector(SmolStr::new("."))),
7738 token(TokenKind::Eof)
7739 ],
7740 Ok(vec![
7741 Shared::new(Node {
7742 token_id: 0.into(),
7743 expr: Shared::new(Expr::Self_),
7744 })
7745 ]))]
7746 #[case::ident_with_single_attr(
7747 vec![
7748 token(TokenKind::Ident(SmolStr::new("obj"))),
7749 token(TokenKind::Selector(SmolStr::new(".name"))),
7750 token(TokenKind::Eof)
7751 ],
7752 Ok(vec![
7753 Shared::new(Node {
7754 token_id: 1.into(),
7755 expr: Shared::new(Expr::Call(
7756 IdentWithToken::new_with_token(constants::builtins::ATTR, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("obj")))))),
7757 smallvec![
7758 Shared::new(Node {
7759 token_id: 0.into(),
7760 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("obj", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("obj")))))))),
7761 }),
7762 Shared::new(Node {
7763 token_id: 1.into(),
7764 expr: Shared::new(Expr::Literal(Literal::String("name".to_owned()))),
7765 }),
7766 ],
7767 )),
7768 })
7769 ]))]
7770 #[case::function_call_result_with_attr(
7771 vec![
7772 token(TokenKind::Ident(SmolStr::new("get_user"))),
7773 token(TokenKind::LParen),
7774 token(TokenKind::RParen),
7775 token(TokenKind::Selector(SmolStr::new(".name"))),
7776 token(TokenKind::Eof)
7777 ],
7778 Ok(vec![
7779 Shared::new(Node {
7780 token_id: 3.into(),
7781 expr: Shared::new(Expr::Call(
7782 IdentWithToken::new_with_token(constants::builtins::ATTR, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("get_user")))))),
7783 smallvec![
7784 Shared::new(Node {
7785 token_id: 0.into(),
7786 expr: Shared::new(Expr::Call(
7787 IdentWithToken::new_with_token("get_user", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("get_user")))))),
7788 SmallVec::new(),
7789 )),
7790 }),
7791 Shared::new(Node {
7792 token_id: 1.into(),
7793 expr: Shared::new(Expr::Literal(Literal::String("name".to_owned()))),
7794 }),
7795 ],
7796 )),
7797 })
7798 ]))]
7799 #[case::ident_with_attr_in_pipe(
7800 vec![
7801 token(TokenKind::Ident(SmolStr::new("data"))),
7802 token(TokenKind::Pipe),
7803 token(TokenKind::Ident(SmolStr::new("obj"))),
7804 token(TokenKind::Selector(SmolStr::new(".value"))),
7805 token(TokenKind::Eof)
7806 ],
7807 Ok(vec![
7808 Shared::new(Node {
7809 token_id: 0.into(),
7810 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("data", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("data")))))))),
7811 }),
7812 Shared::new(Node {
7813 token_id: 3.into(),
7814 expr: Shared::new(Expr::Call(
7815 IdentWithToken::new_with_token(constants::builtins::ATTR, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("obj")))))),
7816 smallvec![
7817 Shared::new(Node {
7818 token_id: 1.into(),
7819 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("obj", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("obj")))))))),
7820 }),
7821 Shared::new(Node {
7822 token_id: 2.into(),
7823 expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
7824 }),
7825 ],
7826 )),
7827 })
7828 ]))]
7829 #[case::self_with_attr(
7830 vec![
7831 token(TokenKind::Self_),
7832 token(TokenKind::Selector(SmolStr::new(".value"))),
7833 token(TokenKind::Eof)
7834 ],
7835 Ok(vec![
7836 Shared::new(Node {
7837 token_id: 1.into(),
7838 expr: Shared::new(Expr::Call(
7839 IdentWithToken::new_with_token(constants::builtins::ATTR, Some(Shared::new(token(TokenKind::Self_)))),
7840 smallvec![
7841 Shared::new(Node {
7842 token_id: 0.into(),
7843 expr: Shared::new(Expr::Self_),
7844 }),
7845 Shared::new(Node {
7846 token_id: 1.into(),
7847 expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
7848 }),
7849 ],
7850 )),
7851 })
7852 ]))]
7853 #[case::pipe_equal_with_selector(
7854 vec![
7855 token(TokenKind::Selector(SmolStr::new(".h1"))),
7856 token(TokenKind::Selector(SmolStr::new(".value"))),
7857 token(TokenKind::PipeEqual),
7858 token(TokenKind::StringLiteral("new_id".to_owned())),
7859 token(TokenKind::Eof)
7860 ],
7861 Ok(vec![
7862 Shared::new(Node {
7863 token_id: 3.into(),
7864 expr: Shared::new(Expr::Call(
7865 IdentWithToken::new_with_token(constants::builtins::SET_ATTR, Some(Shared::new(token(TokenKind::StringLiteral("new_id".to_owned()))))),
7866 smallvec![
7867 Shared::new(Node {
7868 token_id: 0.into(),
7869 expr: Shared::new(Expr::Selector(selector::Selector::Heading(Some(1)))),
7870 }),
7871 Shared::new(Node {
7872 token_id: 1.into(),
7873 expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
7874 }),
7875 Shared::new(Node {
7876 token_id: 2.into(),
7877 expr: Shared::new(Expr::Literal(Literal::String("new_id".to_owned()))),
7878 }),
7879 ],
7880 )),
7881 })
7882 ]))]
7883 #[case::pipe_equal_with_ident_and_attr(
7884 vec![
7885 token(TokenKind::Ident(SmolStr::new("obj"))),
7886 token(TokenKind::Selector(SmolStr::new(".value"))),
7887 token(TokenKind::PipeEqual),
7888 token(TokenKind::StringLiteral("John".to_owned())),
7889 token(TokenKind::Eof)
7890 ],
7891 Ok(vec![
7892 Shared::new(Node {
7893 token_id: 3.into(),
7894 expr: Shared::new(Expr::Call(
7895 IdentWithToken::new_with_token(constants::builtins::SET_ATTR, Some(Shared::new(token(TokenKind::StringLiteral("John".to_owned()))))),
7896 smallvec![
7897 Shared::new(Node {
7898 token_id: 0.into(),
7899 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("obj", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("obj")))))))),
7900 }),
7901 Shared::new(Node {
7902 token_id: 1.into(),
7903 expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
7904 }),
7905 Shared::new(Node {
7906 token_id: 2.into(),
7907 expr: Shared::new(Expr::Literal(Literal::String("John".to_owned()))),
7908 }),
7909 ],
7910 )),
7911 })
7912 ]))]
7913 #[case::pipe_equal_with_self_and_attr(
7914 vec![
7915 token(TokenKind::Self_),
7916 token(TokenKind::Selector(SmolStr::new(".value"))),
7917 token(TokenKind::PipeEqual),
7918 token(TokenKind::NumberLiteral(42.into())),
7919 token(TokenKind::Eof)
7920 ],
7921 Ok(vec![
7922 Shared::new(Node {
7923 token_id: 2.into(),
7924 expr: Shared::new(Expr::Call(
7925 IdentWithToken::new_with_token(constants::builtins::SET_ATTR, Some(Shared::new(token(TokenKind::NumberLiteral(42.into()))))),
7926 smallvec![
7927 Shared::new(Node {
7928 token_id: 0.into(),
7929 expr: Shared::new(Expr::Self_),
7930 }),
7931 Shared::new(Node {
7932 token_id: 1.into(),
7933 expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
7934 }),
7935 Shared::new(Node {
7936 token_id: 2.into(),
7937 expr: Shared::new(Expr::Literal(Literal::Number(42.into()))),
7938 }),
7939 ],
7940 )),
7941 })
7942 ]))]
7943 #[case::let_with_reserved_keyword_as_value(
7944 vec![
7945 token(TokenKind::Let),
7946 token(TokenKind::Ident(SmolStr::new("aaa"))),
7947 token(TokenKind::Equal),
7948 token(TokenKind::Let), token(TokenKind::Eof)
7950 ],
7951 Err(SyntaxError::UnexpectedToken(Token {
7952 range: Range::default(),
7953 kind: TokenKind::Let,
7954 module_id: 1.into(),
7955 }))
7956 )]
7957 #[case::let_with_reserved_keyword_as_variable_and_value(
7958 vec![
7959 token(TokenKind::Let),
7960 token(TokenKind::Let), token(TokenKind::Equal),
7962 token(TokenKind::Ident(SmolStr::new("vvv"))),
7963 token(TokenKind::Eof)
7964 ],
7965 Err(SyntaxError::UnexpectedToken(Token {
7966 range: Range::default(),
7967 kind: TokenKind::Let,
7968 module_id: 1.into(),
7969 }))
7970 )]
7971 #[case::let_with_reserved_keyword_as_variable_and_value2(
7972 vec![
7973 token(TokenKind::Let),
7974 token(TokenKind::Let), token(TokenKind::Equal),
7976 token(TokenKind::Let), token(TokenKind::Eof)
7978 ],
7979 Err(SyntaxError::UnexpectedToken(Token {
7980 range: Range::default(),
7981 kind: TokenKind::Let,
7982 module_id: 1.into(),
7983 }))
7984 )]
7985 #[case::macro_basic(
7986 vec![
7987 token(TokenKind::Macro),
7988 token(TokenKind::Ident(SmolStr::new("double"))),
7989 token(TokenKind::LParen),
7990 token(TokenKind::Ident(SmolStr::new("x"))),
7991 token(TokenKind::RParen),
7992 token(TokenKind::Colon),
7993 token(TokenKind::Ident(SmolStr::new("x"))),
7994 token(TokenKind::Plus),
7995 token(TokenKind::Ident(SmolStr::new("x"))),
7996 ],
7997 Ok(vec![
7998 Shared::new(Node {
7999 token_id: 0.into(),
8000 expr: Shared::new(Expr::Macro(
8001 IdentWithToken::new_with_token("double", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("double")))))),
8002 smallvec![
8003 Param::new(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))
8004 ],
8005 Shared::new(Node {
8006 token_id: 3.into(),
8007 expr: Shared::new(Expr::Call(
8008 IdentWithToken::new_with_token(constants::builtins::ADD, Some(Shared::new(token(TokenKind::Plus)))),
8009 smallvec![
8010 Shared::new(Node {
8011 token_id: 2.into(),
8012 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
8013 }),
8014 Shared::new(Node {
8015 token_id: 4.into(),
8016 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
8017 })
8018 ]
8019 ))
8020 }),
8021 )),
8022 }),
8023 ]))]
8024 #[case::macro_with_end(
8025 vec![
8026 token(TokenKind::Macro),
8027 token(TokenKind::Ident(SmolStr::new("triple"))),
8028 token(TokenKind::LParen),
8029 token(TokenKind::Ident(SmolStr::new("x"))),
8030 token(TokenKind::RParen),
8031 token(TokenKind::Colon),
8032 token(TokenKind::Ident(SmolStr::new("x"))),
8033 token(TokenKind::Plus),
8034 token(TokenKind::Ident(SmolStr::new("x"))),
8035 token(TokenKind::Plus),
8036 token(TokenKind::Ident(SmolStr::new("x"))),
8037 ],
8038 Ok(vec![
8039 Shared::new(Node {
8040 token_id: 0.into(),
8041 expr: Shared::new(Expr::Macro(
8042 IdentWithToken::new_with_token("triple", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("triple")))))),
8043 smallvec![
8044 Param::new(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))
8045 ],
8046 Shared::new(Node {
8047 token_id: 5.into(),
8048 expr: Shared::new(Expr::Call(
8049 IdentWithToken::new_with_token(constants::builtins::ADD, Some(Shared::new(token(TokenKind::Plus)))),
8050 smallvec![
8051 Shared::new(Node {
8052 token_id: 3.into(),
8053 expr: Shared::new(Expr::Call(
8054 IdentWithToken::new_with_token(constants::builtins::ADD, Some(Shared::new(token(TokenKind::Plus)))),
8055 smallvec![
8056 Shared::new(Node {
8057 token_id: 2.into(),
8058 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
8059 }),
8060 Shared::new(Node {
8061 token_id: 4.into(),
8062 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
8063 })
8064 ]
8065 ))
8066 }),
8067 Shared::new(Node {
8068 token_id: 6.into(),
8069 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
8070 })
8071 ]
8072 ))
8073 }),
8074 )),
8075 }),
8076 ]))]
8077 #[case::macro_multiple_params(
8078 vec![
8079 token(TokenKind::Macro),
8080 token(TokenKind::Ident(SmolStr::new("add_two"))),
8081 token(TokenKind::LParen),
8082 token(TokenKind::Ident(SmolStr::new("a"))),
8083 token(TokenKind::Comma),
8084 token(TokenKind::Ident(SmolStr::new("b"))),
8085 token(TokenKind::RParen),
8086 token(TokenKind::Colon),
8087 token(TokenKind::Ident(SmolStr::new("a"))),
8088 token(TokenKind::Plus),
8089 token(TokenKind::Ident(SmolStr::new("b"))),
8090 ],
8091 Ok(vec![
8092 Shared::new(Node {
8093 token_id: 0.into(),
8094 expr: Shared::new(Expr::Macro(
8095 IdentWithToken::new_with_token("add_two", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("add_two")))))),
8096 smallvec![
8097 Param::new(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a"))))))),
8098 Param::new(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b"))))))),
8099 ],
8100 Shared::new(Node {
8101 token_id: 3.into(),
8102 expr: Shared::new(Expr::Call(
8103 IdentWithToken::new_with_token(constants::builtins::ADD, Some(Shared::new(token(TokenKind::Plus)))),
8104 smallvec![
8105 Shared::new(Node {
8106 token_id: 2.into(),
8107 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
8108 }),
8109 Shared::new(Node {
8110 token_id: 4.into(),
8111 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
8112 })
8113 ]
8114 ))
8115 }),
8116 )),
8117 }),
8118 ]))]
8119 #[case::def_with_variadic_param(
8120 vec![
8121 token(TokenKind::Def),
8122 token(TokenKind::Ident(SmolStr::new("f"))),
8123 token(TokenKind::LParen),
8124 token(TokenKind::Asterisk),
8125 token(TokenKind::Ident(SmolStr::new("args"))),
8126 token(TokenKind::RParen),
8127 token(TokenKind::Colon),
8128 token(TokenKind::Ident(SmolStr::new("args"))),
8129 token(TokenKind::SemiColon)
8130 ],
8131 Ok(vec![
8132 Shared::new(Node {
8133 token_id: 0.into(),
8134 expr: Shared::new(Expr::Def(
8135 IdentWithToken::new_with_token("f", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("f")))))),
8136 smallvec![
8137 Param::variadic(IdentWithToken::new_with_token("args", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("args"))))))),
8138 ],
8139 vec![Shared::new(Node {
8140 token_id: 2.into(),
8141 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("args", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("args")))))))),
8142 })],
8143 )),
8144 }),
8145 ]))]
8146 #[case::def_with_regular_and_variadic_param(
8147 vec![
8148 token(TokenKind::Def),
8149 token(TokenKind::Ident(SmolStr::new("f"))),
8150 token(TokenKind::LParen),
8151 token(TokenKind::Ident(SmolStr::new("a"))),
8152 token(TokenKind::Comma),
8153 token(TokenKind::Asterisk),
8154 token(TokenKind::Ident(SmolStr::new("rest"))),
8155 token(TokenKind::RParen),
8156 token(TokenKind::Colon),
8157 token(TokenKind::Ident(SmolStr::new("rest"))),
8158 token(TokenKind::SemiColon)
8159 ],
8160 Ok(vec![
8161 Shared::new(Node {
8162 token_id: 0.into(),
8163 expr: Shared::new(Expr::Def(
8164 IdentWithToken::new_with_token("f", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("f")))))),
8165 smallvec![
8166 Param::new(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a"))))))),
8167 Param::variadic(IdentWithToken::new_with_token("rest", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("rest"))))))),
8168 ],
8169 vec![Shared::new(Node {
8170 token_id: 2.into(),
8171 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("rest", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("rest")))))))),
8172 })],
8173 )),
8174 }),
8175 ]))]
8176 #[case::def_variadic_param_not_last(
8177 vec![
8178 token(TokenKind::Def),
8179 token(TokenKind::Ident(SmolStr::new("f"))),
8180 token(TokenKind::LParen),
8181 token(TokenKind::Asterisk),
8182 token(TokenKind::Ident(SmolStr::new("a"))),
8183 token(TokenKind::Comma),
8184 token(TokenKind::Ident(SmolStr::new("b"))),
8185 token(TokenKind::RParen),
8186 ],
8187 Err(SyntaxError::VariadicParameterMustBeLast(Token{range: Range::default(), kind: TokenKind::Ident(SmolStr::new("b")), module_id: 1.into()})))]
8188 #[case::def_multiple_variadic_params(
8189 vec![
8190 token(TokenKind::Def),
8191 token(TokenKind::Ident(SmolStr::new("f"))),
8192 token(TokenKind::LParen),
8193 token(TokenKind::Asterisk),
8194 token(TokenKind::Ident(SmolStr::new("a"))),
8195 token(TokenKind::Comma),
8196 token(TokenKind::Asterisk),
8197 token(TokenKind::Ident(SmolStr::new("b"))),
8198 token(TokenKind::RParen),
8199 ],
8200 Err(SyntaxError::MultipleVariadicParameters(Token{range: Range::default(), kind: TokenKind::Asterisk, module_id: 1.into()})))]
8201 #[case::def_without_params(
8202 vec![
8203 token(TokenKind::Def),
8204 token(TokenKind::Ident(SmolStr::new("f"))),
8205 token(TokenKind::Colon),
8206 token(TokenKind::Ident(SmolStr::new("args"))),
8207 token(TokenKind::SemiColon)
8208 ],
8209 Ok(vec![
8210 Shared::new(Node {
8211 token_id: 0.into(),
8212 expr: Shared::new(Expr::Def(
8213 IdentWithToken::new_with_token("f", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("f")))))),
8214 smallvec![],
8215 vec![Shared::new(Node {
8216 token_id: 2.into(),
8217 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("args", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("args")))))))),
8218 })],
8219 )),
8220 }),
8221 ]))]
8222 #[case::def_without_params_with_do(
8223 vec![
8224 token(TokenKind::Def),
8225 token(TokenKind::Ident(SmolStr::new("f"))),
8226 token(TokenKind::Do),
8227 token(TokenKind::Ident(SmolStr::new("args"))),
8228 token(TokenKind::SemiColon)
8229 ],
8230 Ok(vec![
8231 Shared::new(Node {
8232 token_id: 0.into(),
8233 expr: Shared::new(Expr::Def(
8234 IdentWithToken::new_with_token("f", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("f")))))),
8235 smallvec![],
8236 vec![Shared::new(Node {
8237 token_id: 2.into(),
8238 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("args", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("args")))))))),
8239 })],
8240 )),
8241 }),
8242 ]))]
8243 #[case::macro_variadic_param(
8244 vec![
8245 token(TokenKind::Macro),
8246 token(TokenKind::Ident(SmolStr::new("m"))),
8247 token(TokenKind::LParen),
8248 token(TokenKind::Asterisk),
8249 token(TokenKind::Ident(SmolStr::new("args"))),
8250 token(TokenKind::RParen),
8251 token(TokenKind::Colon),
8252 token(TokenKind::Ident(SmolStr::new("args"))),
8253 ],
8254 Err(SyntaxError::MacroParametersCannotBeVariadic(Token{range: Range::default(), kind: TokenKind::Macro, module_id: 1.into()})))]
8255 #[case::arrow_simple(
8256 vec![
8257 token(TokenKind::Arrow),
8258 token(TokenKind::LParen),
8259 token(TokenKind::RParen),
8260 token(TokenKind::Colon),
8261 token(TokenKind::StringLiteral("result".to_owned())),
8262 token(TokenKind::SemiColon),
8263 ],
8264 Ok(vec![
8265 Shared::new(Node {
8266 token_id: 0.into(),
8267 expr: Shared::new(Expr::Fn(
8268 SmallVec::new(),
8269 vec![
8270 Shared::new(Node {
8271 token_id: 2.into(),
8272 expr: Shared::new(Expr::Literal(Literal::String("result".to_owned()))),
8273 })
8274 ],
8275 )),
8276 })
8277 ]))]
8278 #[case::arrow_with_args(
8279 vec![
8280 token(TokenKind::Arrow),
8281 token(TokenKind::LParen),
8282 token(TokenKind::Ident(SmolStr::new("x"))),
8283 token(TokenKind::Comma),
8284 token(TokenKind::Ident(SmolStr::new("y"))),
8285 token(TokenKind::RParen),
8286 token(TokenKind::Colon),
8287 token(TokenKind::Ident(SmolStr::new("contains"))),
8288 token(TokenKind::LParen),
8289 token(TokenKind::Ident(SmolStr::new("x"))),
8290 token(TokenKind::Comma),
8291 token(TokenKind::Ident(SmolStr::new("y"))),
8292 token(TokenKind::RParen),
8293 token(TokenKind::SemiColon),
8294 ],
8295 Ok(vec![
8296 Shared::new(Node {
8297 token_id: 0.into(),
8298 expr: Shared::new(Expr::Fn(
8299 smallvec![
8300 Param::new(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x"))))))),
8301 Param::new(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y"))))))),
8302 ],
8303 vec![
8304 Shared::new(Node {
8305 token_id: 4.into(),
8306 expr: Shared::new(Expr::Call(
8307 IdentWithToken::new_with_token("contains", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("contains")))))),
8308 smallvec![
8309 Shared::new(Node {
8310 token_id: 2.into(),
8311 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
8312 }),
8313 Shared::new(Node {
8314 token_id: 3.into(),
8315 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y")))))))),
8316 }),
8317 ],
8318 )),
8319 })
8320 ],
8321 )),
8322 })
8323 ]))]
8324 #[case::arrow_nested_in_call(
8325 vec![
8326 token(TokenKind::Ident(SmolStr::new("apply"))),
8327 token(TokenKind::LParen),
8328 token(TokenKind::Arrow),
8329 token(TokenKind::LParen),
8330 token(TokenKind::Ident(SmolStr::new("x"))),
8331 token(TokenKind::RParen),
8332 token(TokenKind::Colon),
8333 token(TokenKind::StringLiteral("processed".to_owned())),
8334 token(TokenKind::SemiColon),
8335 token(TokenKind::RParen),
8336 token(TokenKind::Eof),
8337 ],
8338 Ok(vec![
8339 Shared::new(Node {
8340 token_id: 4.into(),
8341 expr: Shared::new(Expr::Call(
8342 IdentWithToken::new_with_token("apply", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("apply")))))),
8343 smallvec![
8344 Shared::new(Node {
8345 token_id: 0.into(),
8346 expr: Shared::new(Expr::Fn(
8347 smallvec![
8348 Param::new(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x"))))))),
8349 ],
8350 vec![
8351 Shared::new(Node {
8352 token_id: 2.into(),
8353 expr: Shared::new(Expr::Literal(Literal::String("processed".to_owned()))),
8354 })
8355 ],
8356 )),
8357 })
8358 ],
8359 )),
8360 })
8361 ]))]
8362 fn test_parse(#[case] input: Vec<Token>, #[case] expected: Result<Program, SyntaxError>) {
8363 let mut arena = Arena::new(10);
8364 let tokens: Vec<Shared<Token>> = input.into_iter().map(Shared::new).collect();
8365 let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
8366
8367 match (&result, &expected) {
8368 (Ok(actual), Ok(expected)) => {
8369 assert_eq!(actual.len(), expected.len());
8370 let actual_exprs: Vec<_> = actual.iter().map(|a| &*a.expr).collect();
8371 let expected_exprs: Vec<_> = expected.iter().map(|e| &*e.expr).collect();
8372 assert_eq!(actual_exprs, expected_exprs);
8373 }
8374 (Err(actual), Err(expected)) => {
8375 assert_eq!(actual, expected);
8376 }
8377 _ => {
8378 panic!("Mismatch: actual = {:?}, expected = {:?}", result, expected)
8379 }
8380 }
8381 }
8382
8383 #[rstest]
8384 #[case::heading(".h1", Selector::Heading(Some(1)))]
8385 #[case::heading_h3(".h3", Selector::Heading(Some(3)))]
8386 #[case::blockquote(".>", Selector::Blockquote)]
8387 #[case::blockquote_full(".blockquote", Selector::Blockquote)]
8388 #[case::footnote(".^", Selector::Footnote)]
8389 #[case::footnote_full(".footnote", Selector::Footnote)]
8390 #[case::mdx_jsx_flow(".mdx_jsx_flow_element", Selector::MdxJsxFlowElement)]
8391 #[case::mdx_jsx_flow_short(".<", Selector::MdxJsxFlowElement)]
8392 #[case::emphasis(".**", Selector::Emphasis)]
8393 #[case::emphasis_full(".emphasis", Selector::Emphasis)]
8394 #[case::math(".$$", Selector::Math)]
8395 #[case::math_full(".math", Selector::Math)]
8396 #[case::horizontal_rule(".---", Selector::HorizontalRule)]
8397 #[case::horizontal_rule_alt(".***", Selector::HorizontalRule)]
8398 #[case::horizontal_rule_full(".horizontal_rule", Selector::HorizontalRule)]
8399 #[case::mdx_text_expression(".{}", Selector::MdxTextExpression)]
8400 #[case::mdx_text_expression_full(".mdx_text_expression", Selector::MdxTextExpression)]
8401 #[case::footnote_ref(".[^]", Selector::FootnoteRef)]
8402 #[case::footnote_ref_full(".footnote_ref", Selector::FootnoteRef)]
8403 #[case::definition(".definition", Selector::Definition)]
8404 #[case::break_selector(".break", Selector::Break)]
8405 #[case::delete(".delete", Selector::Delete)]
8406 #[case::html(".<>", Selector::Html)]
8407 #[case::html_full(".html", Selector::Html)]
8408 #[case::image(".image", Selector::Image)]
8409 #[case::image_ref(".image_ref", Selector::ImageRef)]
8410 #[case::code(".code", Selector::Code)]
8411 #[case::code_inline(".code_inline", Selector::InlineCode)]
8412 #[case::math_inline(".math_inline", Selector::InlineMath)]
8413 #[case::link(".link", Selector::Link)]
8414 #[case::link_ref(".link_ref", Selector::LinkRef)]
8415 #[case::list(".list", Selector::List(None, None))]
8416 #[case::toml(".toml", Selector::Toml)]
8417 #[case::strong(".strong", Selector::Strong)]
8418 #[case::yaml(".yaml", Selector::Yaml)]
8419 #[case::text(".text", Selector::Text)]
8420 #[case::mdx_js_esm(".mdx_js_esm", Selector::MdxJsEsm)]
8421 #[case::mdx_jsx_text_element(".mdx_jsx_text_element", Selector::MdxJsxTextElement)]
8422 #[case::mdx_flow_expression(".mdx_flow_expression", Selector::MdxFlowExpression)]
8423 fn test_parse_selector(#[case] selector_str: &str, #[case] expected_selector: Selector) {
8424 let mut arena = Arena::new(10);
8425 let token = Shared::new(Token {
8426 range: Range::default(),
8427 kind: TokenKind::Selector(SmolStr::new(selector_str)),
8428 module_id: 1.into(),
8429 });
8430
8431 let tokens = [
8432 Shared::clone(&token),
8433 Shared::new(Token {
8434 range: Range::default(),
8435 kind: TokenKind::Eof,
8436 module_id: 1.into(),
8437 }),
8438 ];
8439
8440 let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
8441
8442 match result {
8443 Ok(program) => {
8444 assert_eq!(program.len(), 1);
8445 if let Expr::Selector(selector) = &*program[0].expr {
8446 assert_eq!(*selector, expected_selector);
8447 } else {
8448 panic!("Expected Selector expression, got {:?}", program[0].expr);
8449 }
8450 }
8451 Err(err) => panic!("Parse error: {:?}", err),
8452 }
8453 }
8454
8455 #[rstest]
8456 #[case(".", Some(1), None, Selector::List(Some(1), None))]
8457 #[case(".", Some(2), Some(3), Selector::Table(Some(2), Some(3)))]
8458 fn test_parse_array_selector(
8459 #[case] selector_str: &str,
8460 #[case] first_idx: Option<usize>,
8461 #[case] second_idx: Option<usize>,
8462 #[case] expected_selector: Selector,
8463 ) {
8464 let mut arena = Arena::new(10);
8465 let mut tokens = vec![
8466 Shared::new(Token {
8467 range: Range::default(),
8468 kind: TokenKind::Selector(SmolStr::new(selector_str)),
8469 module_id: 1.into(),
8470 }),
8471 Shared::new(Token {
8472 range: Range::default(),
8473 kind: TokenKind::LBracket,
8474 module_id: 1.into(),
8475 }),
8476 ];
8477
8478 if let Some(idx) = first_idx {
8479 tokens.push(Shared::new(Token {
8480 range: Range::default(),
8481 kind: TokenKind::NumberLiteral(idx.into()),
8482 module_id: 1.into(),
8483 }));
8484 }
8485
8486 tokens.push(Shared::new(Token {
8487 range: Range::default(),
8488 kind: TokenKind::RBracket,
8489 module_id: 1.into(),
8490 }));
8491
8492 if second_idx.is_some() {
8493 tokens.push(Shared::new(Token {
8494 range: Range::default(),
8495 kind: TokenKind::LBracket,
8496 module_id: 1.into(),
8497 }));
8498
8499 if let Some(idx) = second_idx {
8500 tokens.push(Shared::new(Token {
8501 range: Range::default(),
8502 kind: TokenKind::NumberLiteral(idx.into()),
8503 module_id: 1.into(),
8504 }));
8505 }
8506
8507 tokens.push(Shared::new(Token {
8508 range: Range::default(),
8509 kind: TokenKind::RBracket,
8510 module_id: 1.into(),
8511 }));
8512 }
8513
8514 tokens.push(Shared::new(Token {
8515 range: Range::default(),
8516 kind: TokenKind::Eof,
8517 module_id: 1.into(),
8518 }));
8519
8520 let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
8521
8522 match result {
8523 Ok(program) => {
8524 assert_eq!(program.len(), 1);
8525 if let Expr::Selector(selector) = &*program[0].expr {
8526 assert_eq!(*selector, expected_selector);
8527 } else {
8528 panic!("Expected Selector expression, got {:?}", program[0].expr);
8529 }
8530 }
8531 Err(err) => panic!("Parse error: {:?}", err),
8532 }
8533 }
8534
8535 #[rstest]
8537 #[case::all_elements(".\"items\"", None, vec![Selector::Property("items".into()), Selector::List(None, None)])]
8538 #[case::index_0(".\"items\"", Some(0usize), vec![Selector::Property("items".into()), Selector::List(Some(0), None)])]
8539 #[case::index_2(".\"items\"", Some(2usize), vec![Selector::Property("items".into()), Selector::List(Some(2), None)])]
8540 fn test_parse_property_selector_iterator(
8541 #[case] selector_str: &str,
8542 #[case] index: Option<usize>,
8543 #[case] expected: Vec<Selector>,
8544 ) {
8545 let mut arena = Arena::new(10);
8546 let mut tokens = vec![
8547 Shared::new(Token {
8548 range: Range::default(),
8549 kind: TokenKind::Selector(SmolStr::new(selector_str)),
8550 module_id: 1.into(),
8551 }),
8552 Shared::new(Token {
8553 range: Range::default(),
8554 kind: TokenKind::LBracket,
8555 module_id: 1.into(),
8556 }),
8557 ];
8558 if let Some(idx) = index {
8559 tokens.push(Shared::new(Token {
8560 range: Range::default(),
8561 kind: TokenKind::NumberLiteral(idx.into()),
8562 module_id: 1.into(),
8563 }));
8564 }
8565 tokens.push(Shared::new(Token {
8566 range: Range::default(),
8567 kind: TokenKind::RBracket,
8568 module_id: 1.into(),
8569 }));
8570 tokens.push(Shared::new(Token {
8571 range: Range::default(),
8572 kind: TokenKind::Eof,
8573 module_id: 1.into(),
8574 }));
8575
8576 let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID)
8577 .parse()
8578 .expect("parse error");
8579
8580 assert_eq!(result.len(), 1);
8581 let Expr::Block(nodes) = &*result[0].expr else {
8582 panic!("expected Block, got {:?}", result[0].expr);
8583 };
8584 assert_eq!(nodes.len(), expected.len());
8585 for (node, sel) in nodes.iter().zip(expected.iter()) {
8586 let Expr::Selector(actual) = &*node.expr else {
8587 panic!("expected Selector, got {:?}", node.expr);
8588 };
8589 assert_eq!(actual, sel);
8590 }
8591 }
8592
8593 #[rstest]
8595 #[case::all_elements(".\"a\"", ".\"b\"", None, vec![Selector::Property("a".into()), Selector::Property("b".into()), Selector::List(None, None)])]
8596 #[case::index_0(".\"a\"", ".\"b\"", Some(0usize), vec![Selector::Property("a".into()), Selector::Property("b".into()), Selector::List(Some(0), None)])]
8597 #[case::index_1(".\"a\"", ".\"b\"", Some(1usize), vec![Selector::Property("a".into()), Selector::Property("b".into()), Selector::List(Some(1), None)])]
8598 fn test_parse_chained_property_selector_iterator(
8599 #[case] first: &str,
8600 #[case] second: &str,
8601 #[case] index: Option<usize>,
8602 #[case] expected: Vec<Selector>,
8603 ) {
8604 let mut arena = Arena::new(10);
8605 let mut tokens = vec![
8606 Shared::new(Token {
8607 range: Range::default(),
8608 kind: TokenKind::Selector(SmolStr::new(first)),
8609 module_id: 1.into(),
8610 }),
8611 Shared::new(Token {
8612 range: Range::default(),
8613 kind: TokenKind::Selector(SmolStr::new(second)),
8614 module_id: 1.into(),
8615 }),
8616 Shared::new(Token {
8617 range: Range::default(),
8618 kind: TokenKind::LBracket,
8619 module_id: 1.into(),
8620 }),
8621 ];
8622 if let Some(idx) = index {
8623 tokens.push(Shared::new(Token {
8624 range: Range::default(),
8625 kind: TokenKind::NumberLiteral(idx.into()),
8626 module_id: 1.into(),
8627 }));
8628 }
8629 tokens.push(Shared::new(Token {
8630 range: Range::default(),
8631 kind: TokenKind::RBracket,
8632 module_id: 1.into(),
8633 }));
8634 tokens.push(Shared::new(Token {
8635 range: Range::default(),
8636 kind: TokenKind::Eof,
8637 module_id: 1.into(),
8638 }));
8639
8640 let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID)
8641 .parse()
8642 .expect("parse error");
8643
8644 assert_eq!(result.len(), 1);
8645 let Expr::Block(nodes) = &*result[0].expr else {
8646 panic!("expected Block, got {:?}", result[0].expr);
8647 };
8648 assert_eq!(nodes.len(), expected.len());
8649 for (node, sel) in nodes.iter().zip(expected.iter()) {
8650 let Expr::Selector(actual) = &*node.expr else {
8651 panic!("expected Selector, got {:?}", node.expr);
8652 };
8653 assert_eq!(actual, sel);
8654 }
8655 }
8656
8657 #[test]
8658 fn test_parse_as_binding() {
8659 let mut arena = Arena::new(10);
8660 let tokens = [
8661 Shared::new(Token {
8662 range: Range::default(),
8663 kind: TokenKind::NumberLiteral(42.into()),
8664 module_id: 1.into(),
8665 }),
8666 Shared::new(Token {
8667 range: Range::default(),
8668 kind: TokenKind::As,
8669 module_id: 1.into(),
8670 }),
8671 Shared::new(Token {
8672 range: Range::default(),
8673 kind: TokenKind::Ident("x".into()),
8674 module_id: 1.into(),
8675 }),
8676 Shared::new(Token {
8677 range: Range::default(),
8678 kind: TokenKind::Eof,
8679 module_id: 1.into(),
8680 }),
8681 ];
8682 let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
8683 assert!(result.is_ok());
8684 let program = result.unwrap();
8685 assert_eq!(program.len(), 1);
8686 let Expr::As(ident, inner) = &*program[0].expr else {
8687 panic!("expected Expr::As, got {:?}", program[0].expr);
8688 };
8689 assert_eq!(ident.name.as_str(), "x");
8690 assert!(matches!(*inner.expr, Expr::Literal(Literal::Number(_))));
8691 }
8692
8693 #[test]
8694 fn test_parse_env() {
8695 unsafe { std::env::set_var("MQ_TEST_VAR", "test_value") };
8696
8697 let mut arena = Arena::new(10);
8698 let tokens = [
8699 Shared::new(Token {
8700 range: Range::default(),
8701 kind: TokenKind::Env("MQ_TEST_VAR".into()),
8702 module_id: 1.into(),
8703 }),
8704 Shared::new(Token {
8705 range: Range::default(),
8706 kind: TokenKind::Eof,
8707 module_id: 1.into(),
8708 }),
8709 ];
8710
8711 let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
8712
8713 match result {
8714 Ok(program) => {
8715 assert_eq!(program.len(), 1);
8716 if let Expr::Literal(Literal::String(value)) = &*program[0].expr {
8717 assert_eq!(value, "test_value");
8718 } else {
8719 panic!("Expected String literal, got {:?}", program[0].expr);
8720 }
8721 }
8722 Err(err) => panic!("Parse error: {:?}", err),
8723 }
8724 }
8725
8726 #[test]
8727 fn test_parse_env_not_found() {
8728 let mut arena = Arena::new(10);
8729 let token = Shared::new(Token {
8730 range: Range::default(),
8731 kind: TokenKind::Env("MQ_NONEXISTENT_VAR".into()),
8732 module_id: 1.into(),
8733 });
8734
8735 let tokens = [
8736 Shared::clone(&token),
8737 Shared::new(Token {
8738 range: Range::default(),
8739 kind: TokenKind::Eof,
8740 module_id: 1.into(),
8741 }),
8742 ];
8743
8744 let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
8745
8746 assert!(matches!(
8747 result,
8748 Err(SyntaxError::EnvNotFound(_, var)) if var == "MQ_NONEXISTENT_VAR"
8749 ));
8750 }
8751
8752 #[test]
8753 fn test_parse_env_in_arguments() {
8754 unsafe { std::env::set_var("MQ_ARG_TEST", "env_arg_value") };
8755
8756 let mut arena = Arena::new(10);
8757 let tokens = [
8758 Shared::new(Token {
8759 range: Range::default(),
8760 kind: TokenKind::Ident(SmolStr::new("function")),
8761 module_id: 1.into(),
8762 }),
8763 Shared::new(Token {
8764 range: Range::default(),
8765 kind: TokenKind::LParen,
8766 module_id: 1.into(),
8767 }),
8768 Shared::new(Token {
8769 range: Range::default(),
8770 kind: TokenKind::Env("MQ_ARG_TEST".into()),
8771 module_id: 1.into(),
8772 }),
8773 Shared::new(Token {
8774 range: Range::default(),
8775 kind: TokenKind::RParen,
8776 module_id: 1.into(),
8777 }),
8778 Shared::new(Token {
8779 range: Range::default(),
8780 kind: TokenKind::Eof,
8781 module_id: 1.into(),
8782 }),
8783 ];
8784
8785 let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
8786
8787 match result {
8788 Ok(program) => {
8789 assert_eq!(program.len(), 1);
8790 if let Expr::Call(ident, args) = &*program[0].expr {
8791 assert_eq!(ident.name, "function".into());
8792 assert_eq!(args.len(), 1);
8793 if let Expr::Literal(Literal::String(value)) = &*args[0].expr {
8794 assert_eq!(value, "env_arg_value");
8795 } else {
8796 panic!("Expected String literal in argument, got {:?}", args[0].expr);
8797 }
8798 } else {
8799 panic!("Expected Call expression, got {:?}", program[0].expr);
8800 }
8801 }
8802 Err(err) => panic!("Parse error: {:?}", err),
8803 }
8804 }
8805
8806 #[rstest]
8807 #[case::lang(".lang", "lang")]
8808 #[case::value(".value", "value")]
8809 #[case::depth(".depth", "depth")]
8810 fn test_parse_standalone_attr_selector(#[case] selector: &str, #[case] attribute: &str) {
8811 let mut arena = Arena::new(10);
8812 let tokens = [
8813 Shared::new(Token {
8814 range: Range::default(),
8815 kind: TokenKind::Selector(SmolStr::new(selector)),
8816 module_id: 1.into(),
8817 }),
8818 Shared::new(Token {
8819 range: Range::default(),
8820 kind: TokenKind::Eof,
8821 module_id: 1.into(),
8822 }),
8823 ];
8824
8825 let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
8826
8827 match result {
8828 Ok(program) => {
8829 assert_eq!(program.len(), 1);
8830 if let Expr::Call(ident, args) = &*program[0].expr {
8831 assert_eq!(ident.name, "attr".into());
8832 assert_eq!(args.len(), 2);
8833 assert!(matches!(&*args[0].expr, Expr::Self_));
8834 if let Expr::Literal(Literal::String(attr_str)) = &*args[1].expr {
8835 assert_eq!(attr_str, attribute);
8836 } else {
8837 panic!("Expected String literal in second argument, got {:?}", args[1].expr);
8838 }
8839 } else {
8840 panic!("Expected Call expression, got {:?}", program[0].expr);
8841 }
8842 }
8843 Err(err) => panic!("Parse error: {:?}", err),
8844 }
8845 }
8846
8847 #[rstest]
8848 #[case::h_value(vec![".h", ".value"], "h", "value")]
8849 #[case::h1_value(vec![".h1", ".value"], "h1", "value")]
8850 #[case::code_lang(vec![".code", ".lang"], "code", "lang")]
8851 #[case::text_value(vec![".text", ".value"], "text", "value")]
8852 fn test_parse_selector_with_attribute(
8853 #[case] selectors: Vec<&str>,
8854 #[case] base_selector: &str,
8855 #[case] attribute: &str,
8856 ) {
8857 let mut arena = Arena::new(10);
8858 let mut tokens = selectors
8859 .iter()
8860 .map(|selector| {
8861 Shared::new(Token {
8862 range: Range::default(),
8863 kind: TokenKind::Selector(SmolStr::new(selector)),
8864 module_id: 1.into(),
8865 })
8866 })
8867 .collect::<Vec<_>>();
8868
8869 tokens.push(Shared::new(Token {
8870 range: Range::default(),
8871 kind: TokenKind::Eof,
8872 module_id: 1.into(),
8873 }));
8874
8875 let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
8876
8877 match result {
8878 Ok(program) => {
8879 assert_eq!(program.len(), 1);
8880 if let Expr::Call(ident, args) = &*program[0].expr {
8881 assert_eq!(ident.name, "attr".into());
8883 assert_eq!(args.len(), 2);
8884
8885 if let Expr::Selector(selector) = &*args[0].expr {
8887 match base_selector {
8888 "h" => assert_eq!(*selector, Selector::Heading(None)),
8889 "h1" => assert_eq!(*selector, Selector::Heading(Some(1))),
8890 "code" => assert_eq!(*selector, Selector::Code),
8891 "text" => assert_eq!(*selector, Selector::Text),
8892 _ => panic!("Unexpected base selector: {}", base_selector),
8893 }
8894 } else {
8895 panic!("Expected Selector expression in first argument, got {:?}", args[0].expr);
8896 }
8897
8898 if let Expr::Literal(Literal::String(attr_str)) = &*args[1].expr {
8900 assert_eq!(attr_str, attribute);
8901 } else {
8902 panic!("Expected String literal in second argument, got {:?}", args[1].expr);
8903 }
8904 } else {
8905 panic!("Expected Call expression, got {:?}", program[0].expr);
8906 }
8907 }
8908 Err(err) => panic!("Parse error: {:?}", err),
8909 }
8910 }
8911
8912 #[rstest]
8913 #[case::match_simple_literal(
8914 vec![
8915 token(TokenKind::Match),
8916 token(TokenKind::LParen),
8917 token(TokenKind::Ident(SmolStr::new("x"))),
8918 token(TokenKind::RParen),
8919 token(TokenKind::Colon),
8920 token(TokenKind::Pipe),
8921 token(TokenKind::NumberLiteral(1.into())),
8922 token(TokenKind::Colon),
8923 token(TokenKind::StringLiteral("one".to_owned())),
8924 token(TokenKind::Pipe),
8925 token(TokenKind::NumberLiteral(2.into())),
8926 token(TokenKind::Colon),
8927 token(TokenKind::StringLiteral("two".to_owned())),
8928 token(TokenKind::Pipe),
8929 token(TokenKind::Ident(SmolStr::new("_"))),
8930 token(TokenKind::Colon),
8931 token(TokenKind::StringLiteral("other".to_owned())),
8932 token(TokenKind::End),
8933 token(TokenKind::Eof)
8934 ],
8935 Ok(vec![
8936 Shared::new(Node {
8937 token_id: 0.into(),
8938 expr: Shared::new(Expr::Match(
8939 Shared::new(Node {
8940 token_id: 1.into(),
8941 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(Token {
8942 range: Range::default(),
8943 kind: TokenKind::Ident(SmolStr::new("x")),
8944 module_id: 1.into()
8945 })))))
8946 }),
8947 smallvec![
8948 MatchArm {
8949 pattern: Pattern::Literal(Literal::Number(1.into())),
8950 guard: None,
8951 body: Shared::new(Node {
8952 token_id: 5.into(),
8953 expr: Shared::new(Expr::Literal(Literal::String("one".to_owned())))
8954 })
8955 },
8956 MatchArm {
8957 pattern: Pattern::Literal(Literal::Number(2.into())),
8958 guard: None,
8959 body: Shared::new(Node {
8960 token_id: 8.into(),
8961 expr: Shared::new(Expr::Literal(Literal::String("two".to_owned())))
8962 })
8963 },
8964 MatchArm {
8965 pattern: Pattern::Wildcard,
8966 guard: None,
8967 body: Shared::new(Node {
8968 token_id: 11.into(),
8969 expr: Shared::new(Expr::Literal(Literal::String("other".to_owned())))
8970 })
8971 }
8972 ]
8973 ))
8974 })
8975 ]))]
8976 #[case::match_type_pattern(
8977 vec![
8978 token(TokenKind::Match),
8979 token(TokenKind::LParen),
8980 token(TokenKind::Ident(SmolStr::new("value"))),
8981 token(TokenKind::RParen),
8982 token(TokenKind::Colon),
8983 token(TokenKind::Pipe),
8984 token(TokenKind::Colon),
8985 token(TokenKind::Ident(SmolStr::new("string"))),
8986 token(TokenKind::Colon),
8987 token(TokenKind::StringLiteral("is string".to_owned())),
8988 token(TokenKind::Pipe),
8989 token(TokenKind::Colon),
8990 token(TokenKind::Ident(SmolStr::new("number"))),
8991 token(TokenKind::Colon),
8992 token(TokenKind::StringLiteral("is number".to_owned())),
8993 token(TokenKind::End),
8994 token(TokenKind::Eof)
8995 ],
8996 Ok(vec![
8997 Shared::new(Node {
8998 token_id: 0.into(),
8999 expr: Shared::new(Expr::Match(
9000 Shared::new(Node {
9001 token_id: 1.into(),
9002 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("value", Some(Shared::new(Token {
9003 range: Range::default(),
9004 kind: TokenKind::Ident(SmolStr::new("value")),
9005 module_id: 1.into()
9006 })))))
9007 }),
9008 smallvec![
9009 MatchArm {
9010 pattern: Pattern::Type(Ident::new("string")),
9011 guard: None,
9012 body: Shared::new(Node {
9013 token_id: 5.into(),
9014 expr: Shared::new(Expr::Literal(Literal::String("is string".to_owned())))
9015 })
9016 },
9017 MatchArm {
9018 pattern: Pattern::Type(Ident::new("number")),
9019 guard: None,
9020 body: Shared::new(Node {
9021 token_id: 8.into(),
9022 expr: Shared::new(Expr::Literal(Literal::String("is number".to_owned())))
9023 })
9024 }
9025 ]
9026 ))
9027 })
9028 ]))]
9029 #[case::match_array_pattern(
9030 vec![
9031 token(TokenKind::Match),
9032 token(TokenKind::LParen),
9033 token(TokenKind::Ident(SmolStr::new("arr"))),
9034 token(TokenKind::RParen),
9035 token(TokenKind::Colon),
9036 token(TokenKind::Pipe),
9037 token(TokenKind::LBracket),
9038 token(TokenKind::Ident(SmolStr::new("x"))),
9039 token(TokenKind::Comma),
9040 token(TokenKind::Ident(SmolStr::new("y"))),
9041 token(TokenKind::RBracket),
9042 token(TokenKind::Colon),
9043 token(TokenKind::StringLiteral("two elements".to_owned())),
9044 token(TokenKind::End),
9045 token(TokenKind::Eof)
9046 ],
9047 Ok(vec![
9048 Shared::new(Node {
9049 token_id: 0.into(),
9050 expr: Shared::new(Expr::Match(
9051 Shared::new(Node {
9052 token_id: 1.into(),
9053 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(Token {
9054 range: Range::default(),
9055 kind: TokenKind::Ident(SmolStr::new("arr")),
9056 module_id: 1.into()
9057 })))))
9058 }),
9059 smallvec![
9060 MatchArm {
9061 pattern: Pattern::Array(vec![
9062 Pattern::Ident(IdentWithToken::new("x")),
9063 Pattern::Ident(IdentWithToken::new("y"))
9064 ]),
9065 guard: None,
9066 body: Shared::new(Node {
9067 token_id: 5.into(),
9068 expr: Shared::new(Expr::Literal(Literal::String("two elements".to_owned())))
9069 })
9070 }
9071 ]
9072 ))
9073 })
9074 ]))]
9075 #[case::match_array_rest_pattern(
9076 vec![
9077 token(TokenKind::Match),
9078 token(TokenKind::LParen),
9079 token(TokenKind::Ident(SmolStr::new("arr"))),
9080 token(TokenKind::RParen),
9081 token(TokenKind::Colon),
9082 token(TokenKind::Pipe),
9083 token(TokenKind::LBracket),
9084 token(TokenKind::Ident(SmolStr::new("first"))),
9085 token(TokenKind::Comma),
9086 token(TokenKind::DoubleDot),
9087 token(TokenKind::Ident(SmolStr::new("rest"))),
9088 token(TokenKind::RBracket),
9089 token(TokenKind::Colon),
9090 token(TokenKind::Ident(SmolStr::new("first"))),
9091 token(TokenKind::End),
9092 token(TokenKind::Eof)
9093 ],
9094 Ok(vec![
9095 Shared::new(Node {
9096 token_id: 0.into(),
9097 expr: Shared::new(Expr::Match(
9098 Shared::new(Node {
9099 token_id: 1.into(),
9100 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(Token {
9101 range: Range::default(),
9102 kind: TokenKind::Ident(SmolStr::new("arr")),
9103 module_id: 1.into()
9104 })))))
9105 }),
9106 smallvec![
9107 MatchArm {
9108 pattern: Pattern::ArrayRest(
9109 vec![Pattern::Ident(IdentWithToken::new("first"))],
9110 IdentWithToken::new("rest")
9111 ),
9112 guard: None,
9113 body: Shared::new(Node {
9114 token_id: 5.into(),
9115 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("first", Some(Shared::new(Token {
9116 range: Range::default(),
9117 kind: TokenKind::Ident(SmolStr::new("first")),
9118 module_id: 1.into()
9119 })))))
9120 })
9121 }
9122 ]
9123 ))
9124 })
9125 ]))]
9126 #[case::match_dict_pattern(
9127 vec![
9128 token(TokenKind::Match),
9129 token(TokenKind::LParen),
9130 token(TokenKind::Ident(SmolStr::new("obj"))),
9131 token(TokenKind::RParen),
9132 token(TokenKind::Colon),
9133 token(TokenKind::Pipe),
9134 token(TokenKind::LBrace),
9135 token(TokenKind::Ident(SmolStr::new("name"))),
9136 token(TokenKind::Comma),
9137 token(TokenKind::Ident(SmolStr::new("age"))),
9138 token(TokenKind::RBrace),
9139 token(TokenKind::Colon),
9140 token(TokenKind::Ident(SmolStr::new("name"))),
9141 token(TokenKind::End),
9142 token(TokenKind::Eof)
9143 ],
9144 Ok(vec![
9145 Shared::new(Node {
9146 token_id: 0.into(),
9147 expr: Shared::new(Expr::Match(
9148 Shared::new(Node {
9149 token_id: 1.into(),
9150 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("obj", Some(Shared::new(Token {
9151 range: Range::default(),
9152 kind: TokenKind::Ident(SmolStr::new("obj")),
9153 module_id: 1.into()
9154 })))))
9155 }),
9156 smallvec![
9157 MatchArm {
9158 pattern: Pattern::Dict(vec![
9159 (IdentWithToken::new("name"), Pattern::Ident(IdentWithToken::new("name"))),
9160 (IdentWithToken::new("age"), Pattern::Ident(IdentWithToken::new("age")))
9161 ]),
9162 guard: None,
9163 body: Shared::new(Node {
9164 token_id: 5.into(),
9165 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("name", Some(Shared::new(Token {
9166 range: Range::default(),
9167 kind: TokenKind::Ident(SmolStr::new("name")),
9168 module_id: 1.into()
9169 })))))
9170 })
9171 }
9172 ]
9173 ))
9174 })
9175 ]))]
9176 #[case::match_with_guard(
9177 vec![
9178 token(TokenKind::Match),
9179 token(TokenKind::LParen),
9180 token(TokenKind::Ident(SmolStr::new("n"))),
9181 token(TokenKind::RParen),
9182 token(TokenKind::Colon),
9183 token(TokenKind::Pipe),
9184 token(TokenKind::Ident(SmolStr::new("x"))),
9185 token(TokenKind::If),
9186 token(TokenKind::LParen),
9187 token(TokenKind::Ident(SmolStr::new("x"))),
9188 token(TokenKind::Gt),
9189 token(TokenKind::NumberLiteral(0.into())),
9190 token(TokenKind::RParen),
9191 token(TokenKind::Colon),
9192 token(TokenKind::StringLiteral("positive".to_owned())),
9193 token(TokenKind::Pipe),
9194 token(TokenKind::Ident(SmolStr::new("x"))),
9195 token(TokenKind::If),
9196 token(TokenKind::LParen),
9197 token(TokenKind::Ident(SmolStr::new("x"))),
9198 token(TokenKind::Lt),
9199 token(TokenKind::NumberLiteral(0.into())),
9200 token(TokenKind::RParen),
9201 token(TokenKind::Colon),
9202 token(TokenKind::StringLiteral("negative".to_owned())),
9203 token(TokenKind::Pipe),
9204 token(TokenKind::Ident(SmolStr::new("_"))),
9205 token(TokenKind::Colon),
9206 token(TokenKind::StringLiteral("zero".to_owned())),
9207 token(TokenKind::End),
9208 token(TokenKind::Eof)
9209 ],
9210 Ok(vec![
9211 Shared::new(Node {
9212 token_id: 0.into(),
9213 expr: Shared::new(Expr::Match(
9214 Shared::new(Node {
9215 token_id: 1.into(),
9216 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("n", Some(Shared::new(Token {
9217 range: Range::default(),
9218 kind: TokenKind::Ident(SmolStr::new("n")),
9219 module_id: 1.into()
9220 })))))
9221 }),
9222 smallvec![
9223 MatchArm {
9224 pattern: Pattern::Ident(IdentWithToken::new("x")),
9225 guard: Some(Shared::new(Node {
9226 token_id: 5.into(),
9227 expr: Shared::new(Expr::Call(
9228 IdentWithToken::new_with_token(constants::builtins::GT, Some(Shared::new(token(TokenKind::Gt)))),
9229 smallvec![
9230 Shared::new(Node {
9231 token_id: 4.into(),
9232 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(Token {
9233 range: Range::default(),
9234 kind: TokenKind::Ident(SmolStr::new("x")),
9235 module_id: 1.into()
9236 })))))
9237 }),
9238 Shared::new(Node {
9239 token_id: 6.into(),
9240 expr: Shared::new(Expr::Literal(Literal::Number(0.into())))
9241 })
9242 ]
9243 ))
9244 })),
9245 body: Shared::new(Node {
9246 token_id: 8.into(),
9247 expr: Shared::new(Expr::Literal(Literal::String("positive".to_owned())))
9248 })
9249 },
9250 MatchArm {
9251 pattern: Pattern::Ident(IdentWithToken::new("x")),
9252 guard: Some(Shared::new(Node {
9253 token_id: 11.into(),
9254 expr: Shared::new(Expr::Call(
9255 IdentWithToken::new_with_token(constants::builtins::LT, Some(Shared::new(token(TokenKind::Lt)))),
9256 smallvec![
9257 Shared::new(Node {
9258 token_id: 10.into(),
9259 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(Token {
9260 range: Range::default(),
9261 kind: TokenKind::Ident(SmolStr::new("x")),
9262 module_id: 1.into()
9263 })))))
9264 }),
9265 Shared::new(Node {
9266 token_id: 12.into(),
9267 expr: Shared::new(Expr::Literal(Literal::Number(0.into())))
9268 })
9269 ]
9270 ))
9271 })),
9272 body: Shared::new(Node {
9273 token_id: 14.into(),
9274 expr: Shared::new(Expr::Literal(Literal::String("negative".to_owned())))
9275 })
9276 },
9277 MatchArm {
9278 pattern: Pattern::Wildcard,
9279 guard: None,
9280 body: Shared::new(Node {
9281 token_id: 17.into(),
9282 expr: Shared::new(Expr::Literal(Literal::String("zero".to_owned())))
9283 })
9284 }
9285 ]
9286 ))
9287 })
9288 ]))]
9289 #[case::match_do_end(
9290 vec![
9291 token(TokenKind::Match),
9292 token(TokenKind::LParen),
9293 token(TokenKind::NumberLiteral(2.into())),
9294 token(TokenKind::RParen),
9295 token(TokenKind::Do),
9296 token(TokenKind::Pipe),
9297 token(TokenKind::NumberLiteral(1.into())),
9298 token(TokenKind::Colon),
9299 token(TokenKind::StringLiteral("one".to_owned())),
9300 token(TokenKind::Pipe),
9301 token(TokenKind::NumberLiteral(2.into())),
9302 token(TokenKind::Colon),
9303 token(TokenKind::StringLiteral("two".to_owned())),
9304 token(TokenKind::Pipe),
9305 token(TokenKind::Ident(SmolStr::new("_"))),
9306 token(TokenKind::Colon),
9307 token(TokenKind::StringLiteral("other".to_owned())),
9308 token(TokenKind::End),
9309 token(TokenKind::Eof)
9310 ],
9311 Ok(vec![
9312 Shared::new(Node {
9313 token_id: 0.into(),
9314 expr: Shared::new(Expr::Match(
9315 Shared::new(Node {
9316 token_id: 1.into(),
9317 expr: Shared::new(Expr::Literal(Literal::Number(2.into())))
9318 }),
9319 smallvec![
9320 MatchArm {
9321 pattern: Pattern::Literal(Literal::Number(1.into())),
9322 guard: None,
9323 body: Shared::new(Node {
9324 token_id: 5.into(),
9325 expr: Shared::new(Expr::Literal(Literal::String("one".to_owned())))
9326 })
9327 },
9328 MatchArm {
9329 pattern: Pattern::Literal(Literal::Number(2.into())),
9330 guard: None,
9331 body: Shared::new(Node {
9332 token_id: 8.into(),
9333 expr: Shared::new(Expr::Literal(Literal::String("two".to_owned())))
9334 })
9335 },
9336 MatchArm {
9337 pattern: Pattern::Wildcard,
9338 guard: None,
9339 body: Shared::new(Node {
9340 token_id: 11.into(),
9341 expr: Shared::new(Expr::Literal(Literal::String("other".to_owned())))
9342 })
9343 }
9344 ]
9345 ))
9346 })
9347 ]))]
9348 #[case::match_or_two_literal_numbers(
9353 vec![
9354 token(TokenKind::Match),
9355 token(TokenKind::LParen),
9356 token(TokenKind::Ident(SmolStr::new("x"))),
9357 token(TokenKind::RParen),
9358 token(TokenKind::Colon),
9359 token(TokenKind::Pipe),
9360 token(TokenKind::NumberLiteral(1.into())),
9361 token(TokenKind::Or),
9362 token(TokenKind::NumberLiteral(2.into())),
9363 token(TokenKind::Colon),
9364 token(TokenKind::StringLiteral("matched".to_owned())),
9365 token(TokenKind::Pipe),
9366 token(TokenKind::Ident(SmolStr::new("_"))),
9367 token(TokenKind::Colon),
9368 token(TokenKind::StringLiteral("other".to_owned())),
9369 token(TokenKind::End),
9370 token(TokenKind::Eof),
9371 ],
9372 Ok(vec![
9373 Shared::new(Node {
9374 token_id: 0.into(),
9375 expr: Shared::new(Expr::Match(
9376 Shared::new(Node {
9377 token_id: 1.into(),
9378 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(Token {
9379 range: Range::default(),
9380 kind: TokenKind::Ident(SmolStr::new("x")),
9381 module_id: 1.into()
9382 })))))
9383 }),
9384 smallvec![
9385 MatchArm {
9386 pattern: Pattern::Or(vec![
9387 Pattern::Literal(Literal::Number(1.into())),
9388 Pattern::Literal(Literal::Number(2.into())),
9389 ]),
9390 guard: None,
9391 body: Shared::new(Node {
9392 token_id: 5.into(),
9393 expr: Shared::new(Expr::Literal(Literal::String("matched".to_owned())))
9394 })
9395 },
9396 MatchArm {
9397 pattern: Pattern::Wildcard,
9398 guard: None,
9399 body: Shared::new(Node {
9400 token_id: 8.into(),
9401 expr: Shared::new(Expr::Literal(Literal::String("other".to_owned())))
9402 })
9403 },
9404 ]
9405 ))
9406 })
9407 ]))]
9408 #[case::match_or_string_literals(
9409 vec![
9410 token(TokenKind::Match),
9411 token(TokenKind::LParen),
9412 token(TokenKind::Ident(SmolStr::new("x"))),
9413 token(TokenKind::RParen),
9414 token(TokenKind::Colon),
9415 token(TokenKind::Pipe),
9416 token(TokenKind::StringLiteral("a".to_owned())),
9417 token(TokenKind::Or),
9418 token(TokenKind::StringLiteral("b".to_owned())),
9419 token(TokenKind::Colon),
9420 token(TokenKind::StringLiteral("matched".to_owned())),
9421 token(TokenKind::Pipe),
9422 token(TokenKind::Ident(SmolStr::new("_"))),
9423 token(TokenKind::Colon),
9424 token(TokenKind::StringLiteral("other".to_owned())),
9425 token(TokenKind::End),
9426 token(TokenKind::Eof),
9427 ],
9428 Ok(vec![
9429 Shared::new(Node {
9430 token_id: 0.into(),
9431 expr: Shared::new(Expr::Match(
9432 Shared::new(Node {
9433 token_id: 1.into(),
9434 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(Token {
9435 range: Range::default(),
9436 kind: TokenKind::Ident(SmolStr::new("x")),
9437 module_id: 1.into()
9438 })))))
9439 }),
9440 smallvec![
9441 MatchArm {
9442 pattern: Pattern::Or(vec![
9443 Pattern::Literal(Literal::String("a".to_owned())),
9444 Pattern::Literal(Literal::String("b".to_owned())),
9445 ]),
9446 guard: None,
9447 body: Shared::new(Node {
9448 token_id: 5.into(),
9449 expr: Shared::new(Expr::Literal(Literal::String("matched".to_owned())))
9450 })
9451 },
9452 MatchArm {
9453 pattern: Pattern::Wildcard,
9454 guard: None,
9455 body: Shared::new(Node {
9456 token_id: 8.into(),
9457 expr: Shared::new(Expr::Literal(Literal::String("other".to_owned())))
9458 })
9459 },
9460 ]
9461 ))
9462 })
9463 ]))]
9464 #[case::match_or_type_patterns(
9465 vec![
9466 token(TokenKind::Match),
9467 token(TokenKind::LParen),
9468 token(TokenKind::Ident(SmolStr::new("x"))),
9469 token(TokenKind::RParen),
9470 token(TokenKind::Colon),
9471 token(TokenKind::Pipe),
9472 token(TokenKind::Colon),
9473 token(TokenKind::Ident(SmolStr::new("string"))),
9474 token(TokenKind::Or),
9475 token(TokenKind::Colon),
9476 token(TokenKind::Ident(SmolStr::new("number"))),
9477 token(TokenKind::Colon),
9478 token(TokenKind::StringLiteral("str or num".to_owned())),
9479 token(TokenKind::End),
9480 token(TokenKind::Eof),
9481 ],
9482 Ok(vec![
9483 Shared::new(Node {
9484 token_id: 0.into(),
9485 expr: Shared::new(Expr::Match(
9486 Shared::new(Node {
9487 token_id: 1.into(),
9488 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(Token {
9489 range: Range::default(),
9490 kind: TokenKind::Ident(SmolStr::new("x")),
9491 module_id: 1.into()
9492 })))))
9493 }),
9494 smallvec![
9495 MatchArm {
9496 pattern: Pattern::Or(vec![
9497 Pattern::Type(Ident::new("string")),
9498 Pattern::Type(Ident::new("number")),
9499 ]),
9500 guard: None,
9501 body: Shared::new(Node {
9502 token_id: 5.into(),
9503 expr: Shared::new(Expr::Literal(Literal::String("str or num".to_owned())))
9504 })
9505 },
9506 ]
9507 ))
9508 })
9509 ]))]
9510 #[case::match_or_three_alternatives(
9511 vec![
9512 token(TokenKind::Match),
9513 token(TokenKind::LParen),
9514 token(TokenKind::Ident(SmolStr::new("x"))),
9515 token(TokenKind::RParen),
9516 token(TokenKind::Colon),
9517 token(TokenKind::Pipe),
9518 token(TokenKind::NumberLiteral(1.into())),
9519 token(TokenKind::Or),
9520 token(TokenKind::NumberLiteral(2.into())),
9521 token(TokenKind::Or),
9522 token(TokenKind::NumberLiteral(3.into())),
9523 token(TokenKind::Colon),
9524 token(TokenKind::StringLiteral("matched".to_owned())),
9525 token(TokenKind::Pipe),
9526 token(TokenKind::Ident(SmolStr::new("_"))),
9527 token(TokenKind::Colon),
9528 token(TokenKind::StringLiteral("other".to_owned())),
9529 token(TokenKind::End),
9530 token(TokenKind::Eof),
9531 ],
9532 Ok(vec![
9533 Shared::new(Node {
9534 token_id: 0.into(),
9535 expr: Shared::new(Expr::Match(
9536 Shared::new(Node {
9537 token_id: 1.into(),
9538 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(Token {
9539 range: Range::default(),
9540 kind: TokenKind::Ident(SmolStr::new("x")),
9541 module_id: 1.into()
9542 })))))
9543 }),
9544 smallvec![
9545 MatchArm {
9546 pattern: Pattern::Or(vec![
9547 Pattern::Literal(Literal::Number(1.into())),
9548 Pattern::Literal(Literal::Number(2.into())),
9549 Pattern::Literal(Literal::Number(3.into())),
9550 ]),
9551 guard: None,
9552 body: Shared::new(Node {
9553 token_id: 5.into(),
9554 expr: Shared::new(Expr::Literal(Literal::String("matched".to_owned())))
9555 })
9556 },
9557 MatchArm {
9558 pattern: Pattern::Wildcard,
9559 guard: None,
9560 body: Shared::new(Node {
9561 token_id: 8.into(),
9562 expr: Shared::new(Expr::Literal(Literal::String("other".to_owned())))
9563 })
9564 },
9565 ]
9566 ))
9567 })
9568 ]))]
9569 #[case::match_or_bool_literals(
9570 vec![
9571 token(TokenKind::Match),
9572 token(TokenKind::LParen),
9573 token(TokenKind::Ident(SmolStr::new("x"))),
9574 token(TokenKind::RParen),
9575 token(TokenKind::Colon),
9576 token(TokenKind::Pipe),
9577 token(TokenKind::BoolLiteral(true)),
9578 token(TokenKind::Or),
9579 token(TokenKind::BoolLiteral(false)),
9580 token(TokenKind::Colon),
9581 token(TokenKind::StringLiteral("bool".to_owned())),
9582 token(TokenKind::End),
9583 token(TokenKind::Eof),
9584 ],
9585 Ok(vec![
9586 Shared::new(Node {
9587 token_id: 0.into(),
9588 expr: Shared::new(Expr::Match(
9589 Shared::new(Node {
9590 token_id: 1.into(),
9591 expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(Token {
9592 range: Range::default(),
9593 kind: TokenKind::Ident(SmolStr::new("x")),
9594 module_id: 1.into()
9595 })))))
9596 }),
9597 smallvec![
9598 MatchArm {
9599 pattern: Pattern::Or(vec![
9600 Pattern::Literal(Literal::Bool(true)),
9601 Pattern::Literal(Literal::Bool(false)),
9602 ]),
9603 guard: None,
9604 body: Shared::new(Node {
9605 token_id: 5.into(),
9606 expr: Shared::new(Expr::Literal(Literal::String("bool".to_owned())))
9607 })
9608 },
9609 ]
9610 ))
9611 })
9612 ]))]
9613 fn test_parse_match(#[case] input: Vec<Token>, #[case] expected: Result<Program, SyntaxError>) {
9614 let mut arena = Arena::new(10);
9615 let tokens: Vec<Shared<Token>> = input.into_iter().map(Shared::new).collect();
9616 let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
9617 assert_eq!(result, expected);
9618 }
9619
9620 #[rstest]
9621 #[case::expr_literal(
9622 vec![
9623 lexer::token::StringSegment::Text("Value: ".to_string(), Range::default()),
9624 lexer::token::StringSegment::Expr("42".into(), Range::default()),
9625 ],
9626 2,
9627 |segments: &[StringSegment]| {
9628 matches!(&segments[0], StringSegment::Text(s) if s == "Value: ") &&
9629 matches!(&segments[1], StringSegment::Expr(node) if matches!(&*node.expr, Expr::Literal(Literal::Number(_))))
9630 }
9631 )]
9632 #[case::expr_string(
9633 vec![
9634 lexer::token::StringSegment::Text("Result: ".to_string(), Range::default()),
9635 lexer::token::StringSegment::Expr("\"hello\"".into(), Range::default()),
9636 ],
9637 2,
9638 |segments: &[StringSegment]| {
9639 matches!(&segments[0], StringSegment::Text(s) if s == "Result: ") &&
9640 matches!(&segments[1], StringSegment::Expr(node) if matches!(&*node.expr, Expr::Literal(Literal::String(s)) if s == "hello"))
9641 }
9642 )]
9643 #[case::expr_call(
9644 vec![
9645 lexer::token::StringSegment::Text("Result: ".to_string(), Range::default()),
9646 lexer::token::StringSegment::Expr("add(1, 2)".into(), Range::default()),
9647 ],
9648 2,
9649 |segments: &[StringSegment]| {
9650 matches!(&segments[0], StringSegment::Text(s) if s == "Result: ") &&
9651 if let StringSegment::Expr(node) = &segments[1] {
9652 if let Expr::Call(ident, args) = &*node.expr {
9653 ident.name == "add".into() && args.len() == 2
9654 } else {
9655 false
9656 }
9657 } else {
9658 false
9659 }
9660 }
9661 )]
9662 #[case::expr_self(
9663 vec![
9664 lexer::token::StringSegment::Text("Value: ".to_string(), Range::default()),
9665 lexer::token::StringSegment::Expr("self".into(), Range::default()),
9666 ],
9667 2,
9668 |segments: &[StringSegment]| {
9669 matches!(&segments[0], StringSegment::Text(s) if s == "Value: ") &&
9670 matches!(&segments[1], StringSegment::Self_)
9671 }
9672 )]
9673 #[case::expr_env(
9674 vec![
9675 lexer::token::StringSegment::Text("Env: ".to_string(), Range::default()),
9676 lexer::token::StringSegment::Expr("$MQ_TEST_INTERPOLATION".into(), Range::default()),
9677 ],
9678 2,
9679 |segments: &[StringSegment]| {
9680 unsafe { std::env::set_var("MQ_TEST_INTERPOLATION", "test_value") };
9681 matches!(&segments[0], StringSegment::Text(s) if s == "Env: ") &&
9682 matches!(&segments[1], StringSegment::Env(var) if var == "MQ_TEST_INTERPOLATION")
9683 }
9684 )]
9685 #[case::multiple_exprs(
9686 vec![
9687 lexer::token::StringSegment::Text("A: ".to_string(), Range::default()),
9688 lexer::token::StringSegment::Expr("1".into(), Range::default()),
9689 lexer::token::StringSegment::Text(", B: ".to_string(), Range::default()),
9690 lexer::token::StringSegment::Expr("2".into(), Range::default()),
9691 ],
9692 4,
9693 |segments: &[StringSegment]| {
9694 matches!(&segments[0], StringSegment::Text(s) if s == "A: ") &&
9695 matches!(&segments[1], StringSegment::Expr(_)) &&
9696 matches!(&segments[2], StringSegment::Text(s) if s == ", B: ") &&
9697 matches!(&segments[3], StringSegment::Expr(_))
9698 }
9699 )]
9700 #[case::mixed_segments(
9701 vec![
9702 lexer::token::StringSegment::Text("Literal, ".to_string(), Range::default()),
9703 lexer::token::StringSegment::Expr("self".into(), Range::default()),
9704 lexer::token::StringSegment::Text(", ".to_string(), Range::default()),
9705 lexer::token::StringSegment::Expr("$MQ_MIXED_TEST".into(), Range::default()),
9706 lexer::token::StringSegment::Text(", ".to_string(), Range::default()),
9707 lexer::token::StringSegment::Expr("42".into(), Range::default()),
9708 ],
9709 6,
9710 |segments: &[StringSegment]| {
9711 unsafe { std::env::set_var("MQ_MIXED_TEST", "env_value") };
9712 matches!(&segments[0], StringSegment::Text(s) if s == "Literal, ") &&
9713 matches!(&segments[1], StringSegment::Self_) &&
9714 matches!(&segments[2], StringSegment::Text(s) if s == ", ") &&
9715 matches!(&segments[3], StringSegment::Env(var) if var == "MQ_MIXED_TEST") &&
9716 matches!(&segments[4], StringSegment::Text(s) if s == ", ") &&
9717 matches!(&segments[5], StringSegment::Expr(_))
9718 }
9719 )]
9720 #[case::expr_bool(
9721 vec![
9722 lexer::token::StringSegment::Text("Bool: ".to_string(), Range::default()),
9723 lexer::token::StringSegment::Expr("true".into(), Range::default()),
9724 ],
9725 2,
9726 |segments: &[StringSegment]| {
9727 matches!(&segments[0], StringSegment::Text(s) if s == "Bool: ") &&
9728 matches!(&segments[1], StringSegment::Expr(node) if matches!(&*node.expr, Expr::Literal(Literal::Bool(true))))
9729 }
9730 )]
9731 fn test_parse_interpolated_string_with_expr(
9732 #[case] input_segments: Vec<lexer::token::StringSegment>,
9733 #[case] expected_len: usize,
9734 #[case] validator: fn(&[StringSegment]) -> bool,
9735 ) {
9736 let mut arena = Arena::new(10);
9737 let tokens = [
9738 Shared::new(Token {
9739 range: Range::default(),
9740 kind: TokenKind::InterpolatedString(input_segments),
9741 module_id: 1.into(),
9742 }),
9743 Shared::new(Token {
9744 range: Range::default(),
9745 kind: TokenKind::Eof,
9746 module_id: 1.into(),
9747 }),
9748 ];
9749
9750 let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
9751
9752 match result {
9753 Ok(program) => {
9754 assert_eq!(program.len(), 1);
9755 if let Expr::InterpolatedString(segments) = &*program[0].expr {
9756 assert_eq!(segments.len(), expected_len);
9757 assert!(validator(segments), "Validator failed for segments");
9758 } else {
9759 panic!("Expected InterpolatedString, got {:?}", program[0].expr);
9760 }
9761 }
9762 Err(err) => panic!("Parse error: {:?}", err),
9763 }
9764 }
9765}