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
47impl ParserError {
48 pub fn display_message(&self) -> String {
54 let msg = self.to_string();
55 if matches!(self, ParserError::Coded { .. }) {
56 msg
57 } else {
58 format!("Parse error: {}", msg)
59 }
60 }
61}
62
63#[cfg(test)]
64mod parser_error_display_message_tests {
65 use super::ParserError;
66
67 #[test]
68 fn coded_error_passes_through_unchanged() {
69 let e = ParserError::Coded {
70 code: "S0214",
71 message: "The % operator is invalid outside a path".to_string(),
72 };
73 assert_eq!(
74 e.display_message(),
75 "S0214: The % operator is invalid outside a path"
76 );
77 }
78
79 #[test]
80 fn uncoded_error_gets_parse_error_prefix() {
81 let e = ParserError::UnexpectedToken("foo".to_string());
82 assert_eq!(e.display_message(), "Parse error: Unexpected token: foo");
83 }
84}
85
86#[derive(Debug, Clone, PartialEq)]
88pub enum Token {
89 String(String),
91 Number(f64),
92 True,
93 False,
94 Null,
95 Undefined, Regex { pattern: String, flags: String }, Identifier(String),
100 Variable(String),
101 ParentVariable(String), Function, Plus,
106 Minus,
107 Star,
108 StarStar, Slash,
110 Percent,
111 Equal,
112 NotEqual,
113 LessThan,
114 LessThanOrEqual,
115 GreaterThan,
116 GreaterThanOrEqual,
117 And,
118 Or,
119 In,
120 Ampersand,
121 Dot,
122 DotDot,
123 Question,
124 QuestionQuestion, QuestionColon, Colon,
127 ColonEqual, TildeArrow, LeftParen,
132 RightParen,
133 LeftBracket,
134 RightBracket,
135 LeftBrace,
136 RightBrace,
137 Comma,
138 Semicolon,
139 Caret, Pipe, Hash, At, Eof,
146}
147
148pub struct Lexer {
150 input: Vec<char>,
151 position: usize,
152 last_token: Option<Token>,
153}
154
155impl Lexer {
156 pub fn new(input: String) -> Self {
157 Lexer {
158 input: input.chars().collect(),
159 position: 0,
160 last_token: None,
161 }
162 }
163
164 fn current(&self) -> Option<char> {
165 self.input.get(self.position).copied()
166 }
167
168 fn peek(&self, offset: usize) -> Option<char> {
169 self.input.get(self.position + offset).copied()
170 }
171
172 fn advance(&mut self) {
173 if self.position < self.input.len() {
174 self.position += 1;
175 }
176 }
177
178 fn skip_whitespace(&mut self) {
179 while self.current().is_some_and(|ch| ch.is_whitespace()) {
180 self.advance();
181 }
182 }
183
184 fn skip_comment(&mut self) -> Result<(), ParserError> {
185 if self.peek(1) == Some('*') {
187 self.advance(); self.advance(); loop {
192 match self.current() {
193 None => return Err(ParserError::UnclosedComment),
194 Some('*') if self.peek(1) == Some('/') => {
195 self.advance(); self.advance(); break;
198 }
199 Some(_) => self.advance(),
200 }
201 }
202 }
203 Ok(())
204 }
205
206 fn read_string(&mut self, quote_char: char) -> Result<String, ParserError> {
207 let mut result = String::new();
208 self.advance(); loop {
211 match self.current() {
212 None => return Err(ParserError::UnclosedString),
213 Some(ch) if ch == quote_char => {
214 self.advance(); return Ok(result);
216 }
217 Some('\\') => {
218 self.advance();
219 match self.current() {
220 None => return Err(ParserError::UnclosedString),
221 Some('"') => result.push('"'),
222 Some('\\') => result.push('\\'),
223 Some('/') => result.push('/'),
224 Some('b') => result.push('\u{0008}'),
225 Some('f') => result.push('\u{000C}'),
226 Some('n') => result.push('\n'),
227 Some('r') => result.push('\r'),
228 Some('t') => result.push('\t'),
229 Some('u') => {
230 self.advance();
232 let mut hex = String::new();
233 for _ in 0..4 {
234 match self.current() {
235 Some(h) if h.is_ascii_hexdigit() => {
236 hex.push(h);
237 self.advance();
238 }
239 _ => {
240 return Err(ParserError::InvalidEscape(format!(
241 "\\u{}",
242 hex
243 )))
244 }
245 }
246 }
247 let code = u32::from_str_radix(&hex, 16).unwrap();
248 if (0xD800..=0xDBFF).contains(&code) {
249 if self.current() == Some('\\') {
251 self.advance();
252 if self.current() == Some('u') {
253 self.advance();
254 let mut low_hex = String::new();
255 for _ in 0..4 {
256 match self.current() {
257 Some(h) if h.is_ascii_hexdigit() => {
258 low_hex.push(h);
259 self.advance();
260 }
261 _ => {
262 return Err(ParserError::InvalidEscape(
263 format!("\\u{}", low_hex),
264 ))
265 }
266 }
267 }
268 let low = u32::from_str_radix(&low_hex, 16).unwrap();
269 if (0xDC00..=0xDFFF).contains(&low) {
270 let cp =
271 0x10000 + (code - 0xD800) * 0x400 + (low - 0xDC00);
272 if let Some(ch) = char::from_u32(cp) {
273 result.push(ch);
274 } else {
275 return Err(ParserError::InvalidEscape(format!(
276 "\\u{}\\u{}",
277 hex, low_hex
278 )));
279 }
280 } else {
281 return Err(ParserError::InvalidEscape(format!(
282 "\\u{}\\u{}",
283 hex, low_hex
284 )));
285 }
286 } else {
287 return Err(ParserError::InvalidEscape(format!(
288 "\\u{}",
289 hex
290 )));
291 }
292 } else {
293 return Err(ParserError::InvalidEscape(format!("\\u{}", hex)));
294 }
295 } else if let Some(ch) = char::from_u32(code) {
296 result.push(ch);
297 } else {
298 return Err(ParserError::InvalidEscape(format!("\\u{}", hex)));
299 }
300 continue; }
302 Some(ch) => return Err(ParserError::InvalidEscape(format!("\\{}", ch))),
303 }
304 self.advance();
305 }
306 Some(ch) => {
307 result.push(ch);
308 self.advance();
309 }
310 }
311 }
312 }
313
314 fn read_number(&mut self) -> Result<f64, ParserError> {
315 let start = self.position;
316
317 if self.current() == Some('0') {
319 self.advance();
320 } else if self.current().is_some_and(|c| c.is_ascii_digit()) {
321 while self.current().is_some_and(|c| c.is_ascii_digit()) {
322 self.advance();
323 }
324 } else {
325 return Err(ParserError::InvalidNumber("Expected digit".to_string()));
326 }
327
328 if self.current() == Some('.') && self.peek(1) != Some('.') {
330 self.advance();
332 if !self.current().is_some_and(|c| c.is_ascii_digit()) {
333 return Err(ParserError::InvalidNumber(
334 "Expected digit after decimal point".to_string(),
335 ));
336 }
337 while self.current().is_some_and(|c| c.is_ascii_digit()) {
338 self.advance();
339 }
340 }
341
342 if matches!(self.current(), Some('e') | Some('E')) {
344 self.advance();
345 if matches!(self.current(), Some('+') | Some('-')) {
346 self.advance();
347 }
348 if !self.current().is_some_and(|c| c.is_ascii_digit()) {
349 return Err(ParserError::InvalidNumber(
350 "Expected digit in exponent".to_string(),
351 ));
352 }
353 while self.current().is_some_and(|c| c.is_ascii_digit()) {
354 self.advance();
355 }
356 }
357
358 let num_str: String = self.input[start..self.position].iter().collect();
359 let num: f64 = num_str
360 .parse()
361 .map_err(|_| ParserError::InvalidNumber(num_str.clone()))?;
362
363 if num.is_infinite() {
365 return Err(ParserError::InvalidNumber(format!(
366 "S0102: Number out of range: {}",
367 num_str
368 )));
369 }
370
371 Ok(num)
372 }
373
374 fn read_identifier(&mut self) -> String {
375 let start = self.position;
376
377 while let Some(ch) = self.current() {
378 if ch.is_alphanumeric() || ch == '_' {
380 self.advance();
381 } else {
382 break;
383 }
384 }
385
386 self.input[start..self.position].iter().collect()
387 }
388
389 fn read_backtick_name(&mut self) -> Result<String, ParserError> {
390 self.advance(); let start = self.position;
392
393 while let Some(ch) = self.current() {
394 if ch == '`' {
395 let name: String = self.input[start..self.position].iter().collect();
396 self.advance(); return Ok(name);
398 }
399 self.advance();
400 }
401
402 Err(ParserError::UnclosedBacktick)
403 }
404
405 fn read_regex(&mut self) -> Result<Token, ParserError> {
406 self.advance(); let mut pattern = String::new();
410 let mut escaped = false;
411
412 loop {
413 match self.current() {
414 None => return Err(ParserError::UnclosedString),
415 Some('/') if !escaped => {
416 self.advance(); break;
418 }
419 Some('\\') if !escaped => {
420 escaped = true;
421 pattern.push('\\');
422 self.advance();
423 }
424 Some(ch) => {
425 escaped = false;
426 pattern.push(ch);
427 self.advance();
428 }
429 }
430 }
431
432 let mut flags = String::new();
434 while let Some(ch) = self.current() {
435 if ch.is_alphabetic() {
436 flags.push(ch);
437 self.advance();
438 } else {
439 break;
440 }
441 }
442
443 Ok(Token::Regex { pattern, flags })
444 }
445
446 fn emit_token(&mut self, token: Token) -> Result<Token, ParserError> {
447 self.last_token = Some(token.clone());
448 Ok(token)
449 }
450
451 pub fn next_token(&mut self) -> Result<Token, ParserError> {
452 loop {
453 self.skip_whitespace();
454
455 match self.current() {
456 None => return Ok(Token::Eof),
457
458 Some('/') if self.peek(1) == Some('*') => {
460 self.skip_comment()?;
461 continue; }
463
464 Some('"') => {
466 let s = self.read_string('"')?;
467 return self.emit_token(Token::String(s));
468 }
469 Some('\'') => {
470 let s = self.read_string('\'')?;
471 return self.emit_token(Token::String(s));
472 }
473
474 Some('`') => {
476 let name = self.read_backtick_name()?;
477 return self.emit_token(Token::Identifier(name));
478 }
479
480 Some(ch) if ch.is_ascii_digit() => {
482 let num = self.read_number()?;
483 return self.emit_token(Token::Number(num));
484 }
485
486 Some('$') if self.peek(1) == Some('$') => {
488 self.advance(); self.advance(); let name = self.read_identifier();
492 return self.emit_token(Token::ParentVariable(name));
493 }
494 Some('$') => {
495 self.advance();
496 let name = self.read_identifier();
497 return self.emit_token(Token::Variable(name));
498 }
499
500 Some('.') if self.peek(1) == Some('.') => {
502 self.advance();
503 self.advance();
504 return Ok(Token::DotDot);
505 }
506 Some(':') if self.peek(1) == Some('=') => {
507 self.advance();
508 self.advance();
509 return Ok(Token::ColonEqual);
510 }
511 Some('!') if self.peek(1) == Some('=') => {
512 self.advance();
513 self.advance();
514 return Ok(Token::NotEqual);
515 }
516 Some('>') if self.peek(1) == Some('=') => {
517 self.advance();
518 self.advance();
519 return Ok(Token::GreaterThanOrEqual);
520 }
521 Some('<') if self.peek(1) == Some('=') => {
522 self.advance();
523 self.advance();
524 return Ok(Token::LessThanOrEqual);
525 }
526 Some('~') if self.peek(1) == Some('>') => {
527 self.advance();
528 self.advance();
529 return self.emit_token(Token::TildeArrow);
530 }
531
532 Some('(') => {
534 self.advance();
535 return Ok(Token::LeftParen);
536 }
537 Some(')') => {
538 self.advance();
539 return self.emit_token(Token::RightParen);
540 }
541 Some('[') => {
542 self.advance();
543 return Ok(Token::LeftBracket);
544 }
545 Some(']') => {
546 self.advance();
547 return self.emit_token(Token::RightBracket);
548 }
549 Some('{') => {
550 self.advance();
551 return Ok(Token::LeftBrace);
552 }
553 Some('}') => {
554 self.advance();
555 return self.emit_token(Token::RightBrace);
556 }
557 Some(',') => {
558 self.advance();
559 return self.emit_token(Token::Comma);
560 }
561 Some(';') => {
562 self.advance();
563 return self.emit_token(Token::Semicolon);
564 }
565 Some(':') => {
566 self.advance();
567 return Ok(Token::Colon);
568 }
569 Some('?') if self.peek(1) == Some('?') => {
570 self.advance();
571 self.advance();
572 return Ok(Token::QuestionQuestion);
573 }
574 Some('?') if self.peek(1) == Some(':') => {
575 self.advance();
576 self.advance();
577 return Ok(Token::QuestionColon);
578 }
579 Some('?') => {
580 self.advance();
581 return Ok(Token::Question);
582 }
583 Some('λ') => {
584 self.advance();
586 return Ok(Token::Function);
587 }
588 Some('.') => {
589 self.advance();
590 return Ok(Token::Dot);
591 }
592 Some('+') => {
593 self.advance();
594 return Ok(Token::Plus);
595 }
596 Some('-') => {
597 self.advance();
598 return Ok(Token::Minus);
599 }
600 Some('*') if self.peek(1) == Some('*') => {
601 self.advance();
602 self.advance();
603 return Ok(Token::StarStar);
604 }
605 Some('*') => {
606 self.advance();
607 return Ok(Token::Star);
608 }
609 Some('/') => {
610 let is_regex = match &self.last_token {
619 None => true, Some(Token::LeftParen)
621 | Some(Token::LeftBracket)
622 | Some(Token::LeftBrace) => true,
623 Some(Token::Comma) | Some(Token::Semicolon) | Some(Token::Colon) => true,
624 Some(Token::Equal) | Some(Token::NotEqual) => true,
625 Some(Token::LessThan) | Some(Token::LessThanOrEqual) => true,
626 Some(Token::GreaterThan) | Some(Token::GreaterThanOrEqual) => true,
627 Some(Token::Plus) | Some(Token::Minus) | Some(Token::Star)
628 | Some(Token::Percent) => true,
629 Some(Token::Ampersand)
630 | Some(Token::Question)
631 | Some(Token::TildeArrow) => true,
632 Some(Token::ColonEqual)
633 | Some(Token::QuestionQuestion)
634 | Some(Token::QuestionColon) => true,
635 Some(Token::And) | Some(Token::Or) | Some(Token::In) => true,
636 Some(Token::Function) => true,
637 Some(Token::Identifier(s)) if s == "and" || s == "or" || s == "in" => true,
638 _ => false, };
640
641 if is_regex {
642 let tok = self.read_regex()?;
643 return self.emit_token(tok);
644 } else {
645 self.advance();
646 return self.emit_token(Token::Slash);
647 }
648 }
649 Some('%') => {
650 self.advance();
651 return Ok(Token::Percent);
652 }
653 Some('^') => {
654 self.advance();
655 return Ok(Token::Caret);
656 }
657 Some('#') => {
658 self.advance();
659 return Ok(Token::Hash);
660 }
661 Some('@') => {
662 self.advance();
663 return Ok(Token::At);
664 }
665 Some('=') => {
666 self.advance();
667 return Ok(Token::Equal);
668 }
669 Some('<') => {
670 self.advance();
671 return Ok(Token::LessThan);
672 }
673 Some('>') => {
674 self.advance();
675 return Ok(Token::GreaterThan);
676 }
677 Some('&') => {
678 self.advance();
679 return Ok(Token::Ampersand);
680 }
681 Some('|') => {
682 self.advance();
683 return Ok(Token::Pipe);
684 }
685
686 Some(ch) if ch.is_alphabetic() || ch == '_' => {
688 let ident = self.read_identifier();
689 let tok = match ident.as_str() {
690 "true" => Token::True,
691 "false" => Token::False,
692 "null" => Token::Null,
693 "undefined" => Token::Undefined,
694 "function" => Token::Function,
695 _ => Token::Identifier(ident),
697 };
698 return self.emit_token(tok);
699 }
700
701 Some(ch) => {
702 return Err(ParserError::UnexpectedToken(ch.to_string()));
703 }
704 }
705 }
706 }
707}
708
709const PARSER_RED_ZONE: usize = 128 * 1024;
716const PARSER_GROW_STACK_SIZE: usize = 8 * 1024 * 1024;
717
718const MAX_PARSE_DEPTH: usize = 1000;
731
732pub struct Parser {
734 lexer: Lexer,
735 current_token: Token,
736 depth: usize,
746}
747
748impl Parser {
749 pub fn new(input: String) -> Result<Self, ParserError> {
750 let mut lexer = Lexer::new(input);
751 let current_token = lexer.next_token()?;
752 Ok(Parser {
753 lexer,
754 current_token,
755 depth: 0,
756 })
757 }
758
759 fn advance(&mut self) -> Result<(), ParserError> {
760 self.current_token = self.lexer.next_token()?;
761 Ok(())
762 }
763
764 fn expect(&mut self, expected: Token) -> Result<(), ParserError> {
765 if std::mem::discriminant(&self.current_token) == std::mem::discriminant(&expected) {
766 self.advance()?;
767 Ok(())
768 } else {
769 Err(ParserError::Expected {
770 expected: format!("{:?}", expected),
771 found: format!("{:?}", self.current_token),
772 })
773 }
774 }
775
776 fn binding_power(&self, token: &Token) -> Option<(u8, u8)> {
778 match token {
781 Token::Identifier(name) if name == "or" => Some((25, 26)),
783 Token::Identifier(name) if name == "and" => Some((30, 31)),
784 Token::Identifier(name) if name == "in" => Some((40, 41)),
785 Token::Or => Some((25, 26)),
787 Token::And => Some((30, 31)),
788 Token::Equal
789 | Token::NotEqual
790 | Token::LessThan
791 | Token::LessThanOrEqual
792 | Token::GreaterThan
793 | Token::GreaterThanOrEqual
794 | Token::In => Some((40, 41)),
795 Token::Ampersand => Some((50, 51)),
796 Token::Plus | Token::Minus => Some((50, 51)),
797 Token::Star | Token::Slash | Token::Percent => Some((60, 61)),
798 Token::Dot => Some((75, 85)), Token::LeftBracket => Some((80, 81)),
800 Token::LeftParen => Some((80, 81)),
801 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)),
806 Token::QuestionQuestion => Some((15, 16)), Token::QuestionColon => Some((15, 16)), Token::DotDot => Some((20, 21)),
809 Token::ColonEqual => Some((10, 9)), Token::TildeArrow => Some((70, 71)), _ => None,
812 }
813 }
814
815 fn parse_signature(&mut self) -> Result<String, ParserError> {
817 if self.current_token != Token::LessThan {
819 return Err(ParserError::Expected {
820 expected: "<".to_string(),
821 found: format!("{:?}", self.current_token),
822 });
823 }
824
825 let mut signature = String::from("<");
827 self.advance()?; let mut depth = 1;
832
833 while depth > 0 && self.current_token != Token::Eof {
834 match &self.current_token {
835 Token::LessThan => {
836 signature.push('<');
837 depth += 1;
838 self.advance()?;
839 }
840 Token::GreaterThan => {
841 depth -= 1;
842 if depth > 0 {
843 signature.push('>');
844 }
845 self.advance()?;
846 }
847 Token::Minus => {
848 signature.push('-');
849 self.advance()?;
850 }
851 Token::Plus => {
852 signature.push('+');
853 self.advance()?;
854 }
855 Token::Colon => {
856 signature.push(':');
857 self.advance()?;
858 }
859 Token::Question => {
860 signature.push('?');
861 self.advance()?;
862 }
863 Token::QuestionColon => {
864 signature.push('?');
866 signature.push(':');
867 self.advance()?;
868 }
869 Token::Identifier(s) => {
870 signature.push_str(s);
871 self.advance()?;
872 }
873 Token::LeftParen | Token::RightParen => {
874 let c = if self.current_token == Token::LeftParen {
876 '('
877 } else {
878 ')'
879 };
880 signature.push(c);
881 self.advance()?;
882 }
883 _ => {
884 return Err(ParserError::UnexpectedToken(format!(
885 "Unexpected token in signature: {:?}",
886 self.current_token
887 )));
888 }
889 }
890 }
891
892 signature.push('>');
893 Ok(signature)
894 }
895
896 fn parse_primary(&mut self) -> Result<AstNode, ParserError> {
898 match &self.current_token {
899 Token::String(s) => {
900 let value = s.clone();
901 self.advance()?;
902 Ok(AstNode::String(value))
903 }
904 Token::Number(n) => {
905 let value = *n;
906 self.advance()?;
907 Ok(AstNode::Number(value))
908 }
909 Token::True => {
910 self.advance()?;
911 Ok(AstNode::Boolean(true))
912 }
913 Token::False => {
914 self.advance()?;
915 Ok(AstNode::Boolean(false))
916 }
917 Token::Null => {
918 self.advance()?;
919 Ok(AstNode::Null)
920 }
921 Token::Undefined => {
922 self.advance()?;
923 Ok(AstNode::Undefined)
924 }
925 Token::Regex { pattern, flags } => {
926 let pat = pattern.clone();
927 let flg = flags.clone();
928 self.advance()?;
929 Ok(AstNode::Regex {
930 pattern: pat,
931 flags: flg,
932 })
933 }
934 Token::Identifier(name) => {
935 let name = name.clone();
936 self.advance()?;
937 Ok(AstNode::Path {
938 steps: vec![PathStep::new(AstNode::Name(name))],
939 })
940 }
941 Token::Variable(name) => {
942 let name = name.clone();
943 self.advance()?;
944 Ok(AstNode::Variable(name))
945 }
946 Token::ParentVariable(name) => {
947 let name = name.clone();
948 self.advance()?;
949 Ok(AstNode::ParentVariable(name))
950 }
951 Token::LeftParen => {
952 self.advance()?; if self.current_token == Token::RightParen {
956 self.advance()?;
957 return Ok(AstNode::Undefined);
958 }
959
960 let mut expressions = vec![self.parse_expression(0)?];
964
965 while self.current_token == Token::Semicolon {
966 self.advance()?;
967 if self.current_token == Token::RightParen {
968 break;
969 }
970 expressions.push(self.parse_expression(0)?);
971 }
972
973 self.expect(Token::RightParen)?;
974
975 Ok(AstNode::Block(expressions))
977 }
978 Token::LeftBracket => {
979 self.advance()?; let mut elements = Vec::new();
982
983 if self.current_token != Token::RightBracket {
984 loop {
985 let element = self.parse_expression(0)?;
986 elements.push(element);
987
988 if self.current_token != Token::Comma {
989 break;
990 }
991 self.advance()?;
992 }
993 }
994
995 self.expect(Token::RightBracket)?;
996 Ok(AstNode::Array(elements))
997 }
998 Token::LeftBrace => {
999 self.advance()?; let mut pairs = Vec::new();
1002
1003 if self.current_token != Token::RightBrace {
1004 loop {
1005 let key = self.parse_expression(0)?;
1006 self.expect(Token::Colon)?;
1007 let value = self.parse_expression(0)?;
1008 pairs.push((key, value));
1009
1010 if self.current_token != Token::Comma {
1011 break;
1012 }
1013 self.advance()?;
1014 }
1015 }
1016
1017 self.expect(Token::RightBrace)?;
1018 Ok(AstNode::Object(pairs))
1019 }
1020 Token::Pipe => {
1021 self.advance()?; let location = self.parse_expression(0)?;
1026
1027 self.expect(Token::Pipe)?;
1029
1030 let update = self.parse_expression(0)?;
1032
1033 let delete = if self.current_token == Token::Comma {
1035 self.advance()?; Some(Box::new(self.parse_expression(0)?))
1037 } else {
1038 None
1039 };
1040
1041 self.expect(Token::Pipe)?;
1043
1044 Ok(AstNode::Transform {
1045 location: Box::new(location),
1046 update: Box::new(update),
1047 delete,
1048 })
1049 }
1050 Token::Minus => {
1051 self.advance()?;
1052 let operand = self.parse_expression(70)?; Ok(AstNode::Unary {
1054 op: UnaryOp::Negate,
1055 operand: Box::new(operand),
1056 })
1057 }
1058 Token::Star => {
1059 self.advance()?;
1061 Ok(AstNode::Wildcard)
1062 }
1063 Token::StarStar => {
1064 self.advance()?;
1066 Ok(AstNode::Descendant)
1067 }
1068 Token::Percent => {
1069 self.advance()?;
1074 Ok(AstNode::Parent(String::new()))
1075 }
1076 Token::Function => {
1077 self.advance()?; self.expect(Token::LeftParen)?;
1080
1081 let mut params = Vec::new();
1083 if self.current_token != Token::RightParen {
1084 loop {
1085 match &self.current_token {
1086 Token::Variable(name) => {
1087 params.push(name.clone());
1088 self.advance()?;
1089 }
1090 _ => {
1091 return Err(ParserError::Expected {
1092 expected: "parameter name".to_string(),
1093 found: format!("{:?}", self.current_token),
1094 })
1095 }
1096 }
1097
1098 if self.current_token != Token::Comma {
1099 break;
1100 }
1101 self.advance()?; }
1103 }
1104
1105 self.expect(Token::RightParen)?;
1106
1107 let signature = if self.current_token == Token::LessThan {
1109 Some(self.parse_signature()?)
1110 } else {
1111 None
1112 };
1113
1114 self.expect(Token::LeftBrace)?;
1115
1116 let body = self.parse_expression(0)?;
1118
1119 self.expect(Token::RightBrace)?;
1120
1121 let (optimized_body, is_thunk) = Self::tail_call_optimize(body);
1123
1124 Ok(AstNode::Lambda {
1125 params,
1126 body: Box::new(optimized_body),
1127 signature,
1128 thunk: is_thunk,
1129 })
1130 }
1131 _ => Err(ParserError::UnexpectedToken(format!(
1132 "{:?}",
1133 self.current_token
1134 ))),
1135 }
1136 }
1137
1138 fn bump_parse_depth(&mut self) -> Result<(), ParserError> {
1148 self.depth += 1;
1149 if self.depth > MAX_PARSE_DEPTH {
1150 return Err(ParserError::Coded {
1151 code: "U1002",
1152 message: format!(
1153 "Stack overflow - maximum expression nesting depth ({}) exceeded while parsing expression",
1154 MAX_PARSE_DEPTH
1155 ),
1156 });
1157 }
1158 Ok(())
1159 }
1160
1161 fn parse_expression(&mut self, min_bp: u8) -> Result<AstNode, ParserError> {
1176 let entry_depth = self.depth;
1177 self.bump_parse_depth()?;
1178
1179 let result = stacker::maybe_grow(PARSER_RED_ZONE, PARSER_GROW_STACK_SIZE, || {
1180 self.parse_expression_impl(min_bp)
1181 });
1182
1183 self.depth = entry_depth;
1184 result
1185 }
1186
1187 fn parse_expression_impl(&mut self, min_bp: u8) -> Result<AstNode, ParserError> {
1188 let mut lhs = self.parse_primary()?;
1189
1190 loop {
1191 if matches!(
1193 self.current_token,
1194 Token::Eof
1195 | Token::RightParen
1196 | Token::RightBracket
1197 | Token::RightBrace
1198 | Token::Comma
1199 | Token::Semicolon
1200 | Token::Colon
1201 ) {
1202 break;
1203 }
1204
1205 let (left_bp, right_bp) = match self.binding_power(&self.current_token) {
1207 Some(bp) => bp,
1208 None => break,
1209 };
1210
1211 if left_bp < min_bp {
1212 break;
1213 }
1214
1215 match &self.current_token {
1217 Token::Dot => {
1218 self.advance()?;
1219
1220 if self.current_token == Token::LeftBracket {
1222 self.advance()?;
1223
1224 let mut elements = Vec::new();
1226 if self.current_token != Token::RightBracket {
1227 loop {
1228 elements.push(self.parse_expression(0)?);
1229 if self.current_token != Token::Comma {
1230 break;
1231 }
1232 self.advance()?;
1233 }
1234 }
1235
1236 self.expect(Token::RightBracket)?;
1237
1238 let mut steps = match lhs {
1240 AstNode::Path { steps } => steps,
1241 _ => vec![PathStep::new(lhs)],
1242 };
1243
1244 steps.push(PathStep::new(AstNode::ArrayGroup(elements)));
1245 self.bump_parse_depth()?;
1246 lhs = AstNode::Path { steps };
1247 } else if self.current_token == Token::LeftParen {
1248 self.advance()?;
1250
1251 if self.current_token == Token::RightParen {
1257 self.advance()?;
1258 let mut steps = match lhs {
1259 AstNode::Path { steps } => steps,
1260 _ => vec![PathStep::new(lhs)],
1261 };
1262 steps.push(PathStep::new(AstNode::FunctionApplication(Box::new(
1263 AstNode::Block(Vec::new()),
1264 ))));
1265 self.bump_parse_depth()?;
1266 lhs = AstNode::Path { steps };
1267 continue;
1268 }
1269
1270 let mut expressions = vec![self.parse_expression(0)?];
1272
1273 while self.current_token == Token::Semicolon {
1274 self.advance()?;
1275 if self.current_token == Token::RightParen {
1276 break;
1277 }
1278 expressions.push(self.parse_expression(0)?);
1279 }
1280
1281 self.expect(Token::RightParen)?;
1282
1283 let expr = if expressions.len() == 1 {
1285 expressions.into_iter().next().unwrap()
1286 } else {
1287 AstNode::Block(expressions)
1288 };
1289
1290 let mut steps = match lhs {
1292 AstNode::Path { steps } => steps,
1293 _ => vec![PathStep::new(lhs)],
1294 };
1295
1296 steps.push(PathStep::new(AstNode::FunctionApplication(Box::new(expr))));
1297 self.bump_parse_depth()?;
1298 lhs = AstNode::Path { steps };
1299 } else {
1300 let rhs = self.parse_expression(right_bp)?;
1302
1303 let mut steps = match lhs {
1305 AstNode::Path { steps } => steps,
1306 AstNode::String(field_name) => {
1309 vec![PathStep::new(AstNode::Name(field_name))]
1310 }
1311 _ => vec![PathStep::new(lhs)],
1312 };
1313
1314 match &rhs {
1317 AstNode::Number(n) => {
1318 return Err(ParserError::InvalidSyntax(
1319 format!("S0213: The literal value {} cannot be used as a step within a path expression", n),
1320 ));
1321 }
1322 AstNode::Boolean(b) => {
1323 return Err(ParserError::InvalidSyntax(
1324 format!("S0213: The literal value {} cannot be used as a step within a path expression", b),
1325 ));
1326 }
1327 AstNode::Null => {
1328 return Err(ParserError::InvalidSyntax(
1329 "S0213: The literal value null cannot be used as a step within a path expression".to_string(),
1330 ));
1331 }
1332 _ => {}
1333 }
1334
1335 match rhs {
1336 AstNode::Path {
1337 steps: mut rhs_steps,
1338 } => {
1339 steps.append(&mut rhs_steps);
1340 }
1341 AstNode::String(field_name) => {
1344 steps.push(PathStep::new(AstNode::Name(field_name)));
1345 }
1346 _ => steps.push(PathStep::new(rhs)),
1347 }
1348
1349 while self.current_token == Token::LeftBracket {
1352 self.advance()?;
1353
1354 let predicate_expr = if self.current_token == Token::RightBracket {
1355 Box::new(AstNode::Boolean(true))
1357 } else {
1358 let pred = self.parse_expression(0)?;
1360 Box::new(pred)
1361 };
1362
1363 self.expect(Token::RightBracket)?;
1364
1365 if let Some(last_step) = steps.last_mut() {
1367 last_step.stages.push(Stage::Filter(predicate_expr));
1368 }
1369 }
1370
1371 self.bump_parse_depth()?;
1372 lhs = AstNode::Path { steps };
1373 }
1374 }
1375 Token::LeftBracket => {
1376 if matches!(lhs, AstNode::ObjectTransform { .. }) {
1379 return Err(ParserError::InvalidSyntax(
1380 "S0209: A predicate cannot follow a grouping expression in a step"
1381 .to_string(),
1382 ));
1383 }
1384
1385 self.advance()?;
1386
1387 if self.current_token == Token::RightBracket {
1390 self.advance()?;
1392
1393 let mut steps = match lhs {
1394 AstNode::Path { steps } => steps,
1395 _ => vec![PathStep::new(lhs)],
1396 };
1397
1398 steps.push(PathStep::new(AstNode::Predicate(Box::new(
1399 AstNode::Boolean(true),
1400 ))));
1401 self.bump_parse_depth()?;
1402 lhs = AstNode::Path { steps };
1403 } else {
1404 let predicate = self.parse_expression(0)?;
1406 self.expect(Token::RightBracket)?;
1407
1408 let mut steps = match lhs {
1409 AstNode::Path { steps } => steps,
1410 _ => vec![PathStep::new(lhs)],
1411 };
1412
1413 steps.push(PathStep::new(AstNode::Predicate(Box::new(predicate))));
1414 self.bump_parse_depth()?;
1415 lhs = AstNode::Path { steps };
1416 }
1417 }
1418 Token::LeftParen => {
1419 self.advance()?;
1420
1421 let mut args = Vec::new();
1422
1423 if self.current_token != Token::RightParen {
1424 loop {
1425 if self.current_token == Token::Question {
1427 args.push(AstNode::Placeholder);
1428 self.advance()?;
1429 } else {
1430 args.push(self.parse_expression(0)?);
1431 }
1432
1433 if self.current_token != Token::Comma {
1434 break;
1435 }
1436 self.advance()?;
1437 }
1438 }
1439
1440 self.expect(Token::RightParen)?;
1441
1442 match lhs {
1444 AstNode::Lambda { .. }
1446 | AstNode::Block(_)
1447 | AstNode::Call { .. }
1448 | AstNode::Function { .. } => {
1449 self.bump_parse_depth()?;
1450 lhs = AstNode::Call {
1451 procedure: Box::new(lhs),
1452 args,
1453 };
1454 }
1455 ref other_lhs => {
1456 match other_lhs {
1458 AstNode::Path { steps } if steps.len() == 1 => {
1460 let name = match &steps[0].node {
1461 AstNode::Name(s) => s.clone(),
1462 _ => {
1463 return Err(ParserError::InvalidSyntax(
1464 "Invalid function name".to_string(),
1465 ))
1466 }
1467 };
1468 self.bump_parse_depth()?;
1469 lhs = AstNode::Function {
1470 name,
1471 args,
1472 is_builtin: false,
1473 };
1474 }
1475 AstNode::Path { steps } if steps.len() > 1 => {
1477 let last_step = &steps[steps.len() - 1].node;
1478
1479 if let AstNode::Variable(func_name) = last_step {
1481 let mut context_steps = steps.clone();
1483 context_steps.pop();
1484
1485 let func_call = AstNode::Function {
1487 name: func_name.clone(),
1488 args: args.clone(),
1489 is_builtin: true, };
1491
1492 context_steps.push(PathStep::new(
1494 AstNode::FunctionApplication(Box::new(func_call)),
1495 ));
1496
1497 self.bump_parse_depth()?;
1498 lhs = AstNode::Path {
1499 steps: context_steps,
1500 };
1501 }
1502 else if let AstNode::Lambda {
1504 params,
1505 body,
1506 signature,
1507 thunk,
1508 } = last_step
1509 {
1510 let mut context_steps = steps.clone();
1512 context_steps.pop();
1513
1514 let full_args = if args.len() < params.len() {
1518 let mut new_args =
1519 vec![AstNode::Variable("$".to_string())];
1520 new_args.extend(args.clone());
1521 new_args
1522 } else {
1523 args.clone()
1524 };
1525
1526 let lambda_invocation = AstNode::Block(vec![
1529 AstNode::Binary {
1530 op: crate::ast::BinaryOp::ColonEqual,
1531 lhs: Box::new(AstNode::Variable(
1532 "__path_lambda__".to_string(),
1533 )),
1534 rhs: Box::new(AstNode::Lambda {
1535 params: params.clone(),
1536 body: body.clone(),
1537 signature: signature.clone(),
1538 thunk: *thunk,
1539 }),
1540 },
1541 AstNode::Function {
1542 name: "__path_lambda__".to_string(),
1543 args: full_args,
1544 is_builtin: true,
1545 },
1546 ]);
1547
1548 context_steps.push(PathStep::new(
1550 AstNode::FunctionApplication(Box::new(
1551 lambda_invocation,
1552 )),
1553 ));
1554
1555 self.bump_parse_depth()?;
1556 lhs = AstNode::Path {
1557 steps: context_steps,
1558 };
1559 } else {
1560 return Err(ParserError::InvalidSyntax(
1561 "Invalid function call".to_string(),
1562 ));
1563 }
1564 }
1565 AstNode::Variable(name) => {
1567 self.bump_parse_depth()?;
1568 lhs = AstNode::Function {
1569 name: name.clone(),
1570 args,
1571 is_builtin: true,
1572 };
1573 }
1574 _ => {
1575 return Err(ParserError::InvalidSyntax(
1576 "Invalid function call".to_string(),
1577 ))
1578 }
1579 };
1580 }
1581 }
1582 }
1583 Token::Question => {
1584 self.advance()?;
1585 let then_branch = self.parse_expression(0)?;
1586
1587 let else_branch = if self.current_token == Token::Colon {
1588 self.advance()?;
1589 Some(Box::new(self.parse_expression(0)?))
1591 } else {
1592 None
1593 };
1594
1595 self.bump_parse_depth()?;
1596 lhs = AstNode::Conditional {
1597 condition: Box::new(lhs),
1598 then_branch: Box::new(then_branch),
1599 else_branch,
1600 };
1601 }
1602 Token::LeftBrace => {
1603 if matches!(lhs, AstNode::ObjectTransform { .. }) {
1606 return Err(ParserError::InvalidSyntax(
1607 "S0210: Each step can only have one grouping expression".to_string(),
1608 ));
1609 }
1610
1611 self.advance()?; let mut pairs = Vec::new();
1615
1616 if self.current_token != Token::RightBrace {
1617 loop {
1618 let key = self.parse_expression(0)?;
1620
1621 self.expect(Token::Colon)?;
1622
1623 let value = self.parse_expression(0)?;
1625
1626 pairs.push((key, value));
1627
1628 if self.current_token != Token::Comma {
1629 break;
1630 }
1631 self.advance()?; }
1633 }
1634
1635 self.expect(Token::RightBrace)?;
1636
1637 self.bump_parse_depth()?;
1639 lhs = AstNode::ObjectTransform {
1640 input: Box::new(lhs),
1641 pattern: pairs,
1642 };
1643 }
1644 Token::Hash => {
1645 self.advance()?; let var_name = match &self.current_token {
1653 Token::Variable(name) => name.clone(),
1654 _ => {
1655 return Err(ParserError::Coded {
1656 code: "S0214",
1657 message: "Expected a variable reference after #".to_string(),
1658 });
1659 }
1660 };
1661 self.advance()?; self.bump_parse_depth()?;
1670 lhs = AstNode::Binary {
1671 op: BinaryOp::IndexBind,
1672 lhs: Box::new(lhs),
1673 rhs: Box::new(AstNode::Variable(var_name)),
1674 };
1675 }
1676 Token::At => {
1677 self.advance()?; let var_name = match &self.current_token {
1685 Token::Variable(name) => name.clone(),
1686 _ => {
1687 return Err(ParserError::Coded {
1688 code: "S0214",
1689 message: "Expected a variable reference after @".to_string(),
1690 });
1691 }
1692 };
1693 self.advance()?; self.bump_parse_depth()?;
1696 lhs = AstNode::Binary {
1697 op: BinaryOp::FocusBind,
1698 lhs: Box::new(lhs),
1699 rhs: Box::new(AstNode::Variable(var_name)),
1700 };
1701 }
1702 Token::Caret => {
1703 self.advance()?; self.expect(Token::LeftParen)?;
1706
1707 let mut terms = Vec::new();
1708
1709 loop {
1710 let ascending = match &self.current_token {
1712 Token::LessThan => {
1713 self.advance()?;
1714 true
1715 }
1716 Token::GreaterThan => {
1717 self.advance()?;
1718 false
1719 }
1720 _ => true, };
1722
1723 let expr = self.parse_expression(0)?;
1725 terms.push((expr, ascending));
1726
1727 if self.current_token != Token::Comma {
1729 break;
1730 }
1731 self.advance()?; }
1733
1734 self.expect(Token::RightParen)?;
1735
1736 self.bump_parse_depth()?;
1737 lhs = AstNode::Sort {
1738 input: Box::new(lhs),
1739 terms,
1740 };
1741 }
1742 _ => {
1743 let op = match &self.current_token {
1745 Token::Identifier(name) if name == "and" => BinaryOp::And,
1747 Token::Identifier(name) if name == "or" => BinaryOp::Or,
1748 Token::Identifier(name) if name == "in" => BinaryOp::In,
1749 Token::Plus => BinaryOp::Add,
1751 Token::Minus => BinaryOp::Subtract,
1752 Token::Star => BinaryOp::Multiply,
1753 Token::Slash => BinaryOp::Divide,
1754 Token::Percent => BinaryOp::Modulo,
1755 Token::Equal => BinaryOp::Equal,
1756 Token::NotEqual => BinaryOp::NotEqual,
1757 Token::LessThan => BinaryOp::LessThan,
1758 Token::LessThanOrEqual => BinaryOp::LessThanOrEqual,
1759 Token::GreaterThan => BinaryOp::GreaterThan,
1760 Token::GreaterThanOrEqual => BinaryOp::GreaterThanOrEqual,
1761 Token::And => BinaryOp::And,
1762 Token::Or => BinaryOp::Or,
1763 Token::In => BinaryOp::In,
1764 Token::Ampersand => BinaryOp::Concatenate,
1765 Token::DotDot => BinaryOp::Range,
1766 Token::ColonEqual => BinaryOp::ColonEqual,
1767 Token::QuestionQuestion => BinaryOp::Coalesce,
1768 Token::QuestionColon => BinaryOp::Default,
1769 Token::TildeArrow => BinaryOp::ChainPipe,
1770 _ => {
1771 return Err(ParserError::UnexpectedToken(format!(
1772 "{:?}",
1773 self.current_token
1774 )))
1775 }
1776 };
1777
1778 self.advance()?;
1779 let rhs = self.parse_expression(right_bp)?;
1780
1781 self.bump_parse_depth()?;
1782 lhs = AstNode::Binary {
1783 op,
1784 lhs: Box::new(lhs),
1785 rhs: Box::new(rhs),
1786 };
1787 }
1788 }
1789 }
1790
1791 Ok(lhs)
1792 }
1793
1794 pub fn parse(&mut self) -> Result<AstNode, ParserError> {
1795 let ast = self.parse_expression(0)?;
1796
1797 if self.current_token != Token::Eof {
1798 return Err(ParserError::Expected {
1799 expected: "end of expression".to_string(),
1800 found: format!("{:?}", self.current_token),
1801 });
1802 }
1803
1804 Ok(ast)
1805 }
1806
1807 fn tail_call_optimize(expr: AstNode) -> (AstNode, bool) {
1817 let is_thunk = Self::is_tail_call(&expr);
1818 (expr, is_thunk)
1819 }
1820
1821 fn is_tail_call(expr: &AstNode) -> bool {
1824 match expr {
1825 AstNode::Function { .. } => true,
1827 AstNode::Call { .. } => true,
1828
1829 AstNode::Conditional {
1831 then_branch,
1832 else_branch,
1833 ..
1834 } => {
1835 let then_is_tail = Self::is_tail_call(then_branch);
1836 let else_is_tail = else_branch.as_ref().is_some_and(|e| Self::is_tail_call(e));
1837 then_is_tail || else_is_tail
1839 }
1840
1841 AstNode::Block(exprs) => exprs.last().is_some_and(Self::is_tail_call),
1843
1844 AstNode::Binary {
1846 op: BinaryOp::ColonEqual,
1847 rhs,
1848 ..
1849 } => {
1850 Self::is_tail_call(rhs)
1854 }
1855
1856 _ => false,
1858 }
1859 }
1860}
1861
1862pub fn parse(expression: &str) -> Result<AstNode, ParserError> {
1869 let mut parser = Parser::new(expression.to_string())?;
1870 let raw_ast = parser.parse()?;
1871 crate::ast_transform::resolve_ancestry(raw_ast).map_err(|e| match e {
1872 crate::ast_transform::AstTransformError::Coded { code, message } => {
1873 ParserError::Coded { code, message }
1874 }
1875 })
1876}
1877
1878#[cfg(test)]
1879mod tests {
1880 use super::*;
1881
1882 #[test]
1884 fn test_lexer_numbers() {
1885 let mut lexer = Lexer::new("42 3.14 -10 2.5e10 1E-5".to_string());
1886
1887 assert_eq!(lexer.next_token().unwrap(), Token::Number(42.0));
1888 assert_eq!(lexer.next_token().unwrap(), Token::Number(3.14));
1889 assert_eq!(lexer.next_token().unwrap(), Token::Minus);
1891 assert_eq!(lexer.next_token().unwrap(), Token::Number(10.0));
1892 assert_eq!(lexer.next_token().unwrap(), Token::Number(2.5e10));
1893 assert_eq!(lexer.next_token().unwrap(), Token::Number(1e-5));
1894 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1895 }
1896
1897 #[test]
1898 fn test_lexer_strings() {
1899 let mut lexer = Lexer::new(r#""hello" 'world' "with\nnewline""#.to_string());
1900
1901 assert_eq!(
1902 lexer.next_token().unwrap(),
1903 Token::String("hello".to_string())
1904 );
1905 assert_eq!(
1906 lexer.next_token().unwrap(),
1907 Token::String("world".to_string())
1908 );
1909 assert_eq!(
1910 lexer.next_token().unwrap(),
1911 Token::String("with\nnewline".to_string())
1912 );
1913 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1914 }
1915
1916 #[test]
1917 fn test_lexer_string_escapes() {
1918 let mut lexer = Lexer::new(r#""a\"b\\c\/d""#.to_string());
1919 assert_eq!(
1920 lexer.next_token().unwrap(),
1921 Token::String("a\"b\\c/d".to_string())
1922 );
1923 }
1924
1925 #[test]
1926 fn test_lexer_keywords() {
1927 let mut lexer = Lexer::new("true false null and or in".to_string());
1928
1929 assert_eq!(lexer.next_token().unwrap(), Token::True);
1930 assert_eq!(lexer.next_token().unwrap(), Token::False);
1931 assert_eq!(lexer.next_token().unwrap(), Token::Null);
1932 assert_eq!(
1934 lexer.next_token().unwrap(),
1935 Token::Identifier("and".to_string())
1936 );
1937 assert_eq!(
1938 lexer.next_token().unwrap(),
1939 Token::Identifier("or".to_string())
1940 );
1941 assert_eq!(
1942 lexer.next_token().unwrap(),
1943 Token::Identifier("in".to_string())
1944 );
1945 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1946 }
1947
1948 #[test]
1949 fn test_lexer_identifiers() {
1950 let mut lexer = Lexer::new("foo bar_baz test123".to_string());
1951
1952 assert_eq!(
1953 lexer.next_token().unwrap(),
1954 Token::Identifier("foo".to_string())
1955 );
1956 assert_eq!(
1957 lexer.next_token().unwrap(),
1958 Token::Identifier("bar_baz".to_string())
1959 );
1960 assert_eq!(
1961 lexer.next_token().unwrap(),
1962 Token::Identifier("test123".to_string())
1963 );
1964 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1965 }
1966
1967 #[test]
1968 fn test_lexer_variables() {
1969 let mut lexer = Lexer::new("$var $foo_bar".to_string());
1970
1971 assert_eq!(
1972 lexer.next_token().unwrap(),
1973 Token::Variable("var".to_string())
1974 );
1975 assert_eq!(
1976 lexer.next_token().unwrap(),
1977 Token::Variable("foo_bar".to_string())
1978 );
1979 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1980 }
1981
1982 #[test]
1983 fn test_lexer_operators() {
1984 let mut lexer = Lexer::new("+ - * % = != < <= > >= & . .. := ".to_string());
1986
1987 assert_eq!(lexer.next_token().unwrap(), Token::Plus);
1988 assert_eq!(lexer.next_token().unwrap(), Token::Minus);
1989 assert_eq!(lexer.next_token().unwrap(), Token::Star);
1990 assert_eq!(lexer.next_token().unwrap(), Token::Percent);
1991 assert_eq!(lexer.next_token().unwrap(), Token::Equal);
1992 assert_eq!(lexer.next_token().unwrap(), Token::NotEqual);
1993 assert_eq!(lexer.next_token().unwrap(), Token::LessThan);
1994 assert_eq!(lexer.next_token().unwrap(), Token::LessThanOrEqual);
1995 assert_eq!(lexer.next_token().unwrap(), Token::GreaterThan);
1996 assert_eq!(lexer.next_token().unwrap(), Token::GreaterThanOrEqual);
1997 assert_eq!(lexer.next_token().unwrap(), Token::Ampersand);
1998 assert_eq!(lexer.next_token().unwrap(), Token::Dot);
1999 assert_eq!(lexer.next_token().unwrap(), Token::DotDot);
2000 assert_eq!(lexer.next_token().unwrap(), Token::ColonEqual);
2001 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
2002
2003 let mut lexer2 = Lexer::new("42 / 2".to_string());
2006 assert_eq!(lexer2.next_token().unwrap(), Token::Number(42.0));
2007 assert_eq!(lexer2.next_token().unwrap(), Token::Slash);
2008 assert_eq!(lexer2.next_token().unwrap(), Token::Number(2.0));
2009 assert_eq!(lexer2.next_token().unwrap(), Token::Eof);
2010 }
2011
2012 #[test]
2013 fn test_lexer_delimiters() {
2014 let mut lexer = Lexer::new("()[]{},:;?".to_string());
2015
2016 assert_eq!(lexer.next_token().unwrap(), Token::LeftParen);
2017 assert_eq!(lexer.next_token().unwrap(), Token::RightParen);
2018 assert_eq!(lexer.next_token().unwrap(), Token::LeftBracket);
2019 assert_eq!(lexer.next_token().unwrap(), Token::RightBracket);
2020 assert_eq!(lexer.next_token().unwrap(), Token::LeftBrace);
2021 assert_eq!(lexer.next_token().unwrap(), Token::RightBrace);
2022 assert_eq!(lexer.next_token().unwrap(), Token::Comma);
2023 assert_eq!(lexer.next_token().unwrap(), Token::Colon);
2024 assert_eq!(lexer.next_token().unwrap(), Token::Semicolon);
2025 assert_eq!(lexer.next_token().unwrap(), Token::Question);
2026 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
2027 }
2028
2029 #[test]
2030 fn test_empty_brackets() {
2031 let mut parser = Parser::new("foo[]".to_string()).unwrap();
2032 let ast = parser.parse().unwrap();
2033
2034 if let AstNode::Path { steps } = ast {
2036 assert_eq!(steps.len(), 2);
2037 assert!(matches!(steps[0].node, AstNode::Name(ref s) if s == "foo"));
2038 if let AstNode::Predicate(pred) = &steps[1].node {
2039 assert!(matches!(**pred, AstNode::Boolean(true)));
2040 } else {
2041 panic!("Expected Predicate as second step, got {:?}", steps[1].node);
2042 }
2043 } else {
2044 panic!("Expected Path, got {:?}", ast);
2045 }
2046 }
2047
2048 #[test]
2049 fn test_lexer_comments() {
2050 let mut lexer = Lexer::new("foo /* comment */ bar".to_string());
2051
2052 assert_eq!(
2053 lexer.next_token().unwrap(),
2054 Token::Identifier("foo".to_string())
2055 );
2056 assert_eq!(
2057 lexer.next_token().unwrap(),
2058 Token::Identifier("bar".to_string())
2059 );
2060 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
2061 }
2062
2063 #[test]
2064 fn test_lexer_backtick_names() {
2065 let mut lexer = Lexer::new("`field name` `with-dash`".to_string());
2066
2067 assert_eq!(
2068 lexer.next_token().unwrap(),
2069 Token::Identifier("field name".to_string())
2070 );
2071 assert_eq!(
2072 lexer.next_token().unwrap(),
2073 Token::Identifier("with-dash".to_string())
2074 );
2075 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
2076 }
2077
2078 #[test]
2080 fn test_parse_number() {
2081 let ast = parse("42").unwrap();
2082 assert_eq!(ast, AstNode::Number(42.0));
2083 }
2084
2085 #[test]
2086 fn test_parse_string() {
2087 let ast = parse(r#""hello""#).unwrap();
2088 assert_eq!(ast, AstNode::String("hello".to_string()));
2089 }
2090
2091 #[test]
2092 fn test_parse_boolean() {
2093 let ast = parse("true").unwrap();
2094 assert_eq!(ast, AstNode::Boolean(true));
2095
2096 let ast = parse("false").unwrap();
2097 assert_eq!(ast, AstNode::Boolean(false));
2098 }
2099
2100 #[test]
2101 fn test_parse_null() {
2102 let ast = parse("null").unwrap();
2103 assert_eq!(ast, AstNode::Null);
2104 }
2105
2106 #[test]
2107 fn test_parse_variable() {
2108 let ast = parse("$var").unwrap();
2109 assert_eq!(ast, AstNode::Variable("var".to_string()));
2110 }
2111
2112 #[test]
2113 fn test_parse_identifier() {
2114 let ast = parse("foo").unwrap();
2115 assert_eq!(
2116 ast,
2117 AstNode::Path {
2118 steps: vec![PathStep::new(AstNode::Name("foo".to_string()))]
2119 }
2120 );
2121 }
2122
2123 #[test]
2124 fn test_parse_addition() {
2125 let ast = parse("1 + 2").unwrap();
2126 match ast {
2127 AstNode::Binary { op, lhs, rhs } => {
2128 assert_eq!(op, BinaryOp::Add);
2129 assert_eq!(*lhs, AstNode::Number(1.0));
2130 assert_eq!(*rhs, AstNode::Number(2.0));
2131 }
2132 _ => panic!("Expected Binary node"),
2133 }
2134 }
2135
2136 #[test]
2137 fn test_parse_precedence() {
2138 let ast = parse("1 + 2 * 3").unwrap();
2140 match ast {
2141 AstNode::Binary {
2142 op: BinaryOp::Add,
2143 lhs,
2144 rhs,
2145 } => {
2146 assert_eq!(*lhs, AstNode::Number(1.0));
2147 match *rhs {
2148 AstNode::Binary {
2149 op: BinaryOp::Multiply,
2150 lhs,
2151 rhs,
2152 } => {
2153 assert_eq!(*lhs, AstNode::Number(2.0));
2154 assert_eq!(*rhs, AstNode::Number(3.0));
2155 }
2156 _ => panic!("Expected Binary node for multiplication"),
2157 }
2158 }
2159 _ => panic!("Expected Binary node for addition"),
2160 }
2161 }
2162
2163 #[test]
2164 fn test_parse_parentheses() {
2165 let ast = parse("(1 + 2) * 3").unwrap();
2168 match ast {
2169 AstNode::Binary {
2170 op: BinaryOp::Multiply,
2171 lhs,
2172 rhs,
2173 } => {
2174 match *lhs {
2175 AstNode::Block(ref exprs) => {
2176 assert_eq!(exprs.len(), 1);
2177 match &exprs[0] {
2178 AstNode::Binary {
2179 op: BinaryOp::Add,
2180 lhs,
2181 rhs,
2182 } => {
2183 assert_eq!(**lhs, AstNode::Number(1.0));
2184 assert_eq!(**rhs, AstNode::Number(2.0));
2185 }
2186 _ => panic!("Expected Binary node for addition inside block"),
2187 }
2188 }
2189 _ => panic!(
2190 "Expected Block node for parenthesized expression, got {:?}",
2191 lhs
2192 ),
2193 }
2194 assert_eq!(*rhs, AstNode::Number(3.0));
2195 }
2196 _ => panic!("Expected Binary node for multiplication"),
2197 }
2198 }
2199
2200 #[test]
2201 fn test_parse_array() {
2202 let ast = parse("[1, 2, 3]").unwrap();
2203 match ast {
2204 AstNode::Array(elements) => {
2205 assert_eq!(elements.len(), 3);
2206 assert_eq!(elements[0], AstNode::Number(1.0));
2207 assert_eq!(elements[1], AstNode::Number(2.0));
2208 assert_eq!(elements[2], AstNode::Number(3.0));
2209 }
2210 _ => panic!("Expected Array node"),
2211 }
2212 }
2213
2214 #[test]
2215 fn test_parse_object() {
2216 let ast = parse(r#"{"a": 1, "b": 2}"#).unwrap();
2217 match ast {
2218 AstNode::Object(pairs) => {
2219 assert_eq!(pairs.len(), 2);
2220 assert_eq!(pairs[0].0, AstNode::String("a".to_string()));
2221 assert_eq!(pairs[0].1, AstNode::Number(1.0));
2222 assert_eq!(pairs[1].0, AstNode::String("b".to_string()));
2223 assert_eq!(pairs[1].1, AstNode::Number(2.0));
2224 }
2225 _ => panic!("Expected Object node"),
2226 }
2227 }
2228
2229 #[test]
2230 fn test_parse_path() {
2231 let ast = parse("foo.bar").unwrap();
2232 match ast {
2233 AstNode::Path { steps } => {
2234 assert_eq!(steps.len(), 2);
2235 assert_eq!(steps[0].node, AstNode::Name("foo".to_string()));
2236 assert_eq!(steps[1].node, AstNode::Name("bar".to_string()));
2237 }
2238 _ => panic!("Expected Path node"),
2239 }
2240 }
2241
2242 #[test]
2243 fn test_parse_function_call() {
2244 let ast = parse("sum(1, 2, 3)").unwrap();
2245 match ast {
2246 AstNode::Function {
2247 name,
2248 args,
2249 is_builtin,
2250 } => {
2251 assert_eq!(name, "sum");
2252 assert_eq!(args.len(), 3);
2253 assert_eq!(args[0], AstNode::Number(1.0));
2254 assert_eq!(args[1], AstNode::Number(2.0));
2255 assert_eq!(args[2], AstNode::Number(3.0));
2256 assert!(!is_builtin); }
2258 _ => panic!("Expected Function node"),
2259 }
2260 }
2261
2262 #[test]
2263 fn test_parse_conditional() {
2264 let ast = parse("x > 0 ? 1 : -1").unwrap();
2265 match ast {
2266 AstNode::Conditional {
2267 condition,
2268 then_branch,
2269 else_branch,
2270 } => {
2271 assert!(matches!(*condition, AstNode::Binary { .. }));
2272 assert_eq!(*then_branch, AstNode::Number(1.0));
2273 assert_eq!(
2275 else_branch,
2276 Some(Box::new(AstNode::Unary {
2277 op: UnaryOp::Negate,
2278 operand: Box::new(AstNode::Number(1.0)),
2279 }))
2280 );
2281 }
2282 _ => panic!("Expected Conditional node"),
2283 }
2284 }
2285
2286 #[test]
2287 fn test_parse_comparison() {
2288 let ast = parse("x < 10").unwrap();
2289 match ast {
2290 AstNode::Binary { op, .. } => {
2291 assert_eq!(op, BinaryOp::LessThan);
2292 }
2293 _ => panic!("Expected Binary node"),
2294 }
2295 }
2296
2297 #[test]
2298 fn test_parse_logical_and() {
2299 let ast = parse("true and false").unwrap();
2300 match ast {
2301 AstNode::Binary { op, lhs, rhs } => {
2302 assert_eq!(op, BinaryOp::And);
2303 assert_eq!(*lhs, AstNode::Boolean(true));
2304 assert_eq!(*rhs, AstNode::Boolean(false));
2305 }
2306 _ => panic!("Expected Binary node"),
2307 }
2308 }
2309
2310 #[test]
2311 fn test_parse_string_concatenation() {
2312 let ast = parse(r#""hello" & " " & "world""#).unwrap();
2313 match ast {
2314 AstNode::Binary { op, .. } => {
2315 assert_eq!(op, BinaryOp::Concatenate);
2316 }
2317 _ => panic!("Expected Binary node"),
2318 }
2319 }
2320
2321 #[test]
2322 fn test_parse_unary_minus() {
2323 let ast = parse("-5").unwrap();
2325 assert_eq!(
2326 ast,
2327 AstNode::Unary {
2328 op: UnaryOp::Negate,
2329 operand: Box::new(AstNode::Number(5.0)),
2330 }
2331 );
2332 }
2333
2334 #[test]
2335 fn test_parse_block() {
2336 let ast = parse("(1; 2; 3)").unwrap();
2337 match ast {
2338 AstNode::Block(expressions) => {
2339 assert_eq!(expressions.len(), 3);
2340 assert_eq!(expressions[0], AstNode::Number(1.0));
2341 assert_eq!(expressions[1], AstNode::Number(2.0));
2342 assert_eq!(expressions[2], AstNode::Number(3.0));
2343 }
2344 _ => panic!("Expected Block node"),
2345 }
2346 }
2347
2348 #[test]
2349 fn test_parse_complex_expression() {
2350 let ast = parse("(a + b) * c.d").unwrap();
2352 assert!(matches!(ast, AstNode::Binary { .. }));
2353 }
2354
2355 #[test]
2356 fn test_parse_dollar_function_call() {
2357 let ast = parse(r#"$uppercase("hello")"#).unwrap();
2359 match ast {
2360 AstNode::Function {
2361 name,
2362 args,
2363 is_builtin,
2364 } => {
2365 assert_eq!(name, "uppercase");
2366 assert_eq!(args.len(), 1);
2367 assert_eq!(args[0], AstNode::String("hello".to_string()));
2368 assert!(is_builtin); }
2370 _ => panic!("Expected Function node"),
2371 }
2372
2373 let ast = parse("$sum([1, 2, 3])").unwrap();
2375 match ast {
2376 AstNode::Function {
2377 name,
2378 args,
2379 is_builtin,
2380 } => {
2381 assert_eq!(name, "sum");
2382 assert_eq!(args.len(), 1);
2383 assert!(is_builtin); }
2385 _ => panic!("Expected Function node"),
2386 }
2387 }
2388
2389 #[test]
2390 fn test_parse_nested_dollar_functions() {
2391 let ast = parse(r#"$length($lowercase("HELLO"))"#).unwrap();
2393 match ast {
2394 AstNode::Function {
2395 name,
2396 args,
2397 is_builtin,
2398 } => {
2399 assert_eq!(name, "length");
2400 assert_eq!(args.len(), 1);
2401 assert!(is_builtin);
2402 match &args[0] {
2404 AstNode::Function {
2405 name: inner_name,
2406 is_builtin: inner_builtin,
2407 ..
2408 } => {
2409 assert_eq!(inner_name, "lowercase");
2410 assert!(inner_builtin);
2411 }
2412 _ => panic!("Expected nested Function node"),
2413 }
2414 }
2415 _ => panic!("Expected Function node"),
2416 }
2417 }
2418
2419 #[test]
2420 fn test_signature_with_repeat_modifier_parses() {
2421 let result = parse("λ($arg1, $arg2)<n+n:o>{{\"a\": $arg1, \"b\": $arg2}}(1, 2, 3)");
2425 assert!(
2426 result.is_ok(),
2427 "expected parse to succeed, got {:?}",
2428 result
2429 );
2430 }
2431
2432 #[test]
2433 fn test_parent_operator_parses_as_prefix() {
2434 let mut parser = Parser::new("%.OrderID".to_string()).unwrap();
2442 let ast = parser.parse().unwrap();
2443 match ast {
2445 AstNode::Path { steps } => {
2446 assert_eq!(steps.len(), 2);
2447 assert!(matches!(steps[0].node, AstNode::Parent(_)));
2448 assert!(matches!(steps[1].node, AstNode::Name(ref n) if n == "OrderID"));
2449 }
2450 other => panic!("expected Path, got {:?}", other),
2451 }
2452 }
2453
2454 #[test]
2455 fn test_percent_still_parses_as_modulo_infix() {
2456 let ast = parse("10 % 3").unwrap();
2458 assert!(matches!(
2459 ast,
2460 AstNode::Binary {
2461 op: BinaryOp::Modulo,
2462 ..
2463 }
2464 ));
2465 }
2466
2467 #[test]
2468 fn test_focus_bind_parses_as_binary_marker() {
2469 let mut parser = Parser::new("Order@$o".to_string()).unwrap();
2474 let ast = parser.parse().unwrap();
2475 match ast {
2476 AstNode::Binary {
2477 op: BinaryOp::FocusBind,
2478 lhs,
2479 rhs,
2480 } => {
2481 if let AstNode::Path { steps } = *lhs {
2483 assert_eq!(steps.len(), 1);
2484 assert!(matches!(steps[0].node, AstNode::Name(ref n) if n == "Order"));
2485 } else {
2486 panic!("expected lhs to be Path, got {:?}", lhs);
2487 }
2488 assert!(matches!(*rhs, AstNode::Variable(ref n) if n == "o"));
2489 }
2490 other => panic!("expected Binary{{FocusBind}}, got {:?}", other),
2491 }
2492 }
2493
2494 #[test]
2495 fn test_index_bind_parses_as_binary_marker() {
2496 let mut parser = Parser::new("arr#$i".to_string()).unwrap();
2499 let ast = parser.parse().unwrap();
2500 match ast {
2501 AstNode::Binary {
2502 op: BinaryOp::IndexBind,
2503 lhs,
2504 rhs,
2505 } => {
2506 if let AstNode::Path { steps } = *lhs {
2507 assert_eq!(steps.len(), 1);
2508 assert!(matches!(steps[0].node, AstNode::Name(ref n) if n == "arr"));
2509 } else {
2510 panic!("expected lhs to be Path, got {:?}", lhs);
2511 }
2512 assert!(matches!(*rhs, AstNode::Variable(ref n) if n == "i"));
2513 }
2514 other => panic!("expected Binary{{IndexBind}}, got {:?}", other),
2515 }
2516 }
2517
2518 #[test]
2519 fn test_focus_bind_requires_variable_rhs() {
2520 let err = parse("Order@foo").unwrap_err();
2522 assert!(err.to_string().starts_with("S0214"));
2523 }
2524}