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
670const PARSER_RED_ZONE: usize = 128 * 1024;
677const PARSER_GROW_STACK_SIZE: usize = 8 * 1024 * 1024;
678
679const MAX_PARSE_DEPTH: usize = 1000;
692
693pub struct Parser {
695 lexer: Lexer,
696 current_token: Token,
697 depth: usize,
707}
708
709impl Parser {
710 pub fn new(input: String) -> Result<Self, ParserError> {
711 let mut lexer = Lexer::new(input);
712 let current_token = lexer.next_token()?;
713 Ok(Parser {
714 lexer,
715 current_token,
716 depth: 0,
717 })
718 }
719
720 fn advance(&mut self) -> Result<(), ParserError> {
721 self.current_token = self.lexer.next_token()?;
722 Ok(())
723 }
724
725 fn expect(&mut self, expected: Token) -> Result<(), ParserError> {
726 if std::mem::discriminant(&self.current_token) == std::mem::discriminant(&expected) {
727 self.advance()?;
728 Ok(())
729 } else {
730 Err(ParserError::Expected {
731 expected: format!("{:?}", expected),
732 found: format!("{:?}", self.current_token),
733 })
734 }
735 }
736
737 fn binding_power(&self, token: &Token) -> Option<(u8, u8)> {
739 match token {
742 Token::Identifier(name) if name == "or" => Some((25, 26)),
744 Token::Identifier(name) if name == "and" => Some((30, 31)),
745 Token::Identifier(name) if name == "in" => Some((40, 41)),
746 Token::Or => Some((25, 26)),
748 Token::And => Some((30, 31)),
749 Token::Equal
750 | Token::NotEqual
751 | Token::LessThan
752 | Token::LessThanOrEqual
753 | Token::GreaterThan
754 | Token::GreaterThanOrEqual
755 | Token::In => Some((40, 41)),
756 Token::Ampersand => Some((50, 51)),
757 Token::Plus | Token::Minus => Some((50, 51)),
758 Token::Star | Token::Slash | Token::Percent => Some((60, 61)),
759 Token::Dot => Some((75, 85)), Token::LeftBracket => Some((80, 81)),
761 Token::LeftParen => Some((80, 81)),
762 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)),
767 Token::QuestionQuestion => Some((15, 16)), Token::QuestionColon => Some((15, 16)), Token::DotDot => Some((20, 21)),
770 Token::ColonEqual => Some((10, 9)), Token::TildeArrow => Some((70, 71)), _ => None,
773 }
774 }
775
776 fn parse_signature(&mut self) -> Result<String, ParserError> {
778 if self.current_token != Token::LessThan {
780 return Err(ParserError::Expected {
781 expected: "<".to_string(),
782 found: format!("{:?}", self.current_token),
783 });
784 }
785
786 let mut signature = String::from("<");
788 self.advance()?; let mut depth = 1;
793
794 while depth > 0 && self.current_token != Token::Eof {
795 match &self.current_token {
796 Token::LessThan => {
797 signature.push('<');
798 depth += 1;
799 self.advance()?;
800 }
801 Token::GreaterThan => {
802 depth -= 1;
803 if depth > 0 {
804 signature.push('>');
805 }
806 self.advance()?;
807 }
808 Token::Minus => {
809 signature.push('-');
810 self.advance()?;
811 }
812 Token::Plus => {
813 signature.push('+');
814 self.advance()?;
815 }
816 Token::Colon => {
817 signature.push(':');
818 self.advance()?;
819 }
820 Token::Question => {
821 signature.push('?');
822 self.advance()?;
823 }
824 Token::QuestionColon => {
825 signature.push('?');
827 signature.push(':');
828 self.advance()?;
829 }
830 Token::Identifier(s) => {
831 signature.push_str(s);
832 self.advance()?;
833 }
834 Token::LeftParen | Token::RightParen => {
835 let c = if self.current_token == Token::LeftParen {
837 '('
838 } else {
839 ')'
840 };
841 signature.push(c);
842 self.advance()?;
843 }
844 _ => {
845 return Err(ParserError::UnexpectedToken(format!(
846 "Unexpected token in signature: {:?}",
847 self.current_token
848 )));
849 }
850 }
851 }
852
853 signature.push('>');
854 Ok(signature)
855 }
856
857 fn parse_primary(&mut self) -> Result<AstNode, ParserError> {
859 match &self.current_token {
860 Token::String(s) => {
861 let value = s.clone();
862 self.advance()?;
863 Ok(AstNode::String(value))
864 }
865 Token::Number(n) => {
866 let value = *n;
867 self.advance()?;
868 Ok(AstNode::Number(value))
869 }
870 Token::True => {
871 self.advance()?;
872 Ok(AstNode::Boolean(true))
873 }
874 Token::False => {
875 self.advance()?;
876 Ok(AstNode::Boolean(false))
877 }
878 Token::Null => {
879 self.advance()?;
880 Ok(AstNode::Null)
881 }
882 Token::Undefined => {
883 self.advance()?;
884 Ok(AstNode::Undefined)
885 }
886 Token::Regex { pattern, flags } => {
887 let pat = pattern.clone();
888 let flg = flags.clone();
889 self.advance()?;
890 Ok(AstNode::Regex {
891 pattern: pat,
892 flags: flg,
893 })
894 }
895 Token::Identifier(name) => {
896 let name = name.clone();
897 self.advance()?;
898 Ok(AstNode::Path {
899 steps: vec![PathStep::new(AstNode::Name(name))],
900 })
901 }
902 Token::Variable(name) => {
903 let name = name.clone();
904 self.advance()?;
905 Ok(AstNode::Variable(name))
906 }
907 Token::ParentVariable(name) => {
908 let name = name.clone();
909 self.advance()?;
910 Ok(AstNode::ParentVariable(name))
911 }
912 Token::LeftParen => {
913 self.advance()?; if self.current_token == Token::RightParen {
917 self.advance()?;
918 return Ok(AstNode::Undefined);
919 }
920
921 let mut expressions = vec![self.parse_expression(0)?];
925
926 while self.current_token == Token::Semicolon {
927 self.advance()?;
928 if self.current_token == Token::RightParen {
929 break;
930 }
931 expressions.push(self.parse_expression(0)?);
932 }
933
934 self.expect(Token::RightParen)?;
935
936 Ok(AstNode::Block(expressions))
938 }
939 Token::LeftBracket => {
940 self.advance()?; let mut elements = Vec::new();
943
944 if self.current_token != Token::RightBracket {
945 loop {
946 let element = self.parse_expression(0)?;
947 elements.push(element);
948
949 if self.current_token != Token::Comma {
950 break;
951 }
952 self.advance()?;
953 }
954 }
955
956 self.expect(Token::RightBracket)?;
957 Ok(AstNode::Array(elements))
958 }
959 Token::LeftBrace => {
960 self.advance()?; let mut pairs = Vec::new();
963
964 if self.current_token != Token::RightBrace {
965 loop {
966 let key = self.parse_expression(0)?;
967 self.expect(Token::Colon)?;
968 let value = self.parse_expression(0)?;
969 pairs.push((key, value));
970
971 if self.current_token != Token::Comma {
972 break;
973 }
974 self.advance()?;
975 }
976 }
977
978 self.expect(Token::RightBrace)?;
979 Ok(AstNode::Object(pairs))
980 }
981 Token::Pipe => {
982 self.advance()?; let location = self.parse_expression(0)?;
987
988 self.expect(Token::Pipe)?;
990
991 let update = self.parse_expression(0)?;
993
994 let delete = if self.current_token == Token::Comma {
996 self.advance()?; Some(Box::new(self.parse_expression(0)?))
998 } else {
999 None
1000 };
1001
1002 self.expect(Token::Pipe)?;
1004
1005 Ok(AstNode::Transform {
1006 location: Box::new(location),
1007 update: Box::new(update),
1008 delete,
1009 })
1010 }
1011 Token::Minus => {
1012 self.advance()?;
1013 let operand = self.parse_expression(70)?; Ok(AstNode::Unary {
1015 op: UnaryOp::Negate,
1016 operand: Box::new(operand),
1017 })
1018 }
1019 Token::Star => {
1020 self.advance()?;
1022 Ok(AstNode::Wildcard)
1023 }
1024 Token::StarStar => {
1025 self.advance()?;
1027 Ok(AstNode::Descendant)
1028 }
1029 Token::Percent => {
1030 self.advance()?;
1035 Ok(AstNode::Parent(String::new()))
1036 }
1037 Token::Function => {
1038 self.advance()?; self.expect(Token::LeftParen)?;
1041
1042 let mut params = Vec::new();
1044 if self.current_token != Token::RightParen {
1045 loop {
1046 match &self.current_token {
1047 Token::Variable(name) => {
1048 params.push(name.clone());
1049 self.advance()?;
1050 }
1051 _ => {
1052 return Err(ParserError::Expected {
1053 expected: "parameter name".to_string(),
1054 found: format!("{:?}", self.current_token),
1055 })
1056 }
1057 }
1058
1059 if self.current_token != Token::Comma {
1060 break;
1061 }
1062 self.advance()?; }
1064 }
1065
1066 self.expect(Token::RightParen)?;
1067
1068 let signature = if self.current_token == Token::LessThan {
1070 Some(self.parse_signature()?)
1071 } else {
1072 None
1073 };
1074
1075 self.expect(Token::LeftBrace)?;
1076
1077 let body = self.parse_expression(0)?;
1079
1080 self.expect(Token::RightBrace)?;
1081
1082 let (optimized_body, is_thunk) = Self::tail_call_optimize(body);
1084
1085 Ok(AstNode::Lambda {
1086 params,
1087 body: Box::new(optimized_body),
1088 signature,
1089 thunk: is_thunk,
1090 })
1091 }
1092 _ => Err(ParserError::UnexpectedToken(format!(
1093 "{:?}",
1094 self.current_token
1095 ))),
1096 }
1097 }
1098
1099 fn bump_parse_depth(&mut self) -> Result<(), ParserError> {
1109 self.depth += 1;
1110 if self.depth > MAX_PARSE_DEPTH {
1111 return Err(ParserError::Coded {
1112 code: "U1002",
1113 message: format!(
1114 "Stack overflow - maximum expression nesting depth ({}) exceeded while parsing expression",
1115 MAX_PARSE_DEPTH
1116 ),
1117 });
1118 }
1119 Ok(())
1120 }
1121
1122 fn parse_expression(&mut self, min_bp: u8) -> Result<AstNode, ParserError> {
1137 let entry_depth = self.depth;
1138 self.bump_parse_depth()?;
1139
1140 let result = stacker::maybe_grow(PARSER_RED_ZONE, PARSER_GROW_STACK_SIZE, || {
1141 self.parse_expression_impl(min_bp)
1142 });
1143
1144 self.depth = entry_depth;
1145 result
1146 }
1147
1148 fn parse_expression_impl(&mut self, min_bp: u8) -> Result<AstNode, ParserError> {
1149 let mut lhs = self.parse_primary()?;
1150
1151 loop {
1152 if matches!(
1154 self.current_token,
1155 Token::Eof
1156 | Token::RightParen
1157 | Token::RightBracket
1158 | Token::RightBrace
1159 | Token::Comma
1160 | Token::Semicolon
1161 | Token::Colon
1162 ) {
1163 break;
1164 }
1165
1166 let (left_bp, right_bp) = match self.binding_power(&self.current_token) {
1168 Some(bp) => bp,
1169 None => break,
1170 };
1171
1172 if left_bp < min_bp {
1173 break;
1174 }
1175
1176 match &self.current_token {
1178 Token::Dot => {
1179 self.advance()?;
1180
1181 if self.current_token == Token::LeftBracket {
1183 self.advance()?;
1184
1185 let mut elements = Vec::new();
1187 if self.current_token != Token::RightBracket {
1188 loop {
1189 elements.push(self.parse_expression(0)?);
1190 if self.current_token != Token::Comma {
1191 break;
1192 }
1193 self.advance()?;
1194 }
1195 }
1196
1197 self.expect(Token::RightBracket)?;
1198
1199 let mut steps = match lhs {
1201 AstNode::Path { steps } => steps,
1202 _ => vec![PathStep::new(lhs)],
1203 };
1204
1205 steps.push(PathStep::new(AstNode::ArrayGroup(elements)));
1206 self.bump_parse_depth()?;
1207 lhs = AstNode::Path { steps };
1208 } else if self.current_token == Token::LeftParen {
1209 self.advance()?;
1211
1212 if self.current_token == Token::RightParen {
1218 self.advance()?;
1219 let mut steps = match lhs {
1220 AstNode::Path { steps } => steps,
1221 _ => vec![PathStep::new(lhs)],
1222 };
1223 steps.push(PathStep::new(AstNode::FunctionApplication(Box::new(
1224 AstNode::Block(Vec::new()),
1225 ))));
1226 self.bump_parse_depth()?;
1227 lhs = AstNode::Path { steps };
1228 continue;
1229 }
1230
1231 let mut expressions = vec![self.parse_expression(0)?];
1233
1234 while self.current_token == Token::Semicolon {
1235 self.advance()?;
1236 if self.current_token == Token::RightParen {
1237 break;
1238 }
1239 expressions.push(self.parse_expression(0)?);
1240 }
1241
1242 self.expect(Token::RightParen)?;
1243
1244 let expr = if expressions.len() == 1 {
1246 expressions.into_iter().next().unwrap()
1247 } else {
1248 AstNode::Block(expressions)
1249 };
1250
1251 let mut steps = match lhs {
1253 AstNode::Path { steps } => steps,
1254 _ => vec![PathStep::new(lhs)],
1255 };
1256
1257 steps.push(PathStep::new(AstNode::FunctionApplication(Box::new(expr))));
1258 self.bump_parse_depth()?;
1259 lhs = AstNode::Path { steps };
1260 } else {
1261 let rhs = self.parse_expression(right_bp)?;
1263
1264 let mut steps = match lhs {
1266 AstNode::Path { steps } => steps,
1267 AstNode::String(field_name) => {
1270 vec![PathStep::new(AstNode::Name(field_name))]
1271 }
1272 _ => vec![PathStep::new(lhs)],
1273 };
1274
1275 match &rhs {
1278 AstNode::Number(n) => {
1279 return Err(ParserError::InvalidSyntax(
1280 format!("S0213: The literal value {} cannot be used as a step within a path expression", n),
1281 ));
1282 }
1283 AstNode::Boolean(b) => {
1284 return Err(ParserError::InvalidSyntax(
1285 format!("S0213: The literal value {} cannot be used as a step within a path expression", b),
1286 ));
1287 }
1288 AstNode::Null => {
1289 return Err(ParserError::InvalidSyntax(
1290 "S0213: The literal value null cannot be used as a step within a path expression".to_string(),
1291 ));
1292 }
1293 _ => {}
1294 }
1295
1296 match rhs {
1297 AstNode::Path {
1298 steps: mut rhs_steps,
1299 } => {
1300 steps.append(&mut rhs_steps);
1301 }
1302 AstNode::String(field_name) => {
1305 steps.push(PathStep::new(AstNode::Name(field_name)));
1306 }
1307 _ => steps.push(PathStep::new(rhs)),
1308 }
1309
1310 while self.current_token == Token::LeftBracket {
1313 self.advance()?;
1314
1315 let predicate_expr = if self.current_token == Token::RightBracket {
1316 Box::new(AstNode::Boolean(true))
1318 } else {
1319 let pred = self.parse_expression(0)?;
1321 Box::new(pred)
1322 };
1323
1324 self.expect(Token::RightBracket)?;
1325
1326 if let Some(last_step) = steps.last_mut() {
1328 last_step.stages.push(Stage::Filter(predicate_expr));
1329 }
1330 }
1331
1332 self.bump_parse_depth()?;
1333 lhs = AstNode::Path { steps };
1334 }
1335 }
1336 Token::LeftBracket => {
1337 if matches!(lhs, AstNode::ObjectTransform { .. }) {
1340 return Err(ParserError::InvalidSyntax(
1341 "S0209: A predicate cannot follow a grouping expression in a step"
1342 .to_string(),
1343 ));
1344 }
1345
1346 self.advance()?;
1347
1348 if self.current_token == Token::RightBracket {
1351 self.advance()?;
1353
1354 let mut steps = match lhs {
1355 AstNode::Path { steps } => steps,
1356 _ => vec![PathStep::new(lhs)],
1357 };
1358
1359 steps.push(PathStep::new(AstNode::Predicate(Box::new(
1360 AstNode::Boolean(true),
1361 ))));
1362 self.bump_parse_depth()?;
1363 lhs = AstNode::Path { steps };
1364 } else {
1365 let predicate = self.parse_expression(0)?;
1367 self.expect(Token::RightBracket)?;
1368
1369 let mut steps = match lhs {
1370 AstNode::Path { steps } => steps,
1371 _ => vec![PathStep::new(lhs)],
1372 };
1373
1374 steps.push(PathStep::new(AstNode::Predicate(Box::new(predicate))));
1375 self.bump_parse_depth()?;
1376 lhs = AstNode::Path { steps };
1377 }
1378 }
1379 Token::LeftParen => {
1380 self.advance()?;
1381
1382 let mut args = Vec::new();
1383
1384 if self.current_token != Token::RightParen {
1385 loop {
1386 if self.current_token == Token::Question {
1388 args.push(AstNode::Placeholder);
1389 self.advance()?;
1390 } else {
1391 args.push(self.parse_expression(0)?);
1392 }
1393
1394 if self.current_token != Token::Comma {
1395 break;
1396 }
1397 self.advance()?;
1398 }
1399 }
1400
1401 self.expect(Token::RightParen)?;
1402
1403 match lhs {
1405 AstNode::Lambda { .. }
1407 | AstNode::Block(_)
1408 | AstNode::Call { .. }
1409 | AstNode::Function { .. } => {
1410 self.bump_parse_depth()?;
1411 lhs = AstNode::Call {
1412 procedure: Box::new(lhs),
1413 args,
1414 };
1415 }
1416 ref other_lhs => {
1417 match other_lhs {
1419 AstNode::Path { steps } if steps.len() == 1 => {
1421 let name = match &steps[0].node {
1422 AstNode::Name(s) => s.clone(),
1423 _ => {
1424 return Err(ParserError::InvalidSyntax(
1425 "Invalid function name".to_string(),
1426 ))
1427 }
1428 };
1429 self.bump_parse_depth()?;
1430 lhs = AstNode::Function {
1431 name,
1432 args,
1433 is_builtin: false,
1434 };
1435 }
1436 AstNode::Path { steps } if steps.len() > 1 => {
1438 let last_step = &steps[steps.len() - 1].node;
1439
1440 if let AstNode::Variable(func_name) = last_step {
1442 let mut context_steps = steps.clone();
1444 context_steps.pop();
1445
1446 let func_call = AstNode::Function {
1448 name: func_name.clone(),
1449 args: args.clone(),
1450 is_builtin: true, };
1452
1453 context_steps.push(PathStep::new(
1455 AstNode::FunctionApplication(Box::new(func_call)),
1456 ));
1457
1458 self.bump_parse_depth()?;
1459 lhs = AstNode::Path {
1460 steps: context_steps,
1461 };
1462 }
1463 else if let AstNode::Lambda {
1465 params,
1466 body,
1467 signature,
1468 thunk,
1469 } = last_step
1470 {
1471 let mut context_steps = steps.clone();
1473 context_steps.pop();
1474
1475 let full_args = if args.len() < params.len() {
1479 let mut new_args =
1480 vec![AstNode::Variable("$".to_string())];
1481 new_args.extend(args.clone());
1482 new_args
1483 } else {
1484 args.clone()
1485 };
1486
1487 let lambda_invocation = AstNode::Block(vec![
1490 AstNode::Binary {
1491 op: crate::ast::BinaryOp::ColonEqual,
1492 lhs: Box::new(AstNode::Variable(
1493 "__path_lambda__".to_string(),
1494 )),
1495 rhs: Box::new(AstNode::Lambda {
1496 params: params.clone(),
1497 body: body.clone(),
1498 signature: signature.clone(),
1499 thunk: *thunk,
1500 }),
1501 },
1502 AstNode::Function {
1503 name: "__path_lambda__".to_string(),
1504 args: full_args,
1505 is_builtin: true,
1506 },
1507 ]);
1508
1509 context_steps.push(PathStep::new(
1511 AstNode::FunctionApplication(Box::new(
1512 lambda_invocation,
1513 )),
1514 ));
1515
1516 self.bump_parse_depth()?;
1517 lhs = AstNode::Path {
1518 steps: context_steps,
1519 };
1520 } else {
1521 return Err(ParserError::InvalidSyntax(
1522 "Invalid function call".to_string(),
1523 ));
1524 }
1525 }
1526 AstNode::Variable(name) => {
1528 self.bump_parse_depth()?;
1529 lhs = AstNode::Function {
1530 name: name.clone(),
1531 args,
1532 is_builtin: true,
1533 };
1534 }
1535 _ => {
1536 return Err(ParserError::InvalidSyntax(
1537 "Invalid function call".to_string(),
1538 ))
1539 }
1540 };
1541 }
1542 }
1543 }
1544 Token::Question => {
1545 self.advance()?;
1546 let then_branch = self.parse_expression(0)?;
1547
1548 let else_branch = if self.current_token == Token::Colon {
1549 self.advance()?;
1550 Some(Box::new(self.parse_expression(0)?))
1552 } else {
1553 None
1554 };
1555
1556 self.bump_parse_depth()?;
1557 lhs = AstNode::Conditional {
1558 condition: Box::new(lhs),
1559 then_branch: Box::new(then_branch),
1560 else_branch,
1561 };
1562 }
1563 Token::LeftBrace => {
1564 if matches!(lhs, AstNode::ObjectTransform { .. }) {
1567 return Err(ParserError::InvalidSyntax(
1568 "S0210: Each step can only have one grouping expression".to_string(),
1569 ));
1570 }
1571
1572 self.advance()?; let mut pairs = Vec::new();
1576
1577 if self.current_token != Token::RightBrace {
1578 loop {
1579 let key = self.parse_expression(0)?;
1581
1582 self.expect(Token::Colon)?;
1583
1584 let value = self.parse_expression(0)?;
1586
1587 pairs.push((key, value));
1588
1589 if self.current_token != Token::Comma {
1590 break;
1591 }
1592 self.advance()?; }
1594 }
1595
1596 self.expect(Token::RightBrace)?;
1597
1598 self.bump_parse_depth()?;
1600 lhs = AstNode::ObjectTransform {
1601 input: Box::new(lhs),
1602 pattern: pairs,
1603 };
1604 }
1605 Token::Hash => {
1606 self.advance()?; let var_name = match &self.current_token {
1614 Token::Variable(name) => name.clone(),
1615 _ => {
1616 return Err(ParserError::Coded {
1617 code: "S0214",
1618 message: "Expected a variable reference after #".to_string(),
1619 });
1620 }
1621 };
1622 self.advance()?; self.bump_parse_depth()?;
1631 lhs = AstNode::Binary {
1632 op: BinaryOp::IndexBind,
1633 lhs: Box::new(lhs),
1634 rhs: Box::new(AstNode::Variable(var_name)),
1635 };
1636 }
1637 Token::At => {
1638 self.advance()?; let var_name = match &self.current_token {
1646 Token::Variable(name) => name.clone(),
1647 _ => {
1648 return Err(ParserError::Coded {
1649 code: "S0214",
1650 message: "Expected a variable reference after @".to_string(),
1651 });
1652 }
1653 };
1654 self.advance()?; self.bump_parse_depth()?;
1657 lhs = AstNode::Binary {
1658 op: BinaryOp::FocusBind,
1659 lhs: Box::new(lhs),
1660 rhs: Box::new(AstNode::Variable(var_name)),
1661 };
1662 }
1663 Token::Caret => {
1664 self.advance()?; self.expect(Token::LeftParen)?;
1667
1668 let mut terms = Vec::new();
1669
1670 loop {
1671 let ascending = match &self.current_token {
1673 Token::LessThan => {
1674 self.advance()?;
1675 true
1676 }
1677 Token::GreaterThan => {
1678 self.advance()?;
1679 false
1680 }
1681 _ => true, };
1683
1684 let expr = self.parse_expression(0)?;
1686 terms.push((expr, ascending));
1687
1688 if self.current_token != Token::Comma {
1690 break;
1691 }
1692 self.advance()?; }
1694
1695 self.expect(Token::RightParen)?;
1696
1697 self.bump_parse_depth()?;
1698 lhs = AstNode::Sort {
1699 input: Box::new(lhs),
1700 terms,
1701 };
1702 }
1703 _ => {
1704 let op = match &self.current_token {
1706 Token::Identifier(name) if name == "and" => BinaryOp::And,
1708 Token::Identifier(name) if name == "or" => BinaryOp::Or,
1709 Token::Identifier(name) if name == "in" => BinaryOp::In,
1710 Token::Plus => BinaryOp::Add,
1712 Token::Minus => BinaryOp::Subtract,
1713 Token::Star => BinaryOp::Multiply,
1714 Token::Slash => BinaryOp::Divide,
1715 Token::Percent => BinaryOp::Modulo,
1716 Token::Equal => BinaryOp::Equal,
1717 Token::NotEqual => BinaryOp::NotEqual,
1718 Token::LessThan => BinaryOp::LessThan,
1719 Token::LessThanOrEqual => BinaryOp::LessThanOrEqual,
1720 Token::GreaterThan => BinaryOp::GreaterThan,
1721 Token::GreaterThanOrEqual => BinaryOp::GreaterThanOrEqual,
1722 Token::And => BinaryOp::And,
1723 Token::Or => BinaryOp::Or,
1724 Token::In => BinaryOp::In,
1725 Token::Ampersand => BinaryOp::Concatenate,
1726 Token::DotDot => BinaryOp::Range,
1727 Token::ColonEqual => BinaryOp::ColonEqual,
1728 Token::QuestionQuestion => BinaryOp::Coalesce,
1729 Token::QuestionColon => BinaryOp::Default,
1730 Token::TildeArrow => BinaryOp::ChainPipe,
1731 _ => {
1732 return Err(ParserError::UnexpectedToken(format!(
1733 "{:?}",
1734 self.current_token
1735 )))
1736 }
1737 };
1738
1739 self.advance()?;
1740 let rhs = self.parse_expression(right_bp)?;
1741
1742 self.bump_parse_depth()?;
1743 lhs = AstNode::Binary {
1744 op,
1745 lhs: Box::new(lhs),
1746 rhs: Box::new(rhs),
1747 };
1748 }
1749 }
1750 }
1751
1752 Ok(lhs)
1753 }
1754
1755 pub fn parse(&mut self) -> Result<AstNode, ParserError> {
1756 let ast = self.parse_expression(0)?;
1757
1758 if self.current_token != Token::Eof {
1759 return Err(ParserError::Expected {
1760 expected: "end of expression".to_string(),
1761 found: format!("{:?}", self.current_token),
1762 });
1763 }
1764
1765 Ok(ast)
1766 }
1767
1768 fn tail_call_optimize(expr: AstNode) -> (AstNode, bool) {
1778 let is_thunk = Self::is_tail_call(&expr);
1779 (expr, is_thunk)
1780 }
1781
1782 fn is_tail_call(expr: &AstNode) -> bool {
1785 match expr {
1786 AstNode::Function { .. } => true,
1788 AstNode::Call { .. } => true,
1789
1790 AstNode::Conditional {
1792 then_branch,
1793 else_branch,
1794 ..
1795 } => {
1796 let then_is_tail = Self::is_tail_call(then_branch);
1797 let else_is_tail = else_branch.as_ref().is_some_and(|e| Self::is_tail_call(e));
1798 then_is_tail || else_is_tail
1800 }
1801
1802 AstNode::Block(exprs) => exprs.last().is_some_and(Self::is_tail_call),
1804
1805 AstNode::Binary {
1807 op: BinaryOp::ColonEqual,
1808 rhs,
1809 ..
1810 } => {
1811 Self::is_tail_call(rhs)
1815 }
1816
1817 _ => false,
1819 }
1820 }
1821}
1822
1823pub fn parse(expression: &str) -> Result<AstNode, ParserError> {
1830 let mut parser = Parser::new(expression.to_string())?;
1831 let raw_ast = parser.parse()?;
1832 crate::ast_transform::resolve_ancestry(raw_ast).map_err(|e| match e {
1833 crate::ast_transform::AstTransformError::Coded { code, message } => {
1834 ParserError::Coded { code, message }
1835 }
1836 })
1837}
1838
1839#[cfg(test)]
1840mod tests {
1841 use super::*;
1842
1843 #[test]
1845 fn test_lexer_numbers() {
1846 let mut lexer = Lexer::new("42 3.14 -10 2.5e10 1E-5".to_string());
1847
1848 assert_eq!(lexer.next_token().unwrap(), Token::Number(42.0));
1849 assert_eq!(lexer.next_token().unwrap(), Token::Number(3.14));
1850 assert_eq!(lexer.next_token().unwrap(), Token::Minus);
1852 assert_eq!(lexer.next_token().unwrap(), Token::Number(10.0));
1853 assert_eq!(lexer.next_token().unwrap(), Token::Number(2.5e10));
1854 assert_eq!(lexer.next_token().unwrap(), Token::Number(1e-5));
1855 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1856 }
1857
1858 #[test]
1859 fn test_lexer_strings() {
1860 let mut lexer = Lexer::new(r#""hello" 'world' "with\nnewline""#.to_string());
1861
1862 assert_eq!(
1863 lexer.next_token().unwrap(),
1864 Token::String("hello".to_string())
1865 );
1866 assert_eq!(
1867 lexer.next_token().unwrap(),
1868 Token::String("world".to_string())
1869 );
1870 assert_eq!(
1871 lexer.next_token().unwrap(),
1872 Token::String("with\nnewline".to_string())
1873 );
1874 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1875 }
1876
1877 #[test]
1878 fn test_lexer_string_escapes() {
1879 let mut lexer = Lexer::new(r#""a\"b\\c\/d""#.to_string());
1880 assert_eq!(
1881 lexer.next_token().unwrap(),
1882 Token::String("a\"b\\c/d".to_string())
1883 );
1884 }
1885
1886 #[test]
1887 fn test_lexer_keywords() {
1888 let mut lexer = Lexer::new("true false null and or in".to_string());
1889
1890 assert_eq!(lexer.next_token().unwrap(), Token::True);
1891 assert_eq!(lexer.next_token().unwrap(), Token::False);
1892 assert_eq!(lexer.next_token().unwrap(), Token::Null);
1893 assert_eq!(
1895 lexer.next_token().unwrap(),
1896 Token::Identifier("and".to_string())
1897 );
1898 assert_eq!(
1899 lexer.next_token().unwrap(),
1900 Token::Identifier("or".to_string())
1901 );
1902 assert_eq!(
1903 lexer.next_token().unwrap(),
1904 Token::Identifier("in".to_string())
1905 );
1906 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1907 }
1908
1909 #[test]
1910 fn test_lexer_identifiers() {
1911 let mut lexer = Lexer::new("foo bar_baz test123".to_string());
1912
1913 assert_eq!(
1914 lexer.next_token().unwrap(),
1915 Token::Identifier("foo".to_string())
1916 );
1917 assert_eq!(
1918 lexer.next_token().unwrap(),
1919 Token::Identifier("bar_baz".to_string())
1920 );
1921 assert_eq!(
1922 lexer.next_token().unwrap(),
1923 Token::Identifier("test123".to_string())
1924 );
1925 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1926 }
1927
1928 #[test]
1929 fn test_lexer_variables() {
1930 let mut lexer = Lexer::new("$var $foo_bar".to_string());
1931
1932 assert_eq!(
1933 lexer.next_token().unwrap(),
1934 Token::Variable("var".to_string())
1935 );
1936 assert_eq!(
1937 lexer.next_token().unwrap(),
1938 Token::Variable("foo_bar".to_string())
1939 );
1940 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1941 }
1942
1943 #[test]
1944 fn test_lexer_operators() {
1945 let mut lexer = Lexer::new("+ - * % = != < <= > >= & . .. := ".to_string());
1947
1948 assert_eq!(lexer.next_token().unwrap(), Token::Plus);
1949 assert_eq!(lexer.next_token().unwrap(), Token::Minus);
1950 assert_eq!(lexer.next_token().unwrap(), Token::Star);
1951 assert_eq!(lexer.next_token().unwrap(), Token::Percent);
1952 assert_eq!(lexer.next_token().unwrap(), Token::Equal);
1953 assert_eq!(lexer.next_token().unwrap(), Token::NotEqual);
1954 assert_eq!(lexer.next_token().unwrap(), Token::LessThan);
1955 assert_eq!(lexer.next_token().unwrap(), Token::LessThanOrEqual);
1956 assert_eq!(lexer.next_token().unwrap(), Token::GreaterThan);
1957 assert_eq!(lexer.next_token().unwrap(), Token::GreaterThanOrEqual);
1958 assert_eq!(lexer.next_token().unwrap(), Token::Ampersand);
1959 assert_eq!(lexer.next_token().unwrap(), Token::Dot);
1960 assert_eq!(lexer.next_token().unwrap(), Token::DotDot);
1961 assert_eq!(lexer.next_token().unwrap(), Token::ColonEqual);
1962 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1963
1964 let mut lexer2 = Lexer::new("42 / 2".to_string());
1967 assert_eq!(lexer2.next_token().unwrap(), Token::Number(42.0));
1968 assert_eq!(lexer2.next_token().unwrap(), Token::Slash);
1969 assert_eq!(lexer2.next_token().unwrap(), Token::Number(2.0));
1970 assert_eq!(lexer2.next_token().unwrap(), Token::Eof);
1971 }
1972
1973 #[test]
1974 fn test_lexer_delimiters() {
1975 let mut lexer = Lexer::new("()[]{},:;?".to_string());
1976
1977 assert_eq!(lexer.next_token().unwrap(), Token::LeftParen);
1978 assert_eq!(lexer.next_token().unwrap(), Token::RightParen);
1979 assert_eq!(lexer.next_token().unwrap(), Token::LeftBracket);
1980 assert_eq!(lexer.next_token().unwrap(), Token::RightBracket);
1981 assert_eq!(lexer.next_token().unwrap(), Token::LeftBrace);
1982 assert_eq!(lexer.next_token().unwrap(), Token::RightBrace);
1983 assert_eq!(lexer.next_token().unwrap(), Token::Comma);
1984 assert_eq!(lexer.next_token().unwrap(), Token::Colon);
1985 assert_eq!(lexer.next_token().unwrap(), Token::Semicolon);
1986 assert_eq!(lexer.next_token().unwrap(), Token::Question);
1987 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
1988 }
1989
1990 #[test]
1991 fn test_empty_brackets() {
1992 let mut parser = Parser::new("foo[]".to_string()).unwrap();
1993 let ast = parser.parse().unwrap();
1994
1995 if let AstNode::Path { steps } = ast {
1997 assert_eq!(steps.len(), 2);
1998 assert!(matches!(steps[0].node, AstNode::Name(ref s) if s == "foo"));
1999 if let AstNode::Predicate(pred) = &steps[1].node {
2000 assert!(matches!(**pred, AstNode::Boolean(true)));
2001 } else {
2002 panic!("Expected Predicate as second step, got {:?}", steps[1].node);
2003 }
2004 } else {
2005 panic!("Expected Path, got {:?}", ast);
2006 }
2007 }
2008
2009 #[test]
2010 fn test_lexer_comments() {
2011 let mut lexer = Lexer::new("foo /* comment */ bar".to_string());
2012
2013 assert_eq!(
2014 lexer.next_token().unwrap(),
2015 Token::Identifier("foo".to_string())
2016 );
2017 assert_eq!(
2018 lexer.next_token().unwrap(),
2019 Token::Identifier("bar".to_string())
2020 );
2021 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
2022 }
2023
2024 #[test]
2025 fn test_lexer_backtick_names() {
2026 let mut lexer = Lexer::new("`field name` `with-dash`".to_string());
2027
2028 assert_eq!(
2029 lexer.next_token().unwrap(),
2030 Token::Identifier("field name".to_string())
2031 );
2032 assert_eq!(
2033 lexer.next_token().unwrap(),
2034 Token::Identifier("with-dash".to_string())
2035 );
2036 assert_eq!(lexer.next_token().unwrap(), Token::Eof);
2037 }
2038
2039 #[test]
2041 fn test_parse_number() {
2042 let ast = parse("42").unwrap();
2043 assert_eq!(ast, AstNode::Number(42.0));
2044 }
2045
2046 #[test]
2047 fn test_parse_string() {
2048 let ast = parse(r#""hello""#).unwrap();
2049 assert_eq!(ast, AstNode::String("hello".to_string()));
2050 }
2051
2052 #[test]
2053 fn test_parse_boolean() {
2054 let ast = parse("true").unwrap();
2055 assert_eq!(ast, AstNode::Boolean(true));
2056
2057 let ast = parse("false").unwrap();
2058 assert_eq!(ast, AstNode::Boolean(false));
2059 }
2060
2061 #[test]
2062 fn test_parse_null() {
2063 let ast = parse("null").unwrap();
2064 assert_eq!(ast, AstNode::Null);
2065 }
2066
2067 #[test]
2068 fn test_parse_variable() {
2069 let ast = parse("$var").unwrap();
2070 assert_eq!(ast, AstNode::Variable("var".to_string()));
2071 }
2072
2073 #[test]
2074 fn test_parse_identifier() {
2075 let ast = parse("foo").unwrap();
2076 assert_eq!(
2077 ast,
2078 AstNode::Path {
2079 steps: vec![PathStep::new(AstNode::Name("foo".to_string()))]
2080 }
2081 );
2082 }
2083
2084 #[test]
2085 fn test_parse_addition() {
2086 let ast = parse("1 + 2").unwrap();
2087 match ast {
2088 AstNode::Binary { op, lhs, rhs } => {
2089 assert_eq!(op, BinaryOp::Add);
2090 assert_eq!(*lhs, AstNode::Number(1.0));
2091 assert_eq!(*rhs, AstNode::Number(2.0));
2092 }
2093 _ => panic!("Expected Binary node"),
2094 }
2095 }
2096
2097 #[test]
2098 fn test_parse_precedence() {
2099 let ast = parse("1 + 2 * 3").unwrap();
2101 match ast {
2102 AstNode::Binary {
2103 op: BinaryOp::Add,
2104 lhs,
2105 rhs,
2106 } => {
2107 assert_eq!(*lhs, AstNode::Number(1.0));
2108 match *rhs {
2109 AstNode::Binary {
2110 op: BinaryOp::Multiply,
2111 lhs,
2112 rhs,
2113 } => {
2114 assert_eq!(*lhs, AstNode::Number(2.0));
2115 assert_eq!(*rhs, AstNode::Number(3.0));
2116 }
2117 _ => panic!("Expected Binary node for multiplication"),
2118 }
2119 }
2120 _ => panic!("Expected Binary node for addition"),
2121 }
2122 }
2123
2124 #[test]
2125 fn test_parse_parentheses() {
2126 let ast = parse("(1 + 2) * 3").unwrap();
2129 match ast {
2130 AstNode::Binary {
2131 op: BinaryOp::Multiply,
2132 lhs,
2133 rhs,
2134 } => {
2135 match *lhs {
2136 AstNode::Block(ref exprs) => {
2137 assert_eq!(exprs.len(), 1);
2138 match &exprs[0] {
2139 AstNode::Binary {
2140 op: BinaryOp::Add,
2141 lhs,
2142 rhs,
2143 } => {
2144 assert_eq!(**lhs, AstNode::Number(1.0));
2145 assert_eq!(**rhs, AstNode::Number(2.0));
2146 }
2147 _ => panic!("Expected Binary node for addition inside block"),
2148 }
2149 }
2150 _ => panic!(
2151 "Expected Block node for parenthesized expression, got {:?}",
2152 lhs
2153 ),
2154 }
2155 assert_eq!(*rhs, AstNode::Number(3.0));
2156 }
2157 _ => panic!("Expected Binary node for multiplication"),
2158 }
2159 }
2160
2161 #[test]
2162 fn test_parse_array() {
2163 let ast = parse("[1, 2, 3]").unwrap();
2164 match ast {
2165 AstNode::Array(elements) => {
2166 assert_eq!(elements.len(), 3);
2167 assert_eq!(elements[0], AstNode::Number(1.0));
2168 assert_eq!(elements[1], AstNode::Number(2.0));
2169 assert_eq!(elements[2], AstNode::Number(3.0));
2170 }
2171 _ => panic!("Expected Array node"),
2172 }
2173 }
2174
2175 #[test]
2176 fn test_parse_object() {
2177 let ast = parse(r#"{"a": 1, "b": 2}"#).unwrap();
2178 match ast {
2179 AstNode::Object(pairs) => {
2180 assert_eq!(pairs.len(), 2);
2181 assert_eq!(pairs[0].0, AstNode::String("a".to_string()));
2182 assert_eq!(pairs[0].1, AstNode::Number(1.0));
2183 assert_eq!(pairs[1].0, AstNode::String("b".to_string()));
2184 assert_eq!(pairs[1].1, AstNode::Number(2.0));
2185 }
2186 _ => panic!("Expected Object node"),
2187 }
2188 }
2189
2190 #[test]
2191 fn test_parse_path() {
2192 let ast = parse("foo.bar").unwrap();
2193 match ast {
2194 AstNode::Path { steps } => {
2195 assert_eq!(steps.len(), 2);
2196 assert_eq!(steps[0].node, AstNode::Name("foo".to_string()));
2197 assert_eq!(steps[1].node, AstNode::Name("bar".to_string()));
2198 }
2199 _ => panic!("Expected Path node"),
2200 }
2201 }
2202
2203 #[test]
2204 fn test_parse_function_call() {
2205 let ast = parse("sum(1, 2, 3)").unwrap();
2206 match ast {
2207 AstNode::Function {
2208 name,
2209 args,
2210 is_builtin,
2211 } => {
2212 assert_eq!(name, "sum");
2213 assert_eq!(args.len(), 3);
2214 assert_eq!(args[0], AstNode::Number(1.0));
2215 assert_eq!(args[1], AstNode::Number(2.0));
2216 assert_eq!(args[2], AstNode::Number(3.0));
2217 assert!(!is_builtin); }
2219 _ => panic!("Expected Function node"),
2220 }
2221 }
2222
2223 #[test]
2224 fn test_parse_conditional() {
2225 let ast = parse("x > 0 ? 1 : -1").unwrap();
2226 match ast {
2227 AstNode::Conditional {
2228 condition,
2229 then_branch,
2230 else_branch,
2231 } => {
2232 assert!(matches!(*condition, AstNode::Binary { .. }));
2233 assert_eq!(*then_branch, AstNode::Number(1.0));
2234 assert_eq!(
2236 else_branch,
2237 Some(Box::new(AstNode::Unary {
2238 op: UnaryOp::Negate,
2239 operand: Box::new(AstNode::Number(1.0)),
2240 }))
2241 );
2242 }
2243 _ => panic!("Expected Conditional node"),
2244 }
2245 }
2246
2247 #[test]
2248 fn test_parse_comparison() {
2249 let ast = parse("x < 10").unwrap();
2250 match ast {
2251 AstNode::Binary { op, .. } => {
2252 assert_eq!(op, BinaryOp::LessThan);
2253 }
2254 _ => panic!("Expected Binary node"),
2255 }
2256 }
2257
2258 #[test]
2259 fn test_parse_logical_and() {
2260 let ast = parse("true and false").unwrap();
2261 match ast {
2262 AstNode::Binary { op, lhs, rhs } => {
2263 assert_eq!(op, BinaryOp::And);
2264 assert_eq!(*lhs, AstNode::Boolean(true));
2265 assert_eq!(*rhs, AstNode::Boolean(false));
2266 }
2267 _ => panic!("Expected Binary node"),
2268 }
2269 }
2270
2271 #[test]
2272 fn test_parse_string_concatenation() {
2273 let ast = parse(r#""hello" & " " & "world""#).unwrap();
2274 match ast {
2275 AstNode::Binary { op, .. } => {
2276 assert_eq!(op, BinaryOp::Concatenate);
2277 }
2278 _ => panic!("Expected Binary node"),
2279 }
2280 }
2281
2282 #[test]
2283 fn test_parse_unary_minus() {
2284 let ast = parse("-5").unwrap();
2286 assert_eq!(
2287 ast,
2288 AstNode::Unary {
2289 op: UnaryOp::Negate,
2290 operand: Box::new(AstNode::Number(5.0)),
2291 }
2292 );
2293 }
2294
2295 #[test]
2296 fn test_parse_block() {
2297 let ast = parse("(1; 2; 3)").unwrap();
2298 match ast {
2299 AstNode::Block(expressions) => {
2300 assert_eq!(expressions.len(), 3);
2301 assert_eq!(expressions[0], AstNode::Number(1.0));
2302 assert_eq!(expressions[1], AstNode::Number(2.0));
2303 assert_eq!(expressions[2], AstNode::Number(3.0));
2304 }
2305 _ => panic!("Expected Block node"),
2306 }
2307 }
2308
2309 #[test]
2310 fn test_parse_complex_expression() {
2311 let ast = parse("(a + b) * c.d").unwrap();
2313 assert!(matches!(ast, AstNode::Binary { .. }));
2314 }
2315
2316 #[test]
2317 fn test_parse_dollar_function_call() {
2318 let ast = parse(r#"$uppercase("hello")"#).unwrap();
2320 match ast {
2321 AstNode::Function {
2322 name,
2323 args,
2324 is_builtin,
2325 } => {
2326 assert_eq!(name, "uppercase");
2327 assert_eq!(args.len(), 1);
2328 assert_eq!(args[0], AstNode::String("hello".to_string()));
2329 assert!(is_builtin); }
2331 _ => panic!("Expected Function node"),
2332 }
2333
2334 let ast = parse("$sum([1, 2, 3])").unwrap();
2336 match ast {
2337 AstNode::Function {
2338 name,
2339 args,
2340 is_builtin,
2341 } => {
2342 assert_eq!(name, "sum");
2343 assert_eq!(args.len(), 1);
2344 assert!(is_builtin); }
2346 _ => panic!("Expected Function node"),
2347 }
2348 }
2349
2350 #[test]
2351 fn test_parse_nested_dollar_functions() {
2352 let ast = parse(r#"$length($lowercase("HELLO"))"#).unwrap();
2354 match ast {
2355 AstNode::Function {
2356 name,
2357 args,
2358 is_builtin,
2359 } => {
2360 assert_eq!(name, "length");
2361 assert_eq!(args.len(), 1);
2362 assert!(is_builtin);
2363 match &args[0] {
2365 AstNode::Function {
2366 name: inner_name,
2367 is_builtin: inner_builtin,
2368 ..
2369 } => {
2370 assert_eq!(inner_name, "lowercase");
2371 assert!(inner_builtin);
2372 }
2373 _ => panic!("Expected nested Function node"),
2374 }
2375 }
2376 _ => panic!("Expected Function node"),
2377 }
2378 }
2379
2380 #[test]
2381 fn test_signature_with_repeat_modifier_parses() {
2382 let result = parse("λ($arg1, $arg2)<n+n:o>{{\"a\": $arg1, \"b\": $arg2}}(1, 2, 3)");
2386 assert!(
2387 result.is_ok(),
2388 "expected parse to succeed, got {:?}",
2389 result
2390 );
2391 }
2392
2393 #[test]
2394 fn test_parent_operator_parses_as_prefix() {
2395 let mut parser = Parser::new("%.OrderID".to_string()).unwrap();
2403 let ast = parser.parse().unwrap();
2404 match ast {
2406 AstNode::Path { steps } => {
2407 assert_eq!(steps.len(), 2);
2408 assert!(matches!(steps[0].node, AstNode::Parent(_)));
2409 assert!(matches!(steps[1].node, AstNode::Name(ref n) if n == "OrderID"));
2410 }
2411 other => panic!("expected Path, got {:?}", other),
2412 }
2413 }
2414
2415 #[test]
2416 fn test_percent_still_parses_as_modulo_infix() {
2417 let ast = parse("10 % 3").unwrap();
2419 assert!(matches!(
2420 ast,
2421 AstNode::Binary {
2422 op: BinaryOp::Modulo,
2423 ..
2424 }
2425 ));
2426 }
2427
2428 #[test]
2429 fn test_focus_bind_parses_as_binary_marker() {
2430 let mut parser = Parser::new("Order@$o".to_string()).unwrap();
2435 let ast = parser.parse().unwrap();
2436 match ast {
2437 AstNode::Binary {
2438 op: BinaryOp::FocusBind,
2439 lhs,
2440 rhs,
2441 } => {
2442 if let AstNode::Path { steps } = *lhs {
2444 assert_eq!(steps.len(), 1);
2445 assert!(matches!(steps[0].node, AstNode::Name(ref n) if n == "Order"));
2446 } else {
2447 panic!("expected lhs to be Path, got {:?}", lhs);
2448 }
2449 assert!(matches!(*rhs, AstNode::Variable(ref n) if n == "o"));
2450 }
2451 other => panic!("expected Binary{{FocusBind}}, got {:?}", other),
2452 }
2453 }
2454
2455 #[test]
2456 fn test_index_bind_parses_as_binary_marker() {
2457 let mut parser = Parser::new("arr#$i".to_string()).unwrap();
2460 let ast = parser.parse().unwrap();
2461 match ast {
2462 AstNode::Binary {
2463 op: BinaryOp::IndexBind,
2464 lhs,
2465 rhs,
2466 } => {
2467 if let AstNode::Path { steps } = *lhs {
2468 assert_eq!(steps.len(), 1);
2469 assert!(matches!(steps[0].node, AstNode::Name(ref n) if n == "arr"));
2470 } else {
2471 panic!("expected lhs to be Path, got {:?}", lhs);
2472 }
2473 assert!(matches!(*rhs, AstNode::Variable(ref n) if n == "i"));
2474 }
2475 other => panic!("expected Binary{{IndexBind}}, got {:?}", other),
2476 }
2477 }
2478
2479 #[test]
2480 fn test_focus_bind_requires_variable_rhs() {
2481 let err = parse("Order@foo").unwrap_err();
2483 assert!(err.to_string().starts_with("S0214"));
2484 }
2485}