1#![allow(clippy::approx_constant)]
5
6use crate::ast::{AstNode, BinaryOp, PathStep, Stage, UnaryOp};
7use thiserror::Error;
8
9#[derive(Error, Debug)]
11pub enum ParserError {
12 #[error("Unexpected token: {0}")]
13 UnexpectedToken(String),
14
15 #[error("Unexpected end of expression")]
16 UnexpectedEnd,
17
18 #[error("Invalid syntax: {0}")]
19 InvalidSyntax(String),
20
21 #[error("Invalid number: {0}")]
22 InvalidNumber(String),
23
24 #[error("Unclosed string literal")]
25 UnclosedString,
26
27 #[error("Invalid escape sequence: {0}")]
28 InvalidEscape(String),
29
30 #[error("Unclosed comment")]
31 UnclosedComment,
32
33 #[error("Unclosed backtick name")]
34 UnclosedBacktick,
35
36 #[error("Expected {expected}, found {found}")]
37 Expected { expected: String, found: String },
38
39 #[error("{code}: {message}")]
44 Coded { code: &'static str, message: String },
45}
46
47#[derive(Debug, Clone, PartialEq)]
49pub enum Token {
50 String(String),
52 Number(f64),
53 True,
54 False,
55 Null,
56 Undefined, Regex { pattern: String, flags: String }, Identifier(String),
61 Variable(String),
62 ParentVariable(String), Function, Plus,
67 Minus,
68 Star,
69 StarStar, Slash,
71 Percent,
72 Equal,
73 NotEqual,
74 LessThan,
75 LessThanOrEqual,
76 GreaterThan,
77 GreaterThanOrEqual,
78 And,
79 Or,
80 In,
81 Ampersand,
82 Dot,
83 DotDot,
84 Question,
85 QuestionQuestion, QuestionColon, Colon,
88 ColonEqual, TildeArrow, LeftParen,
93 RightParen,
94 LeftBracket,
95 RightBracket,
96 LeftBrace,
97 RightBrace,
98 Comma,
99 Semicolon,
100 Caret, Pipe, Hash, At, Eof,
107}
108
109pub struct Lexer {
111 input: Vec<char>,
112 position: usize,
113 last_token: Option<Token>,
114}
115
116impl Lexer {
117 pub fn new(input: String) -> Self {
118 Lexer {
119 input: input.chars().collect(),
120 position: 0,
121 last_token: None,
122 }
123 }
124
125 fn current(&self) -> Option<char> {
126 self.input.get(self.position).copied()
127 }
128
129 fn peek(&self, offset: usize) -> Option<char> {
130 self.input.get(self.position + offset).copied()
131 }
132
133 fn advance(&mut self) {
134 if self.position < self.input.len() {
135 self.position += 1;
136 }
137 }
138
139 fn skip_whitespace(&mut self) {
140 while self.current().is_some_and(|ch| ch.is_whitespace()) {
141 self.advance();
142 }
143 }
144
145 fn skip_comment(&mut self) -> Result<(), ParserError> {
146 if self.peek(1) == Some('*') {
148 self.advance(); self.advance(); loop {
153 match self.current() {
154 None => return Err(ParserError::UnclosedComment),
155 Some('*') if self.peek(1) == Some('/') => {
156 self.advance(); self.advance(); break;
159 }
160 Some(_) => self.advance(),
161 }
162 }
163 }
164 Ok(())
165 }
166
167 fn read_string(&mut self, quote_char: char) -> Result<String, ParserError> {
168 let mut result = String::new();
169 self.advance(); loop {
172 match self.current() {
173 None => return Err(ParserError::UnclosedString),
174 Some(ch) if ch == quote_char => {
175 self.advance(); return Ok(result);
177 }
178 Some('\\') => {
179 self.advance();
180 match self.current() {
181 None => return Err(ParserError::UnclosedString),
182 Some('"') => result.push('"'),
183 Some('\\') => result.push('\\'),
184 Some('/') => result.push('/'),
185 Some('b') => result.push('\u{0008}'),
186 Some('f') => result.push('\u{000C}'),
187 Some('n') => result.push('\n'),
188 Some('r') => result.push('\r'),
189 Some('t') => result.push('\t'),
190 Some('u') => {
191 self.advance();
193 let mut hex = String::new();
194 for _ in 0..4 {
195 match self.current() {
196 Some(h) if h.is_ascii_hexdigit() => {
197 hex.push(h);
198 self.advance();
199 }
200 _ => {
201 return Err(ParserError::InvalidEscape(format!(
202 "\\u{}",
203 hex
204 )))
205 }
206 }
207 }
208 let code = u32::from_str_radix(&hex, 16).unwrap();
209 if (0xD800..=0xDBFF).contains(&code) {
210 if self.current() == Some('\\') {
212 self.advance();
213 if self.current() == Some('u') {
214 self.advance();
215 let mut low_hex = String::new();
216 for _ in 0..4 {
217 match self.current() {
218 Some(h) if h.is_ascii_hexdigit() => {
219 low_hex.push(h);
220 self.advance();
221 }
222 _ => {
223 return Err(ParserError::InvalidEscape(
224 format!("\\u{}", low_hex),
225 ))
226 }
227 }
228 }
229 let low = u32::from_str_radix(&low_hex, 16).unwrap();
230 if (0xDC00..=0xDFFF).contains(&low) {
231 let cp =
232 0x10000 + (code - 0xD800) * 0x400 + (low - 0xDC00);
233 if let Some(ch) = char::from_u32(cp) {
234 result.push(ch);
235 } else {
236 return Err(ParserError::InvalidEscape(format!(
237 "\\u{}\\u{}",
238 hex, low_hex
239 )));
240 }
241 } else {
242 return Err(ParserError::InvalidEscape(format!(
243 "\\u{}\\u{}",
244 hex, low_hex
245 )));
246 }
247 } else {
248 return Err(ParserError::InvalidEscape(format!(
249 "\\u{}",
250 hex
251 )));
252 }
253 } else {
254 return Err(ParserError::InvalidEscape(format!("\\u{}", hex)));
255 }
256 } else if let Some(ch) = char::from_u32(code) {
257 result.push(ch);
258 } else {
259 return Err(ParserError::InvalidEscape(format!("\\u{}", hex)));
260 }
261 continue; }
263 Some(ch) => return Err(ParserError::InvalidEscape(format!("\\{}", ch))),
264 }
265 self.advance();
266 }
267 Some(ch) => {
268 result.push(ch);
269 self.advance();
270 }
271 }
272 }
273 }
274
275 fn read_number(&mut self) -> Result<f64, ParserError> {
276 let start = self.position;
277
278 if self.current() == Some('0') {
280 self.advance();
281 } else if self.current().is_some_and(|c| c.is_ascii_digit()) {
282 while self.current().is_some_and(|c| c.is_ascii_digit()) {
283 self.advance();
284 }
285 } else {
286 return Err(ParserError::InvalidNumber("Expected digit".to_string()));
287 }
288
289 if self.current() == Some('.') && self.peek(1) != Some('.') {
291 self.advance();
293 if !self.current().is_some_and(|c| c.is_ascii_digit()) {
294 return Err(ParserError::InvalidNumber(
295 "Expected digit after decimal point".to_string(),
296 ));
297 }
298 while self.current().is_some_and(|c| c.is_ascii_digit()) {
299 self.advance();
300 }
301 }
302
303 if matches!(self.current(), Some('e') | Some('E')) {
305 self.advance();
306 if matches!(self.current(), Some('+') | Some('-')) {
307 self.advance();
308 }
309 if !self.current().is_some_and(|c| c.is_ascii_digit()) {
310 return Err(ParserError::InvalidNumber(
311 "Expected digit in exponent".to_string(),
312 ));
313 }
314 while self.current().is_some_and(|c| c.is_ascii_digit()) {
315 self.advance();
316 }
317 }
318
319 let num_str: String = self.input[start..self.position].iter().collect();
320 let num: f64 = num_str
321 .parse()
322 .map_err(|_| ParserError::InvalidNumber(num_str.clone()))?;
323
324 if num.is_infinite() {
326 return Err(ParserError::InvalidNumber(format!(
327 "S0102: Number out of range: {}",
328 num_str
329 )));
330 }
331
332 Ok(num)
333 }
334
335 fn read_identifier(&mut self) -> String {
336 let start = self.position;
337
338 while let Some(ch) = self.current() {
339 if ch.is_alphanumeric() || ch == '_' {
341 self.advance();
342 } else {
343 break;
344 }
345 }
346
347 self.input[start..self.position].iter().collect()
348 }
349
350 fn read_backtick_name(&mut self) -> Result<String, ParserError> {
351 self.advance(); let start = self.position;
353
354 while let Some(ch) = self.current() {
355 if ch == '`' {
356 let name: String = self.input[start..self.position].iter().collect();
357 self.advance(); return Ok(name);
359 }
360 self.advance();
361 }
362
363 Err(ParserError::UnclosedBacktick)
364 }
365
366 fn read_regex(&mut self) -> Result<Token, ParserError> {
367 self.advance(); let mut pattern = String::new();
371 let mut escaped = false;
372
373 loop {
374 match self.current() {
375 None => return Err(ParserError::UnclosedString),
376 Some('/') if !escaped => {
377 self.advance(); break;
379 }
380 Some('\\') if !escaped => {
381 escaped = true;
382 pattern.push('\\');
383 self.advance();
384 }
385 Some(ch) => {
386 escaped = false;
387 pattern.push(ch);
388 self.advance();
389 }
390 }
391 }
392
393 let mut flags = String::new();
395 while let Some(ch) = self.current() {
396 if ch.is_alphabetic() {
397 flags.push(ch);
398 self.advance();
399 } else {
400 break;
401 }
402 }
403
404 Ok(Token::Regex { pattern, flags })
405 }
406
407 fn emit_token(&mut self, token: Token) -> Result<Token, ParserError> {
408 self.last_token = Some(token.clone());
409 Ok(token)
410 }
411
412 pub fn next_token(&mut self) -> Result<Token, ParserError> {
413 loop {
414 self.skip_whitespace();
415
416 match self.current() {
417 None => return Ok(Token::Eof),
418
419 Some('/') if self.peek(1) == Some('*') => {
421 self.skip_comment()?;
422 continue; }
424
425 Some('"') => {
427 let s = self.read_string('"')?;
428 return self.emit_token(Token::String(s));
429 }
430 Some('\'') => {
431 let s = self.read_string('\'')?;
432 return self.emit_token(Token::String(s));
433 }
434
435 Some('`') => {
437 let name = self.read_backtick_name()?;
438 return self.emit_token(Token::Identifier(name));
439 }
440
441 Some(ch) if ch.is_ascii_digit() => {
443 let num = self.read_number()?;
444 return self.emit_token(Token::Number(num));
445 }
446
447 Some('$') if self.peek(1) == Some('$') => {
449 self.advance(); self.advance(); let name = self.read_identifier();
453 return self.emit_token(Token::ParentVariable(name));
454 }
455 Some('$') => {
456 self.advance();
457 let name = self.read_identifier();
458 return self.emit_token(Token::Variable(name));
459 }
460
461 Some('.') if self.peek(1) == Some('.') => {
463 self.advance();
464 self.advance();
465 return Ok(Token::DotDot);
466 }
467 Some(':') if self.peek(1) == Some('=') => {
468 self.advance();
469 self.advance();
470 return Ok(Token::ColonEqual);
471 }
472 Some('!') if self.peek(1) == Some('=') => {
473 self.advance();
474 self.advance();
475 return Ok(Token::NotEqual);
476 }
477 Some('>') if self.peek(1) == Some('=') => {
478 self.advance();
479 self.advance();
480 return Ok(Token::GreaterThanOrEqual);
481 }
482 Some('<') if self.peek(1) == Some('=') => {
483 self.advance();
484 self.advance();
485 return Ok(Token::LessThanOrEqual);
486 }
487 Some('~') if self.peek(1) == Some('>') => {
488 self.advance();
489 self.advance();
490 return self.emit_token(Token::TildeArrow);
491 }
492
493 Some('(') => {
495 self.advance();
496 return Ok(Token::LeftParen);
497 }
498 Some(')') => {
499 self.advance();
500 return self.emit_token(Token::RightParen);
501 }
502 Some('[') => {
503 self.advance();
504 return Ok(Token::LeftBracket);
505 }
506 Some(']') => {
507 self.advance();
508 return self.emit_token(Token::RightBracket);
509 }
510 Some('{') => {
511 self.advance();
512 return Ok(Token::LeftBrace);
513 }
514 Some('}') => {
515 self.advance();
516 return self.emit_token(Token::RightBrace);
517 }
518 Some(',') => {
519 self.advance();
520 return self.emit_token(Token::Comma);
521 }
522 Some(';') => {
523 self.advance();
524 return self.emit_token(Token::Semicolon);
525 }
526 Some(':') => {
527 self.advance();
528 return Ok(Token::Colon);
529 }
530 Some('?') if self.peek(1) == Some('?') => {
531 self.advance();
532 self.advance();
533 return Ok(Token::QuestionQuestion);
534 }
535 Some('?') if self.peek(1) == Some(':') => {
536 self.advance();
537 self.advance();
538 return Ok(Token::QuestionColon);
539 }
540 Some('?') => {
541 self.advance();
542 return Ok(Token::Question);
543 }
544 Some('λ') => {
545 self.advance();
547 return Ok(Token::Function);
548 }
549 Some('.') => {
550 self.advance();
551 return Ok(Token::Dot);
552 }
553 Some('+') => {
554 self.advance();
555 return Ok(Token::Plus);
556 }
557 Some('-') => {
558 self.advance();
559 return Ok(Token::Minus);
560 }
561 Some('*') if self.peek(1) == Some('*') => {
562 self.advance();
563 self.advance();
564 return Ok(Token::StarStar);
565 }
566 Some('*') => {
567 self.advance();
568 return Ok(Token::Star);
569 }
570 Some('/') => {
571 let is_regex = match &self.last_token {
580 None => true, Some(Token::LeftParen)
582 | Some(Token::LeftBracket)
583 | Some(Token::LeftBrace) => true,
584 Some(Token::Comma) | Some(Token::Semicolon) | Some(Token::Colon) => true,
585 Some(Token::Equal) | Some(Token::NotEqual) => true,
586 Some(Token::LessThan) | Some(Token::LessThanOrEqual) => true,
587 Some(Token::GreaterThan) | Some(Token::GreaterThanOrEqual) => true,
588 Some(Token::Plus) | Some(Token::Minus) | Some(Token::Star)
589 | Some(Token::Percent) => true,
590 Some(Token::Ampersand)
591 | Some(Token::Question)
592 | Some(Token::TildeArrow) => true,
593 Some(Token::ColonEqual)
594 | Some(Token::QuestionQuestion)
595 | Some(Token::QuestionColon) => true,
596 Some(Token::And) | Some(Token::Or) | Some(Token::In) => true,
597 Some(Token::Function) => true,
598 Some(Token::Identifier(s)) if s == "and" || s == "or" || s == "in" => true,
599 _ => false, };
601
602 if is_regex {
603 let tok = self.read_regex()?;
604 return self.emit_token(tok);
605 } else {
606 self.advance();
607 return self.emit_token(Token::Slash);
608 }
609 }
610 Some('%') => {
611 self.advance();
612 return Ok(Token::Percent);
613 }
614 Some('^') => {
615 self.advance();
616 return Ok(Token::Caret);
617 }
618 Some('#') => {
619 self.advance();
620 return Ok(Token::Hash);
621 }
622 Some('@') => {
623 self.advance();
624 return Ok(Token::At);
625 }
626 Some('=') => {
627 self.advance();
628 return Ok(Token::Equal);
629 }
630 Some('<') => {
631 self.advance();
632 return Ok(Token::LessThan);
633 }
634 Some('>') => {
635 self.advance();
636 return Ok(Token::GreaterThan);
637 }
638 Some('&') => {
639 self.advance();
640 return Ok(Token::Ampersand);
641 }
642 Some('|') => {
643 self.advance();
644 return Ok(Token::Pipe);
645 }
646
647 Some(ch) if ch.is_alphabetic() || ch == '_' => {
649 let ident = self.read_identifier();
650 let tok = match ident.as_str() {
651 "true" => Token::True,
652 "false" => Token::False,
653 "null" => Token::Null,
654 "undefined" => Token::Undefined,
655 "function" => Token::Function,
656 _ => Token::Identifier(ident),
658 };
659 return self.emit_token(tok);
660 }
661
662 Some(ch) => {
663 return Err(ParserError::UnexpectedToken(ch.to_string()));
664 }
665 }
666 }
667 }
668}
669
670pub struct Parser {
672 lexer: Lexer,
673 current_token: Token,
674}
675
676impl Parser {
677 pub fn new(input: String) -> Result<Self, ParserError> {
678 let mut lexer = Lexer::new(input);
679 let current_token = lexer.next_token()?;
680 Ok(Parser {
681 lexer,
682 current_token,
683 })
684 }
685
686 fn advance(&mut self) -> Result<(), ParserError> {
687 self.current_token = self.lexer.next_token()?;
688 Ok(())
689 }
690
691 fn expect(&mut self, expected: Token) -> Result<(), ParserError> {
692 if std::mem::discriminant(&self.current_token) == std::mem::discriminant(&expected) {
693 self.advance()?;
694 Ok(())
695 } else {
696 Err(ParserError::Expected {
697 expected: format!("{:?}", expected),
698 found: format!("{:?}", self.current_token),
699 })
700 }
701 }
702
703 fn binding_power(&self, token: &Token) -> Option<(u8, u8)> {
705 match token {
708 Token::Identifier(name) if name == "or" => Some((25, 26)),
710 Token::Identifier(name) if name == "and" => Some((30, 31)),
711 Token::Identifier(name) if name == "in" => Some((40, 41)),
712 Token::Or => Some((25, 26)),
714 Token::And => Some((30, 31)),
715 Token::Equal
716 | Token::NotEqual
717 | Token::LessThan
718 | Token::LessThanOrEqual
719 | Token::GreaterThan
720 | Token::GreaterThanOrEqual
721 | Token::In => Some((40, 41)),
722 Token::Ampersand => Some((50, 51)),
723 Token::Plus | Token::Minus => Some((50, 51)),
724 Token::Star | Token::Slash | Token::Percent => Some((60, 61)),
725 Token::Dot => Some((75, 85)), Token::LeftBracket => Some((80, 81)),
727 Token::LeftParen => Some((80, 81)),
728 Token::LeftBrace => Some((80, 81)), Token::Caret => Some((80, 81)), Token::Hash => Some((80, 81)), Token::At => Some((80, 81)), Token::Question => Some((20, 21)),
733 Token::QuestionQuestion => Some((15, 16)), Token::QuestionColon => Some((15, 16)), Token::DotDot => Some((20, 21)),
736 Token::ColonEqual => Some((10, 9)), Token::TildeArrow => Some((70, 71)), _ => None,
739 }
740 }
741
742 fn parse_signature(&mut self) -> Result<String, ParserError> {
744 if self.current_token != Token::LessThan {
746 return Err(ParserError::Expected {
747 expected: "<".to_string(),
748 found: format!("{:?}", self.current_token),
749 });
750 }
751
752 let mut signature = String::from("<");
754 self.advance()?; let mut depth = 1;
759
760 while depth > 0 && self.current_token != Token::Eof {
761 match &self.current_token {
762 Token::LessThan => {
763 signature.push('<');
764 depth += 1;
765 self.advance()?;
766 }
767 Token::GreaterThan => {
768 depth -= 1;
769 if depth > 0 {
770 signature.push('>');
771 }
772 self.advance()?;
773 }
774 Token::Minus => {
775 signature.push('-');
776 self.advance()?;
777 }
778 Token::Plus => {
779 signature.push('+');
780 self.advance()?;
781 }
782 Token::Colon => {
783 signature.push(':');
784 self.advance()?;
785 }
786 Token::Question => {
787 signature.push('?');
788 self.advance()?;
789 }
790 Token::QuestionColon => {
791 signature.push('?');
793 signature.push(':');
794 self.advance()?;
795 }
796 Token::Identifier(s) => {
797 signature.push_str(s);
798 self.advance()?;
799 }
800 Token::LeftParen | Token::RightParen => {
801 let c = if self.current_token == Token::LeftParen {
803 '('
804 } else {
805 ')'
806 };
807 signature.push(c);
808 self.advance()?;
809 }
810 _ => {
811 return Err(ParserError::UnexpectedToken(format!(
812 "Unexpected token in signature: {:?}",
813 self.current_token
814 )));
815 }
816 }
817 }
818
819 signature.push('>');
820 Ok(signature)
821 }
822
823 fn parse_primary(&mut self) -> Result<AstNode, ParserError> {
825 match &self.current_token {
826 Token::String(s) => {
827 let value = s.clone();
828 self.advance()?;
829 Ok(AstNode::String(value))
830 }
831 Token::Number(n) => {
832 let value = *n;
833 self.advance()?;
834 Ok(AstNode::Number(value))
835 }
836 Token::True => {
837 self.advance()?;
838 Ok(AstNode::Boolean(true))
839 }
840 Token::False => {
841 self.advance()?;
842 Ok(AstNode::Boolean(false))
843 }
844 Token::Null => {
845 self.advance()?;
846 Ok(AstNode::Null)
847 }
848 Token::Undefined => {
849 self.advance()?;
850 Ok(AstNode::Undefined)
851 }
852 Token::Regex { pattern, flags } => {
853 let pat = pattern.clone();
854 let flg = flags.clone();
855 self.advance()?;
856 Ok(AstNode::Regex {
857 pattern: pat,
858 flags: flg,
859 })
860 }
861 Token::Identifier(name) => {
862 let name = name.clone();
863 self.advance()?;
864 Ok(AstNode::Path {
865 steps: vec![PathStep::new(AstNode::Name(name))],
866 })
867 }
868 Token::Variable(name) => {
869 let name = name.clone();
870 self.advance()?;
871 Ok(AstNode::Variable(name))
872 }
873 Token::ParentVariable(name) => {
874 let name = name.clone();
875 self.advance()?;
876 Ok(AstNode::ParentVariable(name))
877 }
878 Token::LeftParen => {
879 self.advance()?; if self.current_token == Token::RightParen {
883 self.advance()?;
884 return Ok(AstNode::Undefined);
885 }
886
887 let mut expressions = vec![self.parse_expression(0)?];
891
892 while self.current_token == Token::Semicolon {
893 self.advance()?;
894 if self.current_token == Token::RightParen {
895 break;
896 }
897 expressions.push(self.parse_expression(0)?);
898 }
899
900 self.expect(Token::RightParen)?;
901
902 Ok(AstNode::Block(expressions))
904 }
905 Token::LeftBracket => {
906 self.advance()?; let mut elements = Vec::new();
909
910 if self.current_token != Token::RightBracket {
911 loop {
912 let element = self.parse_expression(0)?;
913 elements.push(element);
914
915 if self.current_token != Token::Comma {
916 break;
917 }
918 self.advance()?;
919 }
920 }
921
922 self.expect(Token::RightBracket)?;
923 Ok(AstNode::Array(elements))
924 }
925 Token::LeftBrace => {
926 self.advance()?; let mut pairs = Vec::new();
929
930 if self.current_token != Token::RightBrace {
931 loop {
932 let key = self.parse_expression(0)?;
933 self.expect(Token::Colon)?;
934 let value = self.parse_expression(0)?;
935 pairs.push((key, value));
936
937 if self.current_token != Token::Comma {
938 break;
939 }
940 self.advance()?;
941 }
942 }
943
944 self.expect(Token::RightBrace)?;
945 Ok(AstNode::Object(pairs))
946 }
947 Token::Pipe => {
948 self.advance()?; let location = self.parse_expression(0)?;
953
954 self.expect(Token::Pipe)?;
956
957 let update = self.parse_expression(0)?;
959
960 let delete = if self.current_token == Token::Comma {
962 self.advance()?; Some(Box::new(self.parse_expression(0)?))
964 } else {
965 None
966 };
967
968 self.expect(Token::Pipe)?;
970
971 Ok(AstNode::Transform {
972 location: Box::new(location),
973 update: Box::new(update),
974 delete,
975 })
976 }
977 Token::Minus => {
978 self.advance()?;
979 let operand = self.parse_expression(70)?; Ok(AstNode::Unary {
981 op: UnaryOp::Negate,
982 operand: Box::new(operand),
983 })
984 }
985 Token::Star => {
986 self.advance()?;
988 Ok(AstNode::Wildcard)
989 }
990 Token::StarStar => {
991 self.advance()?;
993 Ok(AstNode::Descendant)
994 }
995 Token::Percent => {
996 self.advance()?;
1001 Ok(AstNode::Parent(String::new()))
1002 }
1003 Token::Function => {
1004 self.advance()?; self.expect(Token::LeftParen)?;
1007
1008 let mut params = Vec::new();
1010 if self.current_token != Token::RightParen {
1011 loop {
1012 match &self.current_token {
1013 Token::Variable(name) => {
1014 params.push(name.clone());
1015 self.advance()?;
1016 }
1017 _ => {
1018 return Err(ParserError::Expected {
1019 expected: "parameter name".to_string(),
1020 found: format!("{:?}", self.current_token),
1021 })
1022 }
1023 }
1024
1025 if self.current_token != Token::Comma {
1026 break;
1027 }
1028 self.advance()?; }
1030 }
1031
1032 self.expect(Token::RightParen)?;
1033
1034 let signature = if self.current_token == Token::LessThan {
1036 Some(self.parse_signature()?)
1037 } else {
1038 None
1039 };
1040
1041 self.expect(Token::LeftBrace)?;
1042
1043 let body = self.parse_expression(0)?;
1045
1046 self.expect(Token::RightBrace)?;
1047
1048 let (optimized_body, is_thunk) = Self::tail_call_optimize(body);
1050
1051 Ok(AstNode::Lambda {
1052 params,
1053 body: Box::new(optimized_body),
1054 signature,
1055 thunk: is_thunk,
1056 })
1057 }
1058 _ => Err(ParserError::UnexpectedToken(format!(
1059 "{:?}",
1060 self.current_token
1061 ))),
1062 }
1063 }
1064
1065 fn parse_expression(&mut self, min_bp: u8) -> Result<AstNode, ParserError> {
1067 let mut lhs = self.parse_primary()?;
1068
1069 loop {
1070 if matches!(
1072 self.current_token,
1073 Token::Eof
1074 | Token::RightParen
1075 | Token::RightBracket
1076 | Token::RightBrace
1077 | Token::Comma
1078 | Token::Semicolon
1079 | Token::Colon
1080 ) {
1081 break;
1082 }
1083
1084 let (left_bp, right_bp) = match self.binding_power(&self.current_token) {
1086 Some(bp) => bp,
1087 None => break,
1088 };
1089
1090 if left_bp < min_bp {
1091 break;
1092 }
1093
1094 match &self.current_token {
1096 Token::Dot => {
1097 self.advance()?;
1098
1099 if self.current_token == Token::LeftBracket {
1101 self.advance()?;
1102
1103 let mut elements = Vec::new();
1105 if self.current_token != Token::RightBracket {
1106 loop {
1107 elements.push(self.parse_expression(0)?);
1108 if self.current_token != Token::Comma {
1109 break;
1110 }
1111 self.advance()?;
1112 }
1113 }
1114
1115 self.expect(Token::RightBracket)?;
1116
1117 let mut steps = match lhs {
1119 AstNode::Path { steps } => steps,
1120 _ => vec![PathStep::new(lhs)],
1121 };
1122
1123 steps.push(PathStep::new(AstNode::ArrayGroup(elements)));
1124 lhs = AstNode::Path { steps };
1125 } else if self.current_token == Token::LeftParen {
1126 self.advance()?;
1128
1129 if self.current_token == Token::RightParen {
1135 self.advance()?;
1136 let mut steps = match lhs {
1137 AstNode::Path { steps } => steps,
1138 _ => vec![PathStep::new(lhs)],
1139 };
1140 steps.push(PathStep::new(AstNode::FunctionApplication(Box::new(
1141 AstNode::Block(Vec::new()),
1142 ))));
1143 lhs = AstNode::Path { steps };
1144 continue;
1145 }
1146
1147 let mut expressions = vec![self.parse_expression(0)?];
1149
1150 while self.current_token == Token::Semicolon {
1151 self.advance()?;
1152 if self.current_token == Token::RightParen {
1153 break;
1154 }
1155 expressions.push(self.parse_expression(0)?);
1156 }
1157
1158 self.expect(Token::RightParen)?;
1159
1160 let expr = if expressions.len() == 1 {
1162 expressions.into_iter().next().unwrap()
1163 } else {
1164 AstNode::Block(expressions)
1165 };
1166
1167 let mut steps = match lhs {
1169 AstNode::Path { steps } => steps,
1170 _ => vec![PathStep::new(lhs)],
1171 };
1172
1173 steps.push(PathStep::new(AstNode::FunctionApplication(Box::new(expr))));
1174 lhs = AstNode::Path { steps };
1175 } else {
1176 let rhs = self.parse_expression(right_bp)?;
1178
1179 let mut steps = match lhs {
1181 AstNode::Path { steps } => steps,
1182 AstNode::String(field_name) => {
1185 vec![PathStep::new(AstNode::Name(field_name))]
1186 }
1187 _ => vec![PathStep::new(lhs)],
1188 };
1189
1190 match &rhs {
1193 AstNode::Number(n) => {
1194 return Err(ParserError::InvalidSyntax(
1195 format!("S0213: The literal value {} cannot be used as a step within a path expression", n),
1196 ));
1197 }
1198 AstNode::Boolean(b) => {
1199 return Err(ParserError::InvalidSyntax(
1200 format!("S0213: The literal value {} cannot be used as a step within a path expression", b),
1201 ));
1202 }
1203 AstNode::Null => {
1204 return Err(ParserError::InvalidSyntax(
1205 "S0213: The literal value null cannot be used as a step within a path expression".to_string(),
1206 ));
1207 }
1208 _ => {}
1209 }
1210
1211 match rhs {
1212 AstNode::Path {
1213 steps: mut rhs_steps,
1214 } => {
1215 steps.append(&mut rhs_steps);
1216 }
1217 AstNode::String(field_name) => {
1220 steps.push(PathStep::new(AstNode::Name(field_name)));
1221 }
1222 _ => steps.push(PathStep::new(rhs)),
1223 }
1224
1225 while self.current_token == Token::LeftBracket {
1228 self.advance()?;
1229
1230 let predicate_expr = if self.current_token == Token::RightBracket {
1231 Box::new(AstNode::Boolean(true))
1233 } else {
1234 let pred = self.parse_expression(0)?;
1236 Box::new(pred)
1237 };
1238
1239 self.expect(Token::RightBracket)?;
1240
1241 if let Some(last_step) = steps.last_mut() {
1243 last_step.stages.push(Stage::Filter(predicate_expr));
1244 }
1245 }
1246
1247 lhs = AstNode::Path { steps };
1248 }
1249 }
1250 Token::LeftBracket => {
1251 if matches!(lhs, AstNode::ObjectTransform { .. }) {
1254 return Err(ParserError::InvalidSyntax(
1255 "S0209: A predicate cannot follow a grouping expression in a step"
1256 .to_string(),
1257 ));
1258 }
1259
1260 self.advance()?;
1261
1262 if self.current_token == Token::RightBracket {
1265 self.advance()?;
1267
1268 let mut steps = match lhs {
1269 AstNode::Path { steps } => steps,
1270 _ => vec![PathStep::new(lhs)],
1271 };
1272
1273 steps.push(PathStep::new(AstNode::Predicate(Box::new(
1274 AstNode::Boolean(true),
1275 ))));
1276 lhs = AstNode::Path { steps };
1277 } else {
1278 let predicate = self.parse_expression(0)?;
1280 self.expect(Token::RightBracket)?;
1281
1282 let mut steps = match lhs {
1283 AstNode::Path { steps } => steps,
1284 _ => vec![PathStep::new(lhs)],
1285 };
1286
1287 steps.push(PathStep::new(AstNode::Predicate(Box::new(predicate))));
1288 lhs = AstNode::Path { steps };
1289 }
1290 }
1291 Token::LeftParen => {
1292 self.advance()?;
1293
1294 let mut args = Vec::new();
1295
1296 if self.current_token != Token::RightParen {
1297 loop {
1298 if self.current_token == Token::Question {
1300 args.push(AstNode::Placeholder);
1301 self.advance()?;
1302 } else {
1303 args.push(self.parse_expression(0)?);
1304 }
1305
1306 if self.current_token != Token::Comma {
1307 break;
1308 }
1309 self.advance()?;
1310 }
1311 }
1312
1313 self.expect(Token::RightParen)?;
1314
1315 match lhs {
1317 AstNode::Lambda { .. }
1319 | AstNode::Block(_)
1320 | AstNode::Call { .. }
1321 | AstNode::Function { .. } => {
1322 lhs = AstNode::Call {
1323 procedure: Box::new(lhs),
1324 args,
1325 };
1326 }
1327 ref other_lhs => {
1328 match other_lhs {
1330 AstNode::Path { steps } if steps.len() == 1 => {
1332 let name = match &steps[0].node {
1333 AstNode::Name(s) => s.clone(),
1334 _ => {
1335 return Err(ParserError::InvalidSyntax(
1336 "Invalid function name".to_string(),
1337 ))
1338 }
1339 };
1340 lhs = AstNode::Function {
1341 name,
1342 args,
1343 is_builtin: false,
1344 };
1345 }
1346 AstNode::Path { steps } if steps.len() > 1 => {
1348 let last_step = &steps[steps.len() - 1].node;
1349
1350 if let AstNode::Variable(func_name) = last_step {
1352 let mut context_steps = steps.clone();
1354 context_steps.pop();
1355
1356 let func_call = AstNode::Function {
1358 name: func_name.clone(),
1359 args: args.clone(),
1360 is_builtin: true, };
1362
1363 context_steps.push(PathStep::new(
1365 AstNode::FunctionApplication(Box::new(func_call)),
1366 ));
1367
1368 lhs = AstNode::Path {
1369 steps: context_steps,
1370 };
1371 }
1372 else if let AstNode::Lambda {
1374 params,
1375 body,
1376 signature,
1377 thunk,
1378 } = last_step
1379 {
1380 let mut context_steps = steps.clone();
1382 context_steps.pop();
1383
1384 let full_args = if args.len() < params.len() {
1388 let mut new_args =
1389 vec![AstNode::Variable("$".to_string())];
1390 new_args.extend(args.clone());
1391 new_args
1392 } else {
1393 args.clone()
1394 };
1395
1396 let lambda_invocation = AstNode::Block(vec![
1399 AstNode::Binary {
1400 op: crate::ast::BinaryOp::ColonEqual,
1401 lhs: Box::new(AstNode::Variable(
1402 "__path_lambda__".to_string(),
1403 )),
1404 rhs: Box::new(AstNode::Lambda {
1405 params: params.clone(),
1406 body: body.clone(),
1407 signature: signature.clone(),
1408 thunk: *thunk,
1409 }),
1410 },
1411 AstNode::Function {
1412 name: "__path_lambda__".to_string(),
1413 args: full_args,
1414 is_builtin: true,
1415 },
1416 ]);
1417
1418 context_steps.push(PathStep::new(
1420 AstNode::FunctionApplication(Box::new(
1421 lambda_invocation,
1422 )),
1423 ));
1424
1425 lhs = AstNode::Path {
1426 steps: context_steps,
1427 };
1428 } else {
1429 return Err(ParserError::InvalidSyntax(
1430 "Invalid function call".to_string(),
1431 ));
1432 }
1433 }
1434 AstNode::Variable(name) => {
1436 lhs = AstNode::Function {
1437 name: name.clone(),
1438 args,
1439 is_builtin: true,
1440 };
1441 }
1442 _ => {
1443 return Err(ParserError::InvalidSyntax(
1444 "Invalid function call".to_string(),
1445 ))
1446 }
1447 };
1448 }
1449 }
1450 }
1451 Token::Question => {
1452 self.advance()?;
1453 let then_branch = self.parse_expression(0)?;
1454
1455 let else_branch = if self.current_token == Token::Colon {
1456 self.advance()?;
1457 Some(Box::new(self.parse_expression(0)?))
1459 } else {
1460 None
1461 };
1462
1463 lhs = AstNode::Conditional {
1464 condition: Box::new(lhs),
1465 then_branch: Box::new(then_branch),
1466 else_branch,
1467 };
1468 }
1469 Token::LeftBrace => {
1470 if matches!(lhs, AstNode::ObjectTransform { .. }) {
1473 return Err(ParserError::InvalidSyntax(
1474 "S0210: Each step can only have one grouping expression".to_string(),
1475 ));
1476 }
1477
1478 self.advance()?; let mut pairs = Vec::new();
1482
1483 if self.current_token != Token::RightBrace {
1484 loop {
1485 let key = self.parse_expression(0)?;
1487
1488 self.expect(Token::Colon)?;
1489
1490 let value = self.parse_expression(0)?;
1492
1493 pairs.push((key, value));
1494
1495 if self.current_token != Token::Comma {
1496 break;
1497 }
1498 self.advance()?; }
1500 }
1501
1502 self.expect(Token::RightBrace)?;
1503
1504 lhs = AstNode::ObjectTransform {
1506 input: Box::new(lhs),
1507 pattern: pairs,
1508 };
1509 }
1510 Token::Hash => {
1511 self.advance()?; let var_name = match &self.current_token {
1519 Token::Variable(name) => name.clone(),
1520 _ => {
1521 return Err(ParserError::Coded {
1522 code: "S0214",
1523 message: "Expected a variable reference after #".to_string(),
1524 });
1525 }
1526 };
1527 self.advance()?; lhs = AstNode::Binary {
1536 op: BinaryOp::IndexBind,
1537 lhs: Box::new(lhs),
1538 rhs: Box::new(AstNode::Variable(var_name)),
1539 };
1540 }
1541 Token::At => {
1542 self.advance()?; let var_name = match &self.current_token {
1550 Token::Variable(name) => name.clone(),
1551 _ => {
1552 return Err(ParserError::Coded {
1553 code: "S0214",
1554 message: "Expected a variable reference after @".to_string(),
1555 });
1556 }
1557 };
1558 self.advance()?; lhs = AstNode::Binary {
1561 op: BinaryOp::FocusBind,
1562 lhs: Box::new(lhs),
1563 rhs: Box::new(AstNode::Variable(var_name)),
1564 };
1565 }
1566 Token::Caret => {
1567 self.advance()?; self.expect(Token::LeftParen)?;
1570
1571 let mut terms = Vec::new();
1572
1573 loop {
1574 let ascending = match &self.current_token {
1576 Token::LessThan => {
1577 self.advance()?;
1578 true
1579 }
1580 Token::GreaterThan => {
1581 self.advance()?;
1582 false
1583 }
1584 _ => true, };
1586
1587 let expr = self.parse_expression(0)?;
1589 terms.push((expr, ascending));
1590
1591 if self.current_token != Token::Comma {
1593 break;
1594 }
1595 self.advance()?; }
1597
1598 self.expect(Token::RightParen)?;
1599
1600 lhs = AstNode::Sort {
1601 input: Box::new(lhs),
1602 terms,
1603 };
1604 }
1605 _ => {
1606 let op = match &self.current_token {
1608 Token::Identifier(name) if name == "and" => BinaryOp::And,
1610 Token::Identifier(name) if name == "or" => BinaryOp::Or,
1611 Token::Identifier(name) if name == "in" => BinaryOp::In,
1612 Token::Plus => BinaryOp::Add,
1614 Token::Minus => BinaryOp::Subtract,
1615 Token::Star => BinaryOp::Multiply,
1616 Token::Slash => BinaryOp::Divide,
1617 Token::Percent => BinaryOp::Modulo,
1618 Token::Equal => BinaryOp::Equal,
1619 Token::NotEqual => BinaryOp::NotEqual,
1620 Token::LessThan => BinaryOp::LessThan,
1621 Token::LessThanOrEqual => BinaryOp::LessThanOrEqual,
1622 Token::GreaterThan => BinaryOp::GreaterThan,
1623 Token::GreaterThanOrEqual => BinaryOp::GreaterThanOrEqual,
1624 Token::And => BinaryOp::And,
1625 Token::Or => BinaryOp::Or,
1626 Token::In => BinaryOp::In,
1627 Token::Ampersand => BinaryOp::Concatenate,
1628 Token::DotDot => BinaryOp::Range,
1629 Token::ColonEqual => BinaryOp::ColonEqual,
1630 Token::QuestionQuestion => BinaryOp::Coalesce,
1631 Token::QuestionColon => BinaryOp::Default,
1632 Token::TildeArrow => BinaryOp::ChainPipe,
1633 _ => {
1634 return Err(ParserError::UnexpectedToken(format!(
1635 "{:?}",
1636 self.current_token
1637 )))
1638 }
1639 };
1640
1641 self.advance()?;
1642 let rhs = self.parse_expression(right_bp)?;
1643
1644 lhs = AstNode::Binary {
1645 op,
1646 lhs: Box::new(lhs),
1647 rhs: Box::new(rhs),
1648 };
1649 }
1650 }
1651 }
1652
1653 Ok(lhs)
1654 }
1655
1656 pub fn parse(&mut self) -> Result<AstNode, ParserError> {
1657 let ast = self.parse_expression(0)?;
1658
1659 if self.current_token != Token::Eof {
1660 return Err(ParserError::Expected {
1661 expected: "end of expression".to_string(),
1662 found: format!("{:?}", self.current_token),
1663 });
1664 }
1665
1666 Ok(ast)
1667 }
1668
1669 fn tail_call_optimize(expr: AstNode) -> (AstNode, bool) {
1679 let is_thunk = Self::is_tail_call(&expr);
1680 (expr, is_thunk)
1681 }
1682
1683 fn is_tail_call(expr: &AstNode) -> bool {
1686 match expr {
1687 AstNode::Function { .. } => true,
1689 AstNode::Call { .. } => true,
1690
1691 AstNode::Conditional {
1693 then_branch,
1694 else_branch,
1695 ..
1696 } => {
1697 let then_is_tail = Self::is_tail_call(then_branch);
1698 let else_is_tail = else_branch.as_ref().is_some_and(|e| Self::is_tail_call(e));
1699 then_is_tail || else_is_tail
1701 }
1702
1703 AstNode::Block(exprs) => exprs.last().is_some_and(Self::is_tail_call),
1705
1706 AstNode::Binary {
1708 op: BinaryOp::ColonEqual,
1709 rhs,
1710 ..
1711 } => {
1712 Self::is_tail_call(rhs)
1716 }
1717
1718 _ => false,
1720 }
1721 }
1722}
1723
1724pub fn parse(expression: &str) -> Result<AstNode, ParserError> {
1731 let mut parser = Parser::new(expression.to_string())?;
1732 let raw_ast = parser.parse()?;
1733 crate::ast_transform::resolve_ancestry(raw_ast).map_err(|e| match e {
1734 crate::ast_transform::AstTransformError::Coded { code, message } => {
1735 ParserError::Coded { code, message }
1736 }
1737 })
1738}
1739
1740#[cfg(test)]
1741mod tests {
1742 use super::*;
1743
1744 #[test]
1746 fn test_lexer_numbers() {
1747 let mut lexer = Lexer::new("42 3.14 -10 2.5e10 1E-5".to_string());
1748
1749 assert_eq!(lexer.next_token().unwrap(), Token::Number(42.0));
1750 assert_eq!(lexer.next_token().unwrap(), Token::Number(3.14));
1751 assert_eq!(lexer.next_token().unwrap(), Token::Minus);
1753 assert_eq!(lexer.next_token().unwrap(), Token::Number(10.0));
1754 assert_eq!(lexer.next_token().unwrap(), Token::Number(2.5e10));
1755 assert_eq!(lexer.next_token().unwrap(), Token::Number(1e-5));
1756 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1757 }
1758
1759 #[test]
1760 fn test_lexer_strings() {
1761 let mut lexer = Lexer::new(r#""hello" 'world' "with\nnewline""#.to_string());
1762
1763 assert_eq!(
1764 lexer.next_token().unwrap(),
1765 Token::String("hello".to_string())
1766 );
1767 assert_eq!(
1768 lexer.next_token().unwrap(),
1769 Token::String("world".to_string())
1770 );
1771 assert_eq!(
1772 lexer.next_token().unwrap(),
1773 Token::String("with\nnewline".to_string())
1774 );
1775 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1776 }
1777
1778 #[test]
1779 fn test_lexer_string_escapes() {
1780 let mut lexer = Lexer::new(r#""a\"b\\c\/d""#.to_string());
1781 assert_eq!(
1782 lexer.next_token().unwrap(),
1783 Token::String("a\"b\\c/d".to_string())
1784 );
1785 }
1786
1787 #[test]
1788 fn test_lexer_keywords() {
1789 let mut lexer = Lexer::new("true false null and or in".to_string());
1790
1791 assert_eq!(lexer.next_token().unwrap(), Token::True);
1792 assert_eq!(lexer.next_token().unwrap(), Token::False);
1793 assert_eq!(lexer.next_token().unwrap(), Token::Null);
1794 assert_eq!(
1796 lexer.next_token().unwrap(),
1797 Token::Identifier("and".to_string())
1798 );
1799 assert_eq!(
1800 lexer.next_token().unwrap(),
1801 Token::Identifier("or".to_string())
1802 );
1803 assert_eq!(
1804 lexer.next_token().unwrap(),
1805 Token::Identifier("in".to_string())
1806 );
1807 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1808 }
1809
1810 #[test]
1811 fn test_lexer_identifiers() {
1812 let mut lexer = Lexer::new("foo bar_baz test123".to_string());
1813
1814 assert_eq!(
1815 lexer.next_token().unwrap(),
1816 Token::Identifier("foo".to_string())
1817 );
1818 assert_eq!(
1819 lexer.next_token().unwrap(),
1820 Token::Identifier("bar_baz".to_string())
1821 );
1822 assert_eq!(
1823 lexer.next_token().unwrap(),
1824 Token::Identifier("test123".to_string())
1825 );
1826 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1827 }
1828
1829 #[test]
1830 fn test_lexer_variables() {
1831 let mut lexer = Lexer::new("$var $foo_bar".to_string());
1832
1833 assert_eq!(
1834 lexer.next_token().unwrap(),
1835 Token::Variable("var".to_string())
1836 );
1837 assert_eq!(
1838 lexer.next_token().unwrap(),
1839 Token::Variable("foo_bar".to_string())
1840 );
1841 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1842 }
1843
1844 #[test]
1845 fn test_lexer_operators() {
1846 let mut lexer = Lexer::new("+ - * % = != < <= > >= & . .. := ".to_string());
1848
1849 assert_eq!(lexer.next_token().unwrap(), Token::Plus);
1850 assert_eq!(lexer.next_token().unwrap(), Token::Minus);
1851 assert_eq!(lexer.next_token().unwrap(), Token::Star);
1852 assert_eq!(lexer.next_token().unwrap(), Token::Percent);
1853 assert_eq!(lexer.next_token().unwrap(), Token::Equal);
1854 assert_eq!(lexer.next_token().unwrap(), Token::NotEqual);
1855 assert_eq!(lexer.next_token().unwrap(), Token::LessThan);
1856 assert_eq!(lexer.next_token().unwrap(), Token::LessThanOrEqual);
1857 assert_eq!(lexer.next_token().unwrap(), Token::GreaterThan);
1858 assert_eq!(lexer.next_token().unwrap(), Token::GreaterThanOrEqual);
1859 assert_eq!(lexer.next_token().unwrap(), Token::Ampersand);
1860 assert_eq!(lexer.next_token().unwrap(), Token::Dot);
1861 assert_eq!(lexer.next_token().unwrap(), Token::DotDot);
1862 assert_eq!(lexer.next_token().unwrap(), Token::ColonEqual);
1863 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1864
1865 let mut lexer2 = Lexer::new("42 / 2".to_string());
1868 assert_eq!(lexer2.next_token().unwrap(), Token::Number(42.0));
1869 assert_eq!(lexer2.next_token().unwrap(), Token::Slash);
1870 assert_eq!(lexer2.next_token().unwrap(), Token::Number(2.0));
1871 assert_eq!(lexer2.next_token().unwrap(), Token::Eof);
1872 }
1873
1874 #[test]
1875 fn test_lexer_delimiters() {
1876 let mut lexer = Lexer::new("()[]{},:;?".to_string());
1877
1878 assert_eq!(lexer.next_token().unwrap(), Token::LeftParen);
1879 assert_eq!(lexer.next_token().unwrap(), Token::RightParen);
1880 assert_eq!(lexer.next_token().unwrap(), Token::LeftBracket);
1881 assert_eq!(lexer.next_token().unwrap(), Token::RightBracket);
1882 assert_eq!(lexer.next_token().unwrap(), Token::LeftBrace);
1883 assert_eq!(lexer.next_token().unwrap(), Token::RightBrace);
1884 assert_eq!(lexer.next_token().unwrap(), Token::Comma);
1885 assert_eq!(lexer.next_token().unwrap(), Token::Colon);
1886 assert_eq!(lexer.next_token().unwrap(), Token::Semicolon);
1887 assert_eq!(lexer.next_token().unwrap(), Token::Question);
1888 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1889 }
1890
1891 #[test]
1892 fn test_empty_brackets() {
1893 let mut parser = Parser::new("foo[]".to_string()).unwrap();
1894 let ast = parser.parse().unwrap();
1895
1896 if let AstNode::Path { steps } = ast {
1898 assert_eq!(steps.len(), 2);
1899 assert!(matches!(steps[0].node, AstNode::Name(ref s) if s == "foo"));
1900 if let AstNode::Predicate(pred) = &steps[1].node {
1901 assert!(matches!(**pred, AstNode::Boolean(true)));
1902 } else {
1903 panic!("Expected Predicate as second step, got {:?}", steps[1].node);
1904 }
1905 } else {
1906 panic!("Expected Path, got {:?}", ast);
1907 }
1908 }
1909
1910 #[test]
1911 fn test_lexer_comments() {
1912 let mut lexer = Lexer::new("foo /* comment */ bar".to_string());
1913
1914 assert_eq!(
1915 lexer.next_token().unwrap(),
1916 Token::Identifier("foo".to_string())
1917 );
1918 assert_eq!(
1919 lexer.next_token().unwrap(),
1920 Token::Identifier("bar".to_string())
1921 );
1922 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1923 }
1924
1925 #[test]
1926 fn test_lexer_backtick_names() {
1927 let mut lexer = Lexer::new("`field name` `with-dash`".to_string());
1928
1929 assert_eq!(
1930 lexer.next_token().unwrap(),
1931 Token::Identifier("field name".to_string())
1932 );
1933 assert_eq!(
1934 lexer.next_token().unwrap(),
1935 Token::Identifier("with-dash".to_string())
1936 );
1937 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1938 }
1939
1940 #[test]
1942 fn test_parse_number() {
1943 let ast = parse("42").unwrap();
1944 assert_eq!(ast, AstNode::Number(42.0));
1945 }
1946
1947 #[test]
1948 fn test_parse_string() {
1949 let ast = parse(r#""hello""#).unwrap();
1950 assert_eq!(ast, AstNode::String("hello".to_string()));
1951 }
1952
1953 #[test]
1954 fn test_parse_boolean() {
1955 let ast = parse("true").unwrap();
1956 assert_eq!(ast, AstNode::Boolean(true));
1957
1958 let ast = parse("false").unwrap();
1959 assert_eq!(ast, AstNode::Boolean(false));
1960 }
1961
1962 #[test]
1963 fn test_parse_null() {
1964 let ast = parse("null").unwrap();
1965 assert_eq!(ast, AstNode::Null);
1966 }
1967
1968 #[test]
1969 fn test_parse_variable() {
1970 let ast = parse("$var").unwrap();
1971 assert_eq!(ast, AstNode::Variable("var".to_string()));
1972 }
1973
1974 #[test]
1975 fn test_parse_identifier() {
1976 let ast = parse("foo").unwrap();
1977 assert_eq!(
1978 ast,
1979 AstNode::Path {
1980 steps: vec![PathStep::new(AstNode::Name("foo".to_string()))]
1981 }
1982 );
1983 }
1984
1985 #[test]
1986 fn test_parse_addition() {
1987 let ast = parse("1 + 2").unwrap();
1988 match ast {
1989 AstNode::Binary { op, lhs, rhs } => {
1990 assert_eq!(op, BinaryOp::Add);
1991 assert_eq!(*lhs, AstNode::Number(1.0));
1992 assert_eq!(*rhs, AstNode::Number(2.0));
1993 }
1994 _ => panic!("Expected Binary node"),
1995 }
1996 }
1997
1998 #[test]
1999 fn test_parse_precedence() {
2000 let ast = parse("1 + 2 * 3").unwrap();
2002 match ast {
2003 AstNode::Binary {
2004 op: BinaryOp::Add,
2005 lhs,
2006 rhs,
2007 } => {
2008 assert_eq!(*lhs, AstNode::Number(1.0));
2009 match *rhs {
2010 AstNode::Binary {
2011 op: BinaryOp::Multiply,
2012 lhs,
2013 rhs,
2014 } => {
2015 assert_eq!(*lhs, AstNode::Number(2.0));
2016 assert_eq!(*rhs, AstNode::Number(3.0));
2017 }
2018 _ => panic!("Expected Binary node for multiplication"),
2019 }
2020 }
2021 _ => panic!("Expected Binary node for addition"),
2022 }
2023 }
2024
2025 #[test]
2026 fn test_parse_parentheses() {
2027 let ast = parse("(1 + 2) * 3").unwrap();
2030 match ast {
2031 AstNode::Binary {
2032 op: BinaryOp::Multiply,
2033 lhs,
2034 rhs,
2035 } => {
2036 match *lhs {
2037 AstNode::Block(ref exprs) => {
2038 assert_eq!(exprs.len(), 1);
2039 match &exprs[0] {
2040 AstNode::Binary {
2041 op: BinaryOp::Add,
2042 lhs,
2043 rhs,
2044 } => {
2045 assert_eq!(**lhs, AstNode::Number(1.0));
2046 assert_eq!(**rhs, AstNode::Number(2.0));
2047 }
2048 _ => panic!("Expected Binary node for addition inside block"),
2049 }
2050 }
2051 _ => panic!(
2052 "Expected Block node for parenthesized expression, got {:?}",
2053 lhs
2054 ),
2055 }
2056 assert_eq!(*rhs, AstNode::Number(3.0));
2057 }
2058 _ => panic!("Expected Binary node for multiplication"),
2059 }
2060 }
2061
2062 #[test]
2063 fn test_parse_array() {
2064 let ast = parse("[1, 2, 3]").unwrap();
2065 match ast {
2066 AstNode::Array(elements) => {
2067 assert_eq!(elements.len(), 3);
2068 assert_eq!(elements[0], AstNode::Number(1.0));
2069 assert_eq!(elements[1], AstNode::Number(2.0));
2070 assert_eq!(elements[2], AstNode::Number(3.0));
2071 }
2072 _ => panic!("Expected Array node"),
2073 }
2074 }
2075
2076 #[test]
2077 fn test_parse_object() {
2078 let ast = parse(r#"{"a": 1, "b": 2}"#).unwrap();
2079 match ast {
2080 AstNode::Object(pairs) => {
2081 assert_eq!(pairs.len(), 2);
2082 assert_eq!(pairs[0].0, AstNode::String("a".to_string()));
2083 assert_eq!(pairs[0].1, AstNode::Number(1.0));
2084 assert_eq!(pairs[1].0, AstNode::String("b".to_string()));
2085 assert_eq!(pairs[1].1, AstNode::Number(2.0));
2086 }
2087 _ => panic!("Expected Object node"),
2088 }
2089 }
2090
2091 #[test]
2092 fn test_parse_path() {
2093 let ast = parse("foo.bar").unwrap();
2094 match ast {
2095 AstNode::Path { steps } => {
2096 assert_eq!(steps.len(), 2);
2097 assert_eq!(steps[0].node, AstNode::Name("foo".to_string()));
2098 assert_eq!(steps[1].node, AstNode::Name("bar".to_string()));
2099 }
2100 _ => panic!("Expected Path node"),
2101 }
2102 }
2103
2104 #[test]
2105 fn test_parse_function_call() {
2106 let ast = parse("sum(1, 2, 3)").unwrap();
2107 match ast {
2108 AstNode::Function {
2109 name,
2110 args,
2111 is_builtin,
2112 } => {
2113 assert_eq!(name, "sum");
2114 assert_eq!(args.len(), 3);
2115 assert_eq!(args[0], AstNode::Number(1.0));
2116 assert_eq!(args[1], AstNode::Number(2.0));
2117 assert_eq!(args[2], AstNode::Number(3.0));
2118 assert!(!is_builtin); }
2120 _ => panic!("Expected Function node"),
2121 }
2122 }
2123
2124 #[test]
2125 fn test_parse_conditional() {
2126 let ast = parse("x > 0 ? 1 : -1").unwrap();
2127 match ast {
2128 AstNode::Conditional {
2129 condition,
2130 then_branch,
2131 else_branch,
2132 } => {
2133 assert!(matches!(*condition, AstNode::Binary { .. }));
2134 assert_eq!(*then_branch, AstNode::Number(1.0));
2135 assert_eq!(
2137 else_branch,
2138 Some(Box::new(AstNode::Unary {
2139 op: UnaryOp::Negate,
2140 operand: Box::new(AstNode::Number(1.0)),
2141 }))
2142 );
2143 }
2144 _ => panic!("Expected Conditional node"),
2145 }
2146 }
2147
2148 #[test]
2149 fn test_parse_comparison() {
2150 let ast = parse("x < 10").unwrap();
2151 match ast {
2152 AstNode::Binary { op, .. } => {
2153 assert_eq!(op, BinaryOp::LessThan);
2154 }
2155 _ => panic!("Expected Binary node"),
2156 }
2157 }
2158
2159 #[test]
2160 fn test_parse_logical_and() {
2161 let ast = parse("true and false").unwrap();
2162 match ast {
2163 AstNode::Binary { op, lhs, rhs } => {
2164 assert_eq!(op, BinaryOp::And);
2165 assert_eq!(*lhs, AstNode::Boolean(true));
2166 assert_eq!(*rhs, AstNode::Boolean(false));
2167 }
2168 _ => panic!("Expected Binary node"),
2169 }
2170 }
2171
2172 #[test]
2173 fn test_parse_string_concatenation() {
2174 let ast = parse(r#""hello" & " " & "world""#).unwrap();
2175 match ast {
2176 AstNode::Binary { op, .. } => {
2177 assert_eq!(op, BinaryOp::Concatenate);
2178 }
2179 _ => panic!("Expected Binary node"),
2180 }
2181 }
2182
2183 #[test]
2184 fn test_parse_unary_minus() {
2185 let ast = parse("-5").unwrap();
2187 assert_eq!(
2188 ast,
2189 AstNode::Unary {
2190 op: UnaryOp::Negate,
2191 operand: Box::new(AstNode::Number(5.0)),
2192 }
2193 );
2194 }
2195
2196 #[test]
2197 fn test_parse_block() {
2198 let ast = parse("(1; 2; 3)").unwrap();
2199 match ast {
2200 AstNode::Block(expressions) => {
2201 assert_eq!(expressions.len(), 3);
2202 assert_eq!(expressions[0], AstNode::Number(1.0));
2203 assert_eq!(expressions[1], AstNode::Number(2.0));
2204 assert_eq!(expressions[2], AstNode::Number(3.0));
2205 }
2206 _ => panic!("Expected Block node"),
2207 }
2208 }
2209
2210 #[test]
2211 fn test_parse_complex_expression() {
2212 let ast = parse("(a + b) * c.d").unwrap();
2214 assert!(matches!(ast, AstNode::Binary { .. }));
2215 }
2216
2217 #[test]
2218 fn test_parse_dollar_function_call() {
2219 let ast = parse(r#"$uppercase("hello")"#).unwrap();
2221 match ast {
2222 AstNode::Function {
2223 name,
2224 args,
2225 is_builtin,
2226 } => {
2227 assert_eq!(name, "uppercase");
2228 assert_eq!(args.len(), 1);
2229 assert_eq!(args[0], AstNode::String("hello".to_string()));
2230 assert!(is_builtin); }
2232 _ => panic!("Expected Function node"),
2233 }
2234
2235 let ast = parse("$sum([1, 2, 3])").unwrap();
2237 match ast {
2238 AstNode::Function {
2239 name,
2240 args,
2241 is_builtin,
2242 } => {
2243 assert_eq!(name, "sum");
2244 assert_eq!(args.len(), 1);
2245 assert!(is_builtin); }
2247 _ => panic!("Expected Function node"),
2248 }
2249 }
2250
2251 #[test]
2252 fn test_parse_nested_dollar_functions() {
2253 let ast = parse(r#"$length($lowercase("HELLO"))"#).unwrap();
2255 match ast {
2256 AstNode::Function {
2257 name,
2258 args,
2259 is_builtin,
2260 } => {
2261 assert_eq!(name, "length");
2262 assert_eq!(args.len(), 1);
2263 assert!(is_builtin);
2264 match &args[0] {
2266 AstNode::Function {
2267 name: inner_name,
2268 is_builtin: inner_builtin,
2269 ..
2270 } => {
2271 assert_eq!(inner_name, "lowercase");
2272 assert!(inner_builtin);
2273 }
2274 _ => panic!("Expected nested Function node"),
2275 }
2276 }
2277 _ => panic!("Expected Function node"),
2278 }
2279 }
2280
2281 #[test]
2282 fn test_signature_with_repeat_modifier_parses() {
2283 let result = parse("λ($arg1, $arg2)<n+n:o>{{\"a\": $arg1, \"b\": $arg2}}(1, 2, 3)");
2287 assert!(
2288 result.is_ok(),
2289 "expected parse to succeed, got {:?}",
2290 result
2291 );
2292 }
2293
2294 #[test]
2295 fn test_parent_operator_parses_as_prefix() {
2296 let mut parser = Parser::new("%.OrderID".to_string()).unwrap();
2304 let ast = parser.parse().unwrap();
2305 match ast {
2307 AstNode::Path { steps } => {
2308 assert_eq!(steps.len(), 2);
2309 assert!(matches!(steps[0].node, AstNode::Parent(_)));
2310 assert!(matches!(steps[1].node, AstNode::Name(ref n) if n == "OrderID"));
2311 }
2312 other => panic!("expected Path, got {:?}", other),
2313 }
2314 }
2315
2316 #[test]
2317 fn test_percent_still_parses_as_modulo_infix() {
2318 let ast = parse("10 % 3").unwrap();
2320 assert!(matches!(
2321 ast,
2322 AstNode::Binary {
2323 op: BinaryOp::Modulo,
2324 ..
2325 }
2326 ));
2327 }
2328
2329 #[test]
2330 fn test_focus_bind_parses_as_binary_marker() {
2331 let mut parser = Parser::new("Order@$o".to_string()).unwrap();
2336 let ast = parser.parse().unwrap();
2337 match ast {
2338 AstNode::Binary {
2339 op: BinaryOp::FocusBind,
2340 lhs,
2341 rhs,
2342 } => {
2343 if let AstNode::Path { steps } = *lhs {
2345 assert_eq!(steps.len(), 1);
2346 assert!(matches!(steps[0].node, AstNode::Name(ref n) if n == "Order"));
2347 } else {
2348 panic!("expected lhs to be Path, got {:?}", lhs);
2349 }
2350 assert!(matches!(*rhs, AstNode::Variable(ref n) if n == "o"));
2351 }
2352 other => panic!("expected Binary{{FocusBind}}, got {:?}", other),
2353 }
2354 }
2355
2356 #[test]
2357 fn test_index_bind_parses_as_binary_marker() {
2358 let mut parser = Parser::new("arr#$i".to_string()).unwrap();
2361 let ast = parser.parse().unwrap();
2362 match ast {
2363 AstNode::Binary {
2364 op: BinaryOp::IndexBind,
2365 lhs,
2366 rhs,
2367 } => {
2368 if let AstNode::Path { steps } = *lhs {
2369 assert_eq!(steps.len(), 1);
2370 assert!(matches!(steps[0].node, AstNode::Name(ref n) if n == "arr"));
2371 } else {
2372 panic!("expected lhs to be Path, got {:?}", lhs);
2373 }
2374 assert!(matches!(*rhs, AstNode::Variable(ref n) if n == "i"));
2375 }
2376 other => panic!("expected Binary{{IndexBind}}, got {:?}", other),
2377 }
2378 }
2379
2380 #[test]
2381 fn test_focus_bind_requires_variable_rhs() {
2382 let err = parse("Order@foo").unwrap_err();
2384 assert!(err.to_string().starts_with("S0214"));
2385 }
2386}