1use crate::error::Error;
2use crate::limits::ResourceLimits;
3use crate::parsing::ast::{try_parse_type_constraint_command, *};
4use crate::parsing::lexer::{
5 can_be_label, can_be_reference_segment, conversion_target_from_token, is_boolean_keyword,
6 is_calendar_unit_token, is_duration_unit, is_math_function, is_spec_body_keyword,
7 is_structural_keyword, is_type_keyword, token_kind_to_boolean_value,
8 token_kind_to_calendar_unit, token_kind_to_duration_unit, token_kind_to_primitive, Lexer,
9 Token, TokenKind,
10};
11use crate::parsing::source::Source;
12use rust_decimal::Decimal;
13use std::str::FromStr;
14use std::sync::Arc;
15
16type TypeArrowChain = (ParentType, Option<SpecRef>, Option<Vec<Constraint>>);
17
18pub struct ParseResult {
19 pub specs: Vec<LemmaSpec>,
20 pub expression_count: usize,
21}
22
23pub fn parse(
24 content: &str,
25 attribute: &str,
26 limits: &ResourceLimits,
27) -> Result<ParseResult, Error> {
28 if content.len() > limits.max_file_size_bytes {
29 return Err(Error::resource_limit_exceeded(
30 "max_file_size_bytes",
31 format!(
32 "{} bytes ({} MB)",
33 limits.max_file_size_bytes,
34 limits.max_file_size_bytes / (1024 * 1024)
35 ),
36 format!(
37 "{} bytes ({:.2} MB)",
38 content.len(),
39 content.len() as f64 / (1024.0 * 1024.0)
40 ),
41 "Reduce file size or split into multiple specs",
42 None,
43 None,
44 None,
45 ));
46 }
47
48 let mut parser = Parser::new(content, attribute, limits);
49 let specs = parser.parse_file()?;
50 Ok(ParseResult {
51 specs,
52 expression_count: parser.expression_count,
53 })
54}
55
56struct Parser {
57 lexer: Lexer,
58 depth_tracker: DepthTracker,
59 expression_count: usize,
60 max_expression_count: usize,
61}
62
63impl Parser {
64 fn new(content: &str, attribute: &str, limits: &ResourceLimits) -> Self {
65 Parser {
66 lexer: Lexer::new(content, attribute),
67 depth_tracker: DepthTracker::with_max_depth(limits.max_expression_depth),
68 expression_count: 0,
69 max_expression_count: limits.max_expression_count,
70 }
71 }
72
73 fn attribute(&self) -> String {
74 self.lexer.attribute().to_string()
75 }
76
77 fn peek(&mut self) -> Result<&Token, Error> {
78 self.lexer.peek()
79 }
80
81 fn next(&mut self) -> Result<Token, Error> {
82 self.lexer.next_token()
83 }
84
85 fn at(&mut self, kind: &TokenKind) -> Result<bool, Error> {
86 Ok(&self.peek()?.kind == kind)
87 }
88
89 fn at_any(&mut self, kinds: &[TokenKind]) -> Result<bool, Error> {
90 let current = &self.peek()?.kind;
91 Ok(kinds.contains(current))
92 }
93
94 fn expect(&mut self, kind: &TokenKind) -> Result<Token, Error> {
95 let token = self.next()?;
96 if &token.kind == kind {
97 Ok(token)
98 } else {
99 Err(self.error_at_token(&token, format!("Expected {}, found {}", kind, token.kind)))
100 }
101 }
102
103 fn error_at_token(&self, token: &Token, message: impl Into<String>) -> Error {
104 Error::parsing(
105 message,
106 Source::new(self.lexer.attribute(), token.span.clone()),
107 None::<String>,
108 )
109 }
110
111 fn error_at_token_with_suggestion(
112 &self,
113 token: &Token,
114 message: impl Into<String>,
115 suggestion: impl Into<String>,
116 ) -> Error {
117 Error::parsing(
118 message,
119 Source::new(self.lexer.attribute(), token.span.clone()),
120 Some(suggestion),
121 )
122 }
123
124 fn try_parse_hash_pin(&mut self) -> Result<Option<String>, Error> {
129 if !self.at(&TokenKind::Tilde)? {
130 return Ok(None);
131 }
132 let tilde_span = self.next()?.span;
133 let hash = self.lexer.scan_raw_alphanumeric()?;
134 if hash.len() != 8 {
135 return Err(Error::parsing(
136 format!(
137 "Expected an 8-character alphanumeric plan hash after '~', found '{}'",
138 hash
139 ),
140 self.make_source(tilde_span),
141 None::<String>,
142 ));
143 }
144 Ok(Some(hash))
145 }
146
147 fn make_source(&self, span: Span) -> Source {
148 Source::new(self.lexer.attribute(), span)
149 }
150
151 fn span_from(&self, start: &Span) -> Span {
152 Span {
155 start: start.start,
156 end: start.end.max(start.start),
157 line: start.line,
158 col: start.col,
159 }
160 }
161
162 fn span_covering(&self, start: &Span, end: &Span) -> Span {
163 Span {
164 start: start.start,
165 end: end.end,
166 line: start.line,
167 col: start.col,
168 }
169 }
170
171 fn parse_file(&mut self) -> Result<Vec<LemmaSpec>, Error> {
176 let mut specs = Vec::new();
177 loop {
178 if self.at(&TokenKind::Eof)? {
179 break;
180 }
181 if self.at(&TokenKind::Spec)? {
182 specs.push(self.parse_spec()?);
183 } else {
184 let token = self.next()?;
185 return Err(self.error_at_token_with_suggestion(
186 &token,
187 format!(
188 "Expected a spec declaration (e.g. 'spec my_spec'), found {}",
189 token.kind
190 ),
191 "A Lemma file must start with 'spec <name>'",
192 ));
193 }
194 }
195 Ok(specs)
196 }
197
198 fn parse_spec(&mut self) -> Result<LemmaSpec, Error> {
199 let spec_token = self.expect(&TokenKind::Spec)?;
200 let start_line = spec_token.span.line;
201
202 let (name, _name_span) = self.parse_spec_name()?;
203
204 let effective_from = self.try_parse_effective_from()?;
205
206 let commentary = self.try_parse_commentary()?;
207
208 let attribute = self.attribute();
209 let mut spec = LemmaSpec::new(name.clone())
210 .with_attribute(attribute)
211 .with_start_line(start_line);
212 spec.effective_from = effective_from;
213
214 if let Some(commentary_text) = commentary {
215 spec = spec.set_commentary(commentary_text);
216 }
217
218 let mut facts = Vec::new();
222 let mut rules = Vec::new();
223 let mut types = Vec::new();
224 let mut meta_fields = Vec::new();
225
226 loop {
227 let peek_kind = self.peek()?.kind.clone();
228 match peek_kind {
229 TokenKind::Fact => {
230 let fact = self.parse_fact()?;
231 facts.push(fact);
232 }
233 TokenKind::Rule => {
234 let rule = self.parse_rule()?;
235 rules.push(rule);
236 }
237 TokenKind::Type => {
238 let type_def = self.parse_type_def()?;
239 types.push(type_def);
240 }
241 TokenKind::Meta => {
242 let meta = self.parse_meta()?;
243 meta_fields.push(meta);
244 }
245 TokenKind::Spec | TokenKind::Eof => break,
246 _ => {
247 let token = self.next()?;
248 return Err(self.error_at_token_with_suggestion(
249 &token,
250 format!(
251 "Expected 'fact', 'rule', 'type', 'meta', or a new 'spec', found '{}'",
252 token.text
253 ),
254 "Check the spelling or add the appropriate keyword",
255 ));
256 }
257 }
258 }
259
260 for type_def in types {
261 spec = spec.add_type(type_def);
262 }
263 for fact in facts {
264 spec = spec.add_fact(fact);
265 }
266 for rule in rules {
267 spec = spec.add_rule(rule);
268 }
269 for meta in meta_fields {
270 spec = spec.add_meta_field(meta);
271 }
272
273 Ok(spec)
274 }
275
276 fn parse_spec_name(&mut self) -> Result<(String, Span), Error> {
279 let mut name = String::new();
280 let start_span;
281
282 if self.at(&TokenKind::At)? {
283 let at_tok = self.next()?;
284 start_span = at_tok.span.clone();
285 name.push('@');
286 } else {
287 start_span = self.peek()?.span.clone();
288 }
289
290 let first = self.next()?;
292 if !first.kind.is_identifier_like() {
293 return Err(self.error_at_token(
294 &first,
295 format!("Expected a spec name, found {}", first.kind),
296 ));
297 }
298 name.push_str(&first.text);
299 let mut end_span = first.span.clone();
300
301 while self.at(&TokenKind::Slash)? {
303 self.next()?; name.push('/');
305 let seg = self.next()?;
306 if !seg.kind.is_identifier_like() {
307 return Err(self.error_at_token(
308 &seg,
309 format!(
310 "Expected identifier after '/' in spec name, found {}",
311 seg.kind
312 ),
313 ));
314 }
315 name.push_str(&seg.text);
316 end_span = seg.span.clone();
317 }
318
319 while self.at(&TokenKind::Minus)? {
321 let minus_span = self.peek()?.span.clone();
324 self.next()?; if let Ok(peeked) = self.peek() {
326 if peeked.kind.is_identifier_like() {
327 let seg = self.next()?;
328 name.push('-');
329 name.push_str(&seg.text);
330 end_span = seg.span.clone();
331 while self.at(&TokenKind::Slash)? {
333 self.next()?; name.push('/');
335 let seg2 = self.next()?;
336 if !seg2.kind.is_identifier_like() {
337 return Err(self.error_at_token(
338 &seg2,
339 format!(
340 "Expected identifier after '/' in spec name, found {}",
341 seg2.kind
342 ),
343 ));
344 }
345 name.push_str(&seg2.text);
346 end_span = seg2.span.clone();
347 }
348 } else {
349 let span = self.span_covering(&start_span, &minus_span);
351 return Err(Error::parsing(
352 "Trailing '-' after spec name",
353 self.make_source(span),
354 None::<String>,
355 ));
356 }
357 }
358 }
359
360 let full_span = self.span_covering(&start_span, &end_span);
361 Ok((name, full_span))
362 }
363
364 fn try_parse_effective_from(&mut self) -> Result<Option<DateTimeValue>, Error> {
365 if !self.at(&TokenKind::NumberLit)? {
370 return Ok(None);
371 }
372
373 let peeked = self.peek()?;
374 let peeked_text = peeked.text.clone();
375 let peeked_span = peeked.span.clone();
376
377 if peeked_text.len() == 4 && peeked_text.chars().all(|c| c.is_ascii_digit()) {
379 let mut dt_str = String::new();
381 let num_tok = self.next()?; dt_str.push_str(&num_tok.text);
383
384 while self.at(&TokenKind::Minus)? {
386 self.next()?; dt_str.push('-');
388 let part = self.next()?;
389 dt_str.push_str(&part.text);
390 }
391
392 if self.at(&TokenKind::Identifier)? {
394 let peeked = self.peek()?;
395 if peeked.text.starts_with('T') || peeked.text.starts_with('t') {
396 let time_part = self.next()?;
397 dt_str.push_str(&time_part.text);
398 while self.at(&TokenKind::Colon)? {
400 self.next()?;
401 dt_str.push(':');
402 let part = self.next()?;
403 dt_str.push_str(&part.text);
404 }
405 if self.at(&TokenKind::Plus)? {
407 self.next()?;
408 dt_str.push('+');
409 let tz_part = self.next()?;
410 dt_str.push_str(&tz_part.text);
411 if self.at(&TokenKind::Colon)? {
412 self.next()?;
413 dt_str.push(':');
414 let tz_min = self.next()?;
415 dt_str.push_str(&tz_min.text);
416 }
417 }
418 }
419 }
420
421 if let Ok(dtv) = dt_str.parse::<DateTimeValue>() {
423 return Ok(Some(dtv));
424 }
425
426 return Err(Error::parsing(
427 format!("Invalid date/time in spec declaration: '{}'", dt_str),
428 self.make_source(peeked_span),
429 None::<String>,
430 ));
431 }
432
433 Ok(None)
434 }
435
436 fn try_parse_commentary(&mut self) -> Result<Option<String>, Error> {
437 if !self.at(&TokenKind::Commentary)? {
438 return Ok(None);
439 }
440 let token = self.next()?;
441 let trimmed = token.text.trim().to_string();
442 if trimmed.is_empty() {
443 Ok(None)
444 } else {
445 Ok(Some(trimmed))
446 }
447 }
448
449 fn parse_fact(&mut self) -> Result<LemmaFact, Error> {
454 let fact_token = self.expect(&TokenKind::Fact)?;
455 let start_span = fact_token.span.clone();
456
457 let reference = self.parse_reference()?;
459
460 self.expect(&TokenKind::Colon)?;
461
462 let value = self.parse_fact_value()?;
463
464 let end_span = self.peek()?.span.clone();
465 let span = self.span_covering(&start_span, &end_span);
466 let source = self.make_source(span);
467
468 Ok(LemmaFact::new(reference, value, source))
469 }
470
471 fn parse_reference(&mut self) -> Result<Reference, Error> {
472 let mut segments = Vec::new();
473
474 let first = self.next()?;
475 if is_structural_keyword(&first.kind) {
478 return Err(self.error_at_token_with_suggestion(
479 &first,
480 format!(
481 "'{}' is a reserved keyword and cannot be used as a name",
482 first.text
483 ),
484 "Choose a different name that is not a reserved keyword",
485 ));
486 }
487
488 if !can_be_reference_segment(&first.kind) {
489 return Err(self.error_at_token(
490 &first,
491 format!("Expected an identifier, found {}", first.kind),
492 ));
493 }
494
495 segments.push(first.text.clone());
496
497 while self.at(&TokenKind::Dot)? {
499 self.next()?; let seg = self.next()?;
501 if !can_be_reference_segment(&seg.kind) {
502 return Err(self.error_at_token(
503 &seg,
504 format!("Expected an identifier after '.', found {}", seg.kind),
505 ));
506 }
507 segments.push(seg.text.clone());
508 }
509
510 Ok(Reference::from_path(segments))
511 }
512
513 fn parse_fact_value(&mut self) -> Result<FactValue, Error> {
514 if self.at(&TokenKind::LBracket)? {
516 return self.parse_type_declaration_or_inline();
517 }
518
519 if self.at(&TokenKind::Spec)? {
521 return self.parse_fact_spec_reference();
522 }
523
524 let value = self.parse_literal_value()?;
526 Ok(FactValue::Literal(value))
527 }
528
529 fn parse_type_declaration_or_inline(&mut self) -> Result<FactValue, Error> {
530 self.expect(&TokenKind::LBracket)?;
531
532 let (base, from_spec, constraints) = self.parse_type_arrow_chain()?;
534
535 self.expect(&TokenKind::RBracket)?;
536
537 Ok(FactValue::TypeDeclaration {
538 base,
539 constraints,
540 from: from_spec,
541 })
542 }
543
544 fn parse_fact_spec_reference(&mut self) -> Result<FactValue, Error> {
545 self.expect(&TokenKind::Spec)?;
546
547 let (name, _name_span) = self.parse_spec_name()?;
548 let from_registry = name.starts_with('@');
549
550 let hash_pin = self.try_parse_hash_pin()?;
551
552 let mut effective = None;
553 if self.at(&TokenKind::NumberLit)? {
555 let peeked = self.peek()?;
556 if peeked.text.len() == 4 && peeked.text.chars().all(|c| c.is_ascii_digit()) {
557 effective = self.try_parse_effective_from()?;
559 }
560 }
561
562 Ok(FactValue::SpecReference(SpecRef {
563 name,
564 from_registry,
565 hash_pin,
566 effective,
567 }))
568 }
569
570 fn parse_rule(&mut self) -> Result<LemmaRule, Error> {
575 let rule_token = self.expect(&TokenKind::Rule)?;
576 let start_span = rule_token.span.clone();
577
578 let name_tok = self.next()?;
579 if is_structural_keyword(&name_tok.kind) {
580 return Err(self.error_at_token_with_suggestion(
581 &name_tok,
582 format!(
583 "'{}' is a reserved keyword and cannot be used as a rule name",
584 name_tok.text
585 ),
586 "Choose a different name that is not a reserved keyword",
587 ));
588 }
589 if !can_be_label(&name_tok.kind) && !is_type_keyword(&name_tok.kind) {
590 return Err(self.error_at_token(
591 &name_tok,
592 format!("Expected a rule name, found {}", name_tok.kind),
593 ));
594 }
595 let rule_name = name_tok.text.clone();
596
597 self.expect(&TokenKind::Colon)?;
598
599 let expression = if self.at(&TokenKind::Veto)? {
601 self.parse_veto_expression()?
602 } else {
603 self.parse_expression()?
604 };
605
606 let mut unless_clauses = Vec::new();
608 while self.at(&TokenKind::Unless)? {
609 unless_clauses.push(self.parse_unless_clause()?);
610 }
611
612 let end_span = if let Some(last_unless) = unless_clauses.last() {
613 last_unless.source_location.span.clone()
614 } else if let Some(ref loc) = expression.source_location {
615 loc.span.clone()
616 } else {
617 start_span.clone()
618 };
619
620 let span = self.span_covering(&start_span, &end_span);
621 Ok(LemmaRule {
622 name: rule_name,
623 expression,
624 unless_clauses,
625 source_location: self.make_source(span),
626 })
627 }
628
629 fn parse_veto_expression(&mut self) -> Result<Expression, Error> {
630 let veto_tok = self.expect(&TokenKind::Veto)?;
631 let start_span = veto_tok.span.clone();
632
633 let message = if self.at(&TokenKind::StringLit)? {
634 let str_tok = self.next()?;
635 let content = unquote_string(&str_tok.text);
636 Some(content)
637 } else {
638 None
639 };
640
641 let span = self.span_from(&start_span);
642 self.new_expression(
643 ExpressionKind::Veto(VetoExpression { message }),
644 self.make_source(span),
645 )
646 }
647
648 fn parse_unless_clause(&mut self) -> Result<UnlessClause, Error> {
649 let unless_tok = self.expect(&TokenKind::Unless)?;
650 let start_span = unless_tok.span.clone();
651
652 let condition = self.parse_expression()?;
653
654 self.expect(&TokenKind::Then)?;
655
656 let result = if self.at(&TokenKind::Veto)? {
657 self.parse_veto_expression()?
658 } else {
659 self.parse_expression()?
660 };
661
662 let end_span = result
663 .source_location
664 .as_ref()
665 .map(|s| s.span.clone())
666 .unwrap_or_else(|| start_span.clone());
667 let span = self.span_covering(&start_span, &end_span);
668
669 Ok(UnlessClause {
670 condition,
671 result,
672 source_location: self.make_source(span),
673 })
674 }
675
676 fn parse_type_def(&mut self) -> Result<TypeDef, Error> {
681 let type_tok = self.expect(&TokenKind::Type)?;
682 let start_span = type_tok.span.clone();
683
684 let name_tok = self.next()?;
686 let type_name = name_tok.text.clone();
687
688 if self.at(&TokenKind::From)? {
690 return self.parse_type_import(type_name, start_span);
691 }
692
693 if self.at(&TokenKind::Colon)? {
695 self.next()?; } else {
697 let peek = self.peek()?.clone();
700 return Err(self.error_at_token(
701 &peek,
702 format!(
703 "Expected ':' or 'from' after type name '{}', found {}",
704 type_name, peek.kind
705 ),
706 ));
707 }
708
709 let (parent, _from, constraints) = self.parse_type_arrow_chain()?;
710
711 let end_span = self.peek()?.span.clone();
712 let span = self.span_covering(&start_span, &end_span);
713 Ok(TypeDef::Regular {
714 source_location: self.make_source(span),
715 name: type_name,
716 parent,
717 constraints,
718 })
719 }
720
721 fn parse_type_import(&mut self, type_name: String, start_span: Span) -> Result<TypeDef, Error> {
722 self.expect(&TokenKind::From)?;
723
724 let (from_name, _from_span) = self.parse_spec_name()?;
725 let from_registry = from_name.starts_with('@');
726 let hash_pin = self.try_parse_hash_pin()?;
727
728 let mut effective = None;
729 if self.at(&TokenKind::NumberLit)? {
730 let peeked = self.peek()?;
731 if peeked.text.len() == 4 && peeked.text.chars().all(|c| c.is_ascii_digit()) {
732 effective = self.try_parse_effective_from()?;
733 }
734 }
735
736 let from = SpecRef {
737 name: from_name,
738 from_registry,
739 hash_pin,
740 effective,
741 };
742
743 let constraints = if self.at(&TokenKind::Arrow)? {
745 let (_, _, constraints) = self.parse_remaining_arrow_chain()?;
746 constraints
747 } else {
748 None
749 };
750
751 let end_span = self.peek()?.span.clone();
752 let span = self.span_covering(&start_span, &end_span);
753
754 let source_type = type_name.clone();
755
756 Ok(TypeDef::Import {
757 source_location: self.make_source(span),
758 name: type_name,
759 source_type,
760 from,
761 constraints,
762 })
763 }
764
765 fn parse_type_arrow_chain(&mut self) -> Result<TypeArrowChain, Error> {
767 let name_tok = self.next()?;
768 let base = if let Some(kind) = token_kind_to_primitive(&name_tok.kind) {
769 ParentType::Primitive { primitive: kind }
770 } else if can_be_label(&name_tok.kind) {
771 ParentType::Custom {
772 name: name_tok.text.clone(),
773 }
774 } else {
775 return Err(self.error_at_token(
776 &name_tok,
777 format!("Expected a type name, found {}", name_tok.kind),
778 ));
779 };
780
781 let from_spec = if self.at(&TokenKind::From)? {
783 self.next()?; let (from_name, _) = self.parse_spec_name()?;
785 let from_registry = from_name.starts_with('@');
786 let hash_pin = self.try_parse_hash_pin()?;
787 let mut effective = None;
788 if self.at(&TokenKind::NumberLit)? {
789 let peeked = self.peek()?;
790 if peeked.text.len() == 4 && peeked.text.chars().all(|c| c.is_ascii_digit()) {
791 effective = self.try_parse_effective_from()?;
792 }
793 }
794 Some(SpecRef {
795 name: from_name,
796 from_registry,
797 hash_pin,
798 effective,
799 })
800 } else {
801 None
802 };
803
804 let mut commands = Vec::new();
806 while self.at(&TokenKind::Arrow)? {
807 self.next()?; let (cmd, cmd_args) = self.parse_command()?;
809 commands.push((cmd, cmd_args));
810 }
811
812 let constraints = if commands.is_empty() {
813 None
814 } else {
815 Some(commands)
816 };
817
818 Ok((base, from_spec, constraints))
819 }
820
821 fn parse_remaining_arrow_chain(&mut self) -> Result<TypeArrowChain, Error> {
822 let mut commands = Vec::new();
823 while self.at(&TokenKind::Arrow)? {
824 self.next()?; let (cmd, cmd_args) = self.parse_command()?;
826 commands.push((cmd, cmd_args));
827 }
828 let constraints = if commands.is_empty() {
829 None
830 } else {
831 Some(commands)
832 };
833 Ok((
834 ParentType::Custom {
835 name: String::new(),
836 },
837 None,
838 constraints,
839 ))
840 }
841
842 fn parse_command(&mut self) -> Result<(TypeConstraintCommand, Vec<CommandArg>), Error> {
843 let name_tok = self.next()?;
844 if !can_be_label(&name_tok.kind) && !is_type_keyword(&name_tok.kind) {
845 return Err(self.error_at_token(
846 &name_tok,
847 format!("Expected a command name, found {}", name_tok.kind),
848 ));
849 }
850 let cmd = try_parse_type_constraint_command(&name_tok.text).ok_or_else(|| {
851 self.error_at_token(
852 &name_tok,
853 format!(
854 "Unknown constraint command '{}'. Valid commands: help, default, unit, minimum, maximum, decimals, precision, option, options, length",
855 name_tok.text
856 ),
857 )
858 })?;
859
860 let mut args = Vec::new();
861 loop {
862 if self.at(&TokenKind::Arrow)?
865 || self.at(&TokenKind::RBracket)?
866 || self.at(&TokenKind::Eof)?
867 || is_spec_body_keyword(&self.peek()?.kind)
868 || self.at(&TokenKind::Spec)?
869 {
870 break;
871 }
872
873 let peek_kind = self.peek()?.kind.clone();
874 match peek_kind {
875 TokenKind::NumberLit => {
876 let tok = self.next()?;
877 args.push(CommandArg::Number(tok.text));
878 }
879 TokenKind::Minus | TokenKind::Plus => {
880 let second = self.lexer.peek_second()?.kind.clone();
881 if second == TokenKind::NumberLit {
882 let sign = self.next()?;
883 let num = self.next()?;
884 let text = format!("{}{}", sign.text, num.text);
885 args.push(CommandArg::Number(text));
886 } else {
887 break;
888 }
889 }
890 TokenKind::StringLit => {
891 let tok = self.next()?;
892 let content = unquote_string(&tok.text);
893 args.push(CommandArg::Text(content));
894 }
895 ref k if is_boolean_keyword(k) => {
896 let tok = self.next()?;
897 args.push(CommandArg::Boolean(token_kind_to_boolean_value(&tok.kind)));
898 }
899 ref k if can_be_label(k) || is_type_keyword(k) => {
900 let tok = self.next()?;
901 args.push(CommandArg::Label(tok.text));
902 }
903 _ => break,
904 }
905 }
906
907 Ok((cmd, args))
908 }
909
910 fn parse_meta(&mut self) -> Result<MetaField, Error> {
915 let meta_tok = self.expect(&TokenKind::Meta)?;
916 let start_span = meta_tok.span.clone();
917
918 let key_tok = self.next()?;
919 let key = key_tok.text.clone();
920
921 self.expect(&TokenKind::Colon)?;
922
923 let value = self.parse_meta_value()?;
924
925 let end_span = self.peek()?.span.clone();
926 let span = self.span_covering(&start_span, &end_span);
927
928 Ok(MetaField {
929 key,
930 value,
931 source_location: self.make_source(span),
932 })
933 }
934
935 fn parse_meta_value(&mut self) -> Result<MetaValue, Error> {
936 let peeked = self.peek()?;
938 match &peeked.kind {
939 TokenKind::StringLit => {
940 let value = self.parse_literal_value()?;
941 return Ok(MetaValue::Literal(value));
942 }
943 TokenKind::NumberLit => {
944 let value = self.parse_literal_value()?;
945 return Ok(MetaValue::Literal(value));
946 }
947 k if is_boolean_keyword(k) => {
948 let value = self.parse_literal_value()?;
949 return Ok(MetaValue::Literal(value));
950 }
951 _ => {}
952 }
953
954 let mut ident = String::new();
957 loop {
958 let peeked = self.peek()?;
959 match &peeked.kind {
960 k if k.is_identifier_like() => {
961 let tok = self.next()?;
962 ident.push_str(&tok.text);
963 }
964 TokenKind::Dot => {
965 self.next()?;
966 ident.push('.');
967 }
968 TokenKind::Slash => {
969 self.next()?;
970 ident.push('/');
971 }
972 TokenKind::Minus => {
973 self.next()?;
974 ident.push('-');
975 }
976 TokenKind::NumberLit => {
977 let tok = self.next()?;
978 ident.push_str(&tok.text);
979 }
980 _ => break,
981 }
982 }
983
984 if ident.is_empty() {
985 let tok = self.peek()?.clone();
986 return Err(self.error_at_token(&tok, "Expected a meta value"));
987 }
988
989 Ok(MetaValue::Unquoted(ident))
990 }
991
992 fn parse_literal_value(&mut self) -> Result<Value, Error> {
997 let peeked = self.peek()?;
998 match &peeked.kind {
999 TokenKind::StringLit => {
1000 let tok = self.next()?;
1001 let content = unquote_string(&tok.text);
1002 Ok(Value::Text(content))
1003 }
1004 k if is_boolean_keyword(k) => {
1005 let tok = self.next()?;
1006 Ok(Value::Boolean(token_kind_to_boolean_value(&tok.kind)))
1007 }
1008 TokenKind::NumberLit => self.parse_number_literal(),
1009 TokenKind::Minus | TokenKind::Plus => self.parse_signed_number_literal(),
1010 _ => {
1011 let tok = self.next()?;
1012 Err(self.error_at_token(
1013 &tok,
1014 format!(
1015 "Expected a value (number, text, boolean, date, etc.), found '{}'",
1016 tok.text
1017 ),
1018 ))
1019 }
1020 }
1021 }
1022
1023 fn parse_signed_number_literal(&mut self) -> Result<Value, Error> {
1024 let sign_tok = self.next()?;
1025 let sign_span = sign_tok.span.clone();
1026 let is_negative = sign_tok.kind == TokenKind::Minus;
1027
1028 if !self.at(&TokenKind::NumberLit)? {
1029 let tok = self.peek()?.clone();
1030 return Err(self.error_at_token(
1031 &tok,
1032 format!(
1033 "Expected a number after '{}', found '{}'",
1034 sign_tok.text, tok.text
1035 ),
1036 ));
1037 }
1038
1039 let value = self.parse_number_literal()?;
1040 if !is_negative {
1041 return Ok(value);
1042 }
1043 match value {
1044 Value::Number(d) => Ok(Value::Number(-d)),
1045 Value::Scale(d, unit) => Ok(Value::Scale(-d, unit)),
1046 Value::Duration(d, unit) => Ok(Value::Duration(-d, unit)),
1047 Value::Ratio(d, label) => Ok(Value::Ratio(-d, label)),
1048 other => Err(Error::parsing(
1049 format!("Cannot negate this value: {}", other),
1050 self.make_source(sign_span),
1051 None::<String>,
1052 )),
1053 }
1054 }
1055
1056 fn parse_number_literal(&mut self) -> Result<Value, Error> {
1057 let num_tok = self.next()?;
1058 let num_text = &num_tok.text;
1059 let num_span = num_tok.span.clone();
1060
1061 if num_text.len() == 4
1063 && num_text.chars().all(|c| c.is_ascii_digit())
1064 && self.at(&TokenKind::Minus)?
1065 {
1066 return self.parse_date_literal(num_text.clone(), num_span);
1067 }
1068
1069 let peeked = self.peek()?;
1071
1072 if num_text.len() == 2
1074 && num_text.chars().all(|c| c.is_ascii_digit())
1075 && peeked.kind == TokenKind::Colon
1076 {
1077 return self.try_parse_time_literal(num_text.clone(), num_span);
1084 }
1085
1086 if peeked.kind == TokenKind::PercentPercent {
1088 let pp_tok = self.next()?;
1089 if let Ok(next_peek) = self.peek() {
1091 if next_peek.kind == TokenKind::NumberLit {
1092 return Err(self.error_at_token(
1093 &pp_tok,
1094 "Permille literal cannot be followed by a digit",
1095 ));
1096 }
1097 }
1098 let decimal = parse_decimal_string(num_text, &num_span, self)?;
1099 let ratio_value = decimal / Decimal::from(1000);
1100 return Ok(Value::Ratio(ratio_value, Some("permille".to_string())));
1101 }
1102
1103 if peeked.kind == TokenKind::Percent {
1105 let pct_tok = self.next()?;
1106 if let Ok(next_peek) = self.peek() {
1108 if next_peek.kind == TokenKind::NumberLit || next_peek.kind == TokenKind::Percent {
1109 return Err(self.error_at_token(
1110 &pct_tok,
1111 "Percent literal cannot be followed by a digit",
1112 ));
1113 }
1114 }
1115 let decimal = parse_decimal_string(num_text, &num_span, self)?;
1116 let ratio_value = decimal / Decimal::from(100);
1117 return Ok(Value::Ratio(ratio_value, Some("percent".to_string())));
1118 }
1119
1120 if peeked.kind == TokenKind::PercentKw {
1122 self.next()?; let decimal = parse_decimal_string(num_text, &num_span, self)?;
1124 let ratio_value = decimal / Decimal::from(100);
1125 return Ok(Value::Ratio(ratio_value, Some("percent".to_string())));
1126 }
1127
1128 if peeked.kind == TokenKind::Permille {
1130 self.next()?; let decimal = parse_decimal_string(num_text, &num_span, self)?;
1132 let ratio_value = decimal / Decimal::from(1000);
1133 return Ok(Value::Ratio(ratio_value, Some("permille".to_string())));
1134 }
1135
1136 if is_duration_unit(&peeked.kind) && peeked.kind != TokenKind::PercentKw {
1138 let unit_tok = self.next()?;
1139 let decimal = parse_decimal_string(num_text, &num_span, self)?;
1140 let duration_unit = token_kind_to_duration_unit(&unit_tok.kind);
1141 return Ok(Value::Duration(decimal, duration_unit));
1142 }
1143
1144 if can_be_label(&peeked.kind) {
1146 let unit_tok = self.next()?;
1147 let decimal = parse_decimal_string(num_text, &num_span, self)?;
1148 return Ok(Value::Scale(decimal, unit_tok.text.clone()));
1149 }
1150
1151 let decimal = parse_decimal_string(num_text, &num_span, self)?;
1153 Ok(Value::Number(decimal))
1154 }
1155
1156 fn parse_date_literal(&mut self, year_text: String, start_span: Span) -> Result<Value, Error> {
1157 let mut dt_str = year_text;
1158
1159 self.expect(&TokenKind::Minus)?;
1161 dt_str.push('-');
1162 let month_tok = self.expect(&TokenKind::NumberLit)?;
1163 dt_str.push_str(&month_tok.text);
1164
1165 self.expect(&TokenKind::Minus)?;
1167 dt_str.push('-');
1168 let day_tok = self.expect(&TokenKind::NumberLit)?;
1169 dt_str.push_str(&day_tok.text);
1170
1171 if self.at(&TokenKind::Identifier)? {
1173 let peeked = self.peek()?;
1174 if peeked.text.len() >= 2
1175 && (peeked.text.starts_with('T') || peeked.text.starts_with('t'))
1176 {
1177 let t_tok = self.next()?;
1179 dt_str.push_str(&t_tok.text);
1180
1181 if self.at(&TokenKind::Colon)? {
1183 self.next()?;
1184 dt_str.push(':');
1185 let min_tok = self.next()?;
1186 dt_str.push_str(&min_tok.text);
1187
1188 if self.at(&TokenKind::Colon)? {
1190 self.next()?;
1191 dt_str.push(':');
1192 let sec_tok = self.next()?;
1193 dt_str.push_str(&sec_tok.text);
1194
1195 if self.at(&TokenKind::Dot)? {
1197 self.next()?;
1198 dt_str.push('.');
1199 let frac_tok = self.expect(&TokenKind::NumberLit)?;
1200 dt_str.push_str(&frac_tok.text);
1201 }
1202 }
1203 }
1204
1205 self.try_consume_timezone(&mut dt_str)?;
1207 }
1208 }
1209
1210 if let Ok(dtv) = dt_str.parse::<crate::literals::DateTimeValue>() {
1211 return Ok(Value::Date(dtv));
1212 }
1213
1214 Err(Error::parsing(
1215 format!("Invalid date/time format: '{}'", dt_str),
1216 self.make_source(start_span),
1217 None::<String>,
1218 ))
1219 }
1220
1221 fn try_consume_timezone(&mut self, dt_str: &mut String) -> Result<(), Error> {
1222 if self.at(&TokenKind::Identifier)? {
1224 let peeked = self.peek()?;
1225 if peeked.text == "Z" || peeked.text == "z" {
1226 let z_tok = self.next()?;
1227 dt_str.push_str(&z_tok.text);
1228 return Ok(());
1229 }
1230 }
1231
1232 if self.at(&TokenKind::Plus)? || self.at(&TokenKind::Minus)? {
1234 let sign_tok = self.next()?;
1235 dt_str.push_str(&sign_tok.text);
1236 let hour_tok = self.expect(&TokenKind::NumberLit)?;
1237 dt_str.push_str(&hour_tok.text);
1238 if self.at(&TokenKind::Colon)? {
1239 self.next()?;
1240 dt_str.push(':');
1241 let min_tok = self.expect(&TokenKind::NumberLit)?;
1242 dt_str.push_str(&min_tok.text);
1243 }
1244 }
1245
1246 Ok(())
1247 }
1248
1249 fn try_parse_time_literal(
1250 &mut self,
1251 hour_text: String,
1252 start_span: Span,
1253 ) -> Result<Value, Error> {
1254 let mut time_str = hour_text;
1255
1256 self.expect(&TokenKind::Colon)?;
1258 time_str.push(':');
1259 let min_tok = self.expect(&TokenKind::NumberLit)?;
1260 time_str.push_str(&min_tok.text);
1261
1262 if self.at(&TokenKind::Colon)? {
1264 self.next()?;
1265 time_str.push(':');
1266 let sec_tok = self.expect(&TokenKind::NumberLit)?;
1267 time_str.push_str(&sec_tok.text);
1268 }
1269
1270 self.try_consume_timezone(&mut time_str)?;
1272
1273 if let Ok(t) = time_str.parse::<chrono::NaiveTime>() {
1274 use chrono::Timelike;
1275 return Ok(Value::Time(TimeValue {
1276 hour: t.hour() as u8,
1277 minute: t.minute() as u8,
1278 second: t.second() as u8,
1279 timezone: None,
1280 }));
1281 }
1282
1283 Err(Error::parsing(
1284 format!("Invalid time format: '{}'", time_str),
1285 self.make_source(start_span),
1286 None::<String>,
1287 ))
1288 }
1289
1290 fn new_expression(
1295 &mut self,
1296 kind: ExpressionKind,
1297 source: Source,
1298 ) -> Result<Expression, Error> {
1299 self.expression_count += 1;
1300 if self.expression_count > self.max_expression_count {
1301 return Err(Error::resource_limit_exceeded(
1302 "max_expression_count",
1303 self.max_expression_count.to_string(),
1304 self.expression_count.to_string(),
1305 "Split logic into multiple rules to reduce expression count",
1306 Some(source),
1307 None,
1308 None,
1309 ));
1310 }
1311 Ok(Expression::new(kind, source))
1312 }
1313
1314 fn check_depth(&mut self) -> Result<(), Error> {
1315 if let Err(actual) = self.depth_tracker.push_depth() {
1316 let span = self.peek()?.span.clone();
1317 self.depth_tracker.pop_depth();
1318 return Err(Error::resource_limit_exceeded(
1319 "max_expression_depth",
1320 self.depth_tracker.max_depth().to_string(),
1321 actual.to_string(),
1322 "Simplify nested expressions or break into separate rules",
1323 Some(self.make_source(span)),
1324 None,
1325 None,
1326 ));
1327 }
1328 Ok(())
1329 }
1330
1331 fn parse_expression(&mut self) -> Result<Expression, Error> {
1332 self.check_depth()?;
1333 let result = self.parse_and_expression();
1334 self.depth_tracker.pop_depth();
1335 result
1336 }
1337
1338 fn parse_and_expression(&mut self) -> Result<Expression, Error> {
1339 let start_span = self.peek()?.span.clone();
1340 let mut left = self.parse_and_operand()?;
1341
1342 while self.at(&TokenKind::And)? {
1343 self.next()?; let right = self.parse_and_operand()?;
1345 let span = self.span_covering(
1346 &start_span,
1347 &right
1348 .source_location
1349 .as_ref()
1350 .map(|s| s.span.clone())
1351 .unwrap_or_else(|| start_span.clone()),
1352 );
1353 left = self.new_expression(
1354 ExpressionKind::LogicalAnd(Arc::new(left), Arc::new(right)),
1355 self.make_source(span),
1356 )?;
1357 }
1358
1359 Ok(left)
1360 }
1361
1362 fn parse_and_operand(&mut self) -> Result<Expression, Error> {
1363 if self.at(&TokenKind::Not)? {
1365 return self.parse_not_expression();
1366 }
1367
1368 self.parse_base_with_suffix()
1370 }
1371
1372 fn parse_not_expression(&mut self) -> Result<Expression, Error> {
1373 let not_tok = self.expect(&TokenKind::Not)?;
1374 let start_span = not_tok.span.clone();
1375
1376 self.check_depth()?;
1377 let operand = self.parse_and_operand()?;
1378 self.depth_tracker.pop_depth();
1379
1380 let end_span = operand
1381 .source_location
1382 .as_ref()
1383 .map(|s| s.span.clone())
1384 .unwrap_or_else(|| start_span.clone());
1385 let span = self.span_covering(&start_span, &end_span);
1386
1387 self.new_expression(
1388 ExpressionKind::LogicalNegation(Arc::new(operand), NegationType::Not),
1389 self.make_source(span),
1390 )
1391 }
1392
1393 fn parse_base_with_suffix(&mut self) -> Result<Expression, Error> {
1394 let start_span = self.peek()?.span.clone();
1395 let base = self.parse_base_expression()?;
1396
1397 let peeked = self.peek()?;
1399
1400 if is_comparison_operator(&peeked.kind) {
1402 return self.parse_comparison_suffix(base, start_span);
1403 }
1404
1405 if peeked.kind == TokenKind::Not {
1409 return self.parse_not_in_calendar_suffix(base, start_span);
1410 }
1411
1412 if peeked.kind == TokenKind::In {
1414 return self.parse_in_suffix(base, start_span);
1415 }
1416
1417 Ok(base)
1418 }
1419
1420 fn parse_comparison_suffix(
1421 &mut self,
1422 left: Expression,
1423 start_span: Span,
1424 ) -> Result<Expression, Error> {
1425 let operator = self.parse_comparison_operator()?;
1426
1427 let right = if self.at(&TokenKind::Not)? {
1429 self.parse_not_expression()?
1430 } else {
1431 let rhs = self.parse_base_expression()?;
1432 if self.at(&TokenKind::In)? {
1434 self.parse_in_suffix(rhs, start_span.clone())?
1435 } else {
1436 rhs
1437 }
1438 };
1439
1440 let end_span = right
1441 .source_location
1442 .as_ref()
1443 .map(|s| s.span.clone())
1444 .unwrap_or_else(|| start_span.clone());
1445 let span = self.span_covering(&start_span, &end_span);
1446
1447 self.new_expression(
1448 ExpressionKind::Comparison(Arc::new(left), operator, Arc::new(right)),
1449 self.make_source(span),
1450 )
1451 }
1452
1453 fn parse_comparison_operator(&mut self) -> Result<ComparisonComputation, Error> {
1454 let tok = self.next()?;
1455 match tok.kind {
1456 TokenKind::Gt => Ok(ComparisonComputation::GreaterThan),
1457 TokenKind::Lt => Ok(ComparisonComputation::LessThan),
1458 TokenKind::Gte => Ok(ComparisonComputation::GreaterThanOrEqual),
1459 TokenKind::Lte => Ok(ComparisonComputation::LessThanOrEqual),
1460 TokenKind::Is => {
1461 if self.at(&TokenKind::Not)? {
1463 self.next()?; Ok(ComparisonComputation::IsNot)
1465 } else {
1466 Ok(ComparisonComputation::Is)
1467 }
1468 }
1469 _ => Err(self.error_at_token(
1470 &tok,
1471 format!("Expected a comparison operator, found {}", tok.kind),
1472 )),
1473 }
1474 }
1475
1476 fn parse_not_in_calendar_suffix(
1477 &mut self,
1478 base: Expression,
1479 start_span: Span,
1480 ) -> Result<Expression, Error> {
1481 self.expect(&TokenKind::Not)?;
1482 self.expect(&TokenKind::In)?;
1483 self.expect(&TokenKind::Calendar)?;
1484 let unit = self.parse_calendar_unit()?;
1485 let end = self.peek()?.span.clone();
1486 let span = self.span_covering(&start_span, &end);
1487 self.new_expression(
1488 ExpressionKind::DateCalendar(DateCalendarKind::NotIn, unit, Arc::new(base)),
1489 self.make_source(span),
1490 )
1491 }
1492
1493 fn parse_in_suffix(&mut self, base: Expression, start_span: Span) -> Result<Expression, Error> {
1494 self.expect(&TokenKind::In)?;
1495
1496 let peeked = self.peek()?;
1497
1498 if peeked.kind == TokenKind::Past || peeked.kind == TokenKind::Future {
1500 let direction = self.next()?;
1501 let rel_kind = if direction.kind == TokenKind::Past {
1502 DateRelativeKind::InPast
1503 } else {
1504 DateRelativeKind::InFuture
1505 };
1506
1507 if self.at(&TokenKind::Calendar)? {
1509 self.next()?; let cal_kind = if direction.kind == TokenKind::Past {
1511 DateCalendarKind::Past
1512 } else {
1513 DateCalendarKind::Future
1514 };
1515 let unit = self.parse_calendar_unit()?;
1516 let end = self.peek()?.span.clone();
1517 let span = self.span_covering(&start_span, &end);
1518 return self.new_expression(
1519 ExpressionKind::DateCalendar(cal_kind, unit, Arc::new(base)),
1520 self.make_source(span),
1521 );
1522 }
1523
1524 let tolerance = if !self.at(&TokenKind::And)?
1526 && !self.at(&TokenKind::Unless)?
1527 && !self.at(&TokenKind::Then)?
1528 && !self.at(&TokenKind::Eof)?
1529 && !is_comparison_operator(&self.peek()?.kind)
1530 {
1531 let peek_kind = self.peek()?.kind.clone();
1532 if peek_kind == TokenKind::NumberLit
1533 || peek_kind == TokenKind::LParen
1534 || can_be_reference_segment(&peek_kind)
1535 || is_math_function(&peek_kind)
1536 {
1537 Some(Arc::new(self.parse_base_expression()?))
1538 } else {
1539 None
1540 }
1541 } else {
1542 None
1543 };
1544
1545 let end = self.peek()?.span.clone();
1546 let span = self.span_covering(&start_span, &end);
1547 return self.new_expression(
1548 ExpressionKind::DateRelative(rel_kind, Arc::new(base), tolerance),
1549 self.make_source(span),
1550 );
1551 }
1552
1553 if peeked.kind == TokenKind::Calendar {
1555 self.next()?; let unit = self.parse_calendar_unit()?;
1557 let end = self.peek()?.span.clone();
1558 let span = self.span_covering(&start_span, &end);
1559 return self.new_expression(
1560 ExpressionKind::DateCalendar(DateCalendarKind::Current, unit, Arc::new(base)),
1561 self.make_source(span),
1562 );
1563 }
1564
1565 let target_tok = self.next()?;
1567 let target = conversion_target_from_token(&target_tok.kind, &target_tok.text);
1568
1569 let converted = self.new_expression(
1570 ExpressionKind::UnitConversion(Arc::new(base), target),
1571 self.make_source(self.span_covering(&start_span, &target_tok.span)),
1572 )?;
1573
1574 if is_comparison_operator(&self.peek()?.kind) {
1576 return self.parse_comparison_suffix(converted, start_span);
1577 }
1578
1579 Ok(converted)
1580 }
1581
1582 fn parse_calendar_unit(&mut self) -> Result<CalendarUnit, Error> {
1583 let tok = self.next()?;
1584 if !is_calendar_unit_token(&tok.kind) {
1585 return Err(self.error_at_token(
1586 &tok,
1587 format!("Expected 'year', 'month', or 'week', found '{}'", tok.text),
1588 ));
1589 }
1590 Ok(token_kind_to_calendar_unit(&tok.kind))
1591 }
1592
1593 fn parse_base_expression(&mut self) -> Result<Expression, Error> {
1598 let start_span = self.peek()?.span.clone();
1599 let mut left = self.parse_term()?;
1600
1601 while self.at_any(&[TokenKind::Plus, TokenKind::Minus])? {
1602 let op_tok = self.next()?;
1605 let operation = match op_tok.kind {
1606 TokenKind::Plus => ArithmeticComputation::Add,
1607 TokenKind::Minus => ArithmeticComputation::Subtract,
1608 _ => unreachable!("BUG: only + and - should reach here"),
1609 };
1610
1611 let right = self.parse_term()?;
1612 let end_span = right
1613 .source_location
1614 .as_ref()
1615 .map(|s| s.span.clone())
1616 .unwrap_or_else(|| start_span.clone());
1617 let span = self.span_covering(&start_span, &end_span);
1618
1619 left = self.new_expression(
1620 ExpressionKind::Arithmetic(Arc::new(left), operation, Arc::new(right)),
1621 self.make_source(span),
1622 )?;
1623 }
1624
1625 Ok(left)
1626 }
1627
1628 fn parse_term(&mut self) -> Result<Expression, Error> {
1629 let start_span = self.peek()?.span.clone();
1630 let mut left = self.parse_power()?;
1631
1632 while self.at_any(&[TokenKind::Star, TokenKind::Slash, TokenKind::Percent])? {
1633 let op_tok = self.next()?;
1636 let operation = match op_tok.kind {
1637 TokenKind::Star => ArithmeticComputation::Multiply,
1638 TokenKind::Slash => ArithmeticComputation::Divide,
1639 TokenKind::Percent => ArithmeticComputation::Modulo,
1640 _ => unreachable!("BUG: only *, /, % should reach here"),
1641 };
1642
1643 let right = self.parse_power()?;
1644 let end_span = right
1645 .source_location
1646 .as_ref()
1647 .map(|s| s.span.clone())
1648 .unwrap_or_else(|| start_span.clone());
1649 let span = self.span_covering(&start_span, &end_span);
1650
1651 left = self.new_expression(
1652 ExpressionKind::Arithmetic(Arc::new(left), operation, Arc::new(right)),
1653 self.make_source(span),
1654 )?;
1655 }
1656
1657 Ok(left)
1658 }
1659
1660 fn parse_power(&mut self) -> Result<Expression, Error> {
1661 let start_span = self.peek()?.span.clone();
1662 let left = self.parse_factor()?;
1663
1664 if self.at(&TokenKind::Caret)? {
1665 self.next()?;
1666 self.check_depth()?;
1667 let right = self.parse_power()?;
1668 self.depth_tracker.pop_depth();
1669 let end_span = right
1670 .source_location
1671 .as_ref()
1672 .map(|s| s.span.clone())
1673 .unwrap_or_else(|| start_span.clone());
1674 let span = self.span_covering(&start_span, &end_span);
1675
1676 return self.new_expression(
1677 ExpressionKind::Arithmetic(
1678 Arc::new(left),
1679 ArithmeticComputation::Power,
1680 Arc::new(right),
1681 ),
1682 self.make_source(span),
1683 );
1684 }
1685
1686 Ok(left)
1687 }
1688
1689 fn parse_factor(&mut self) -> Result<Expression, Error> {
1690 let peeked = self.peek()?;
1691 let start_span = peeked.span.clone();
1692
1693 if peeked.kind == TokenKind::Minus {
1694 self.next()?;
1695 let operand = self.parse_primary_or_math()?;
1696 let end_span = operand
1697 .source_location
1698 .as_ref()
1699 .map(|s| s.span.clone())
1700 .unwrap_or_else(|| start_span.clone());
1701 let span = self.span_covering(&start_span, &end_span);
1702
1703 let zero = self.new_expression(
1704 ExpressionKind::Literal(Value::Number(Decimal::ZERO)),
1705 self.make_source(start_span),
1706 )?;
1707 return self.new_expression(
1708 ExpressionKind::Arithmetic(
1709 Arc::new(zero),
1710 ArithmeticComputation::Subtract,
1711 Arc::new(operand),
1712 ),
1713 self.make_source(span),
1714 );
1715 }
1716
1717 if peeked.kind == TokenKind::Plus {
1718 self.next()?;
1719 return self.parse_primary_or_math();
1720 }
1721
1722 self.parse_primary_or_math()
1723 }
1724
1725 fn parse_primary_or_math(&mut self) -> Result<Expression, Error> {
1726 let peeked = self.peek()?;
1727
1728 if is_math_function(&peeked.kind) {
1730 return self.parse_math_function();
1731 }
1732
1733 self.parse_primary()
1734 }
1735
1736 fn parse_math_function(&mut self) -> Result<Expression, Error> {
1737 let func_tok = self.next()?;
1738 let start_span = func_tok.span.clone();
1739
1740 let operator = match func_tok.kind {
1741 TokenKind::Sqrt => MathematicalComputation::Sqrt,
1742 TokenKind::Sin => MathematicalComputation::Sin,
1743 TokenKind::Cos => MathematicalComputation::Cos,
1744 TokenKind::Tan => MathematicalComputation::Tan,
1745 TokenKind::Asin => MathematicalComputation::Asin,
1746 TokenKind::Acos => MathematicalComputation::Acos,
1747 TokenKind::Atan => MathematicalComputation::Atan,
1748 TokenKind::Log => MathematicalComputation::Log,
1749 TokenKind::Exp => MathematicalComputation::Exp,
1750 TokenKind::Abs => MathematicalComputation::Abs,
1751 TokenKind::Floor => MathematicalComputation::Floor,
1752 TokenKind::Ceil => MathematicalComputation::Ceil,
1753 TokenKind::Round => MathematicalComputation::Round,
1754 _ => unreachable!("BUG: only math functions should reach here"),
1755 };
1756
1757 self.check_depth()?;
1758 let operand = self.parse_base_expression()?;
1759 self.depth_tracker.pop_depth();
1760
1761 let end_span = operand
1762 .source_location
1763 .as_ref()
1764 .map(|s| s.span.clone())
1765 .unwrap_or_else(|| start_span.clone());
1766 let span = self.span_covering(&start_span, &end_span);
1767
1768 self.new_expression(
1769 ExpressionKind::MathematicalComputation(operator, Arc::new(operand)),
1770 self.make_source(span),
1771 )
1772 }
1773
1774 fn parse_primary(&mut self) -> Result<Expression, Error> {
1775 let peeked = self.peek()?;
1776 let start_span = peeked.span.clone();
1777
1778 match &peeked.kind {
1779 TokenKind::LParen => {
1781 self.next()?; let inner = self.parse_expression()?;
1783 self.expect(&TokenKind::RParen)?;
1784 Ok(inner)
1785 }
1786
1787 TokenKind::Now => {
1789 let tok = self.next()?;
1790 self.new_expression(ExpressionKind::Now, self.make_source(tok.span))
1791 }
1792
1793 TokenKind::StringLit => {
1795 let tok = self.next()?;
1796 let content = unquote_string(&tok.text);
1797 self.new_expression(
1798 ExpressionKind::Literal(Value::Text(content)),
1799 self.make_source(tok.span),
1800 )
1801 }
1802
1803 k if is_boolean_keyword(k) => {
1805 let tok = self.next()?;
1806 self.new_expression(
1807 ExpressionKind::Literal(Value::Boolean(token_kind_to_boolean_value(&tok.kind))),
1808 self.make_source(tok.span),
1809 )
1810 }
1811
1812 TokenKind::NumberLit => self.parse_number_expression(),
1814
1815 k if can_be_reference_segment(k) => {
1817 let reference = self.parse_expression_reference()?;
1818 let end_span = self.peek()?.span.clone();
1819 let span = self.span_covering(&start_span, &end_span);
1820 self.new_expression(ExpressionKind::Reference(reference), self.make_source(span))
1821 }
1822
1823 _ => {
1824 let tok = self.next()?;
1825 Err(self.error_at_token(
1826 &tok,
1827 format!("Expected an expression, found '{}'", tok.text),
1828 ))
1829 }
1830 }
1831 }
1832
1833 fn parse_number_expression(&mut self) -> Result<Expression, Error> {
1834 let num_tok = self.next()?;
1835 let num_text = num_tok.text.clone();
1836 let start_span = num_tok.span.clone();
1837
1838 if num_text.len() == 4
1840 && num_text.chars().all(|c| c.is_ascii_digit())
1841 && self.at(&TokenKind::Minus)?
1842 {
1843 let minus_span = self.peek()?.span.clone();
1850 if minus_span.start == start_span.end {
1852 let value = self.parse_date_literal(num_text, start_span.clone())?;
1853 return self
1854 .new_expression(ExpressionKind::Literal(value), self.make_source(start_span));
1855 }
1856 }
1857
1858 if num_text.len() == 2
1860 && num_text.chars().all(|c| c.is_ascii_digit())
1861 && self.at(&TokenKind::Colon)?
1862 {
1863 let colon_span = self.peek()?.span.clone();
1864 if colon_span.start == start_span.end {
1865 let value = self.try_parse_time_literal(num_text, start_span.clone())?;
1866 return self
1867 .new_expression(ExpressionKind::Literal(value), self.make_source(start_span));
1868 }
1869 }
1870
1871 if self.at(&TokenKind::PercentPercent)? {
1873 let pp_tok = self.next()?;
1874 if let Ok(next_peek) = self.peek() {
1875 if next_peek.kind == TokenKind::NumberLit {
1876 return Err(self.error_at_token(
1877 &pp_tok,
1878 "Permille literal cannot be followed by a digit",
1879 ));
1880 }
1881 }
1882 let decimal = parse_decimal_string(&num_text, &start_span, self)?;
1883 let ratio_value = decimal / Decimal::from(1000);
1884 return self.new_expression(
1885 ExpressionKind::Literal(Value::Ratio(ratio_value, Some("permille".to_string()))),
1886 self.make_source(start_span),
1887 );
1888 }
1889
1890 if self.at(&TokenKind::Percent)? {
1892 let pct_span = self.peek()?.span.clone();
1893 let pct_tok = self.next()?;
1896 if let Ok(next_peek) = self.peek() {
1897 if next_peek.kind == TokenKind::NumberLit || next_peek.kind == TokenKind::Percent {
1898 return Err(self.error_at_token(
1899 &pct_tok,
1900 "Percent literal cannot be followed by a digit",
1901 ));
1902 }
1903 }
1904 let decimal = parse_decimal_string(&num_text, &start_span, self)?;
1905 let ratio_value = decimal / Decimal::from(100);
1906 return self.new_expression(
1907 ExpressionKind::Literal(Value::Ratio(ratio_value, Some("percent".to_string()))),
1908 self.make_source(self.span_covering(&start_span, &pct_span)),
1909 );
1910 }
1911
1912 if self.at(&TokenKind::PercentKw)? {
1914 self.next()?;
1915 let decimal = parse_decimal_string(&num_text, &start_span, self)?;
1916 let ratio_value = decimal / Decimal::from(100);
1917 return self.new_expression(
1918 ExpressionKind::Literal(Value::Ratio(ratio_value, Some("percent".to_string()))),
1919 self.make_source(start_span),
1920 );
1921 }
1922
1923 if self.at(&TokenKind::Permille)? {
1925 self.next()?;
1926 let decimal = parse_decimal_string(&num_text, &start_span, self)?;
1927 let ratio_value = decimal / Decimal::from(1000);
1928 return self.new_expression(
1929 ExpressionKind::Literal(Value::Ratio(ratio_value, Some("permille".to_string()))),
1930 self.make_source(start_span),
1931 );
1932 }
1933
1934 if is_duration_unit(&self.peek()?.kind) && self.peek()?.kind != TokenKind::PercentKw {
1936 let unit_tok = self.next()?;
1937 let decimal = parse_decimal_string(&num_text, &start_span, self)?;
1938 let duration_unit = token_kind_to_duration_unit(&unit_tok.kind);
1939 return self.new_expression(
1940 ExpressionKind::Literal(Value::Duration(decimal, duration_unit)),
1941 self.make_source(self.span_covering(&start_span, &unit_tok.span)),
1942 );
1943 }
1944
1945 if can_be_label(&self.peek()?.kind) {
1947 let unit_tok = self.next()?;
1948 let decimal = parse_decimal_string(&num_text, &start_span, self)?;
1949 return self.new_expression(
1950 ExpressionKind::UnresolvedUnitLiteral(decimal, unit_tok.text.clone()),
1951 self.make_source(self.span_covering(&start_span, &unit_tok.span)),
1952 );
1953 }
1954
1955 let decimal = parse_decimal_string(&num_text, &start_span, self)?;
1957 self.new_expression(
1958 ExpressionKind::Literal(Value::Number(decimal)),
1959 self.make_source(start_span),
1960 )
1961 }
1962
1963 fn parse_expression_reference(&mut self) -> Result<Reference, Error> {
1964 let mut segments = Vec::new();
1965
1966 let first = self.next()?;
1967 segments.push(first.text.clone());
1968
1969 while self.at(&TokenKind::Dot)? {
1970 self.next()?; let seg = self.next()?;
1972 if !can_be_reference_segment(&seg.kind) {
1973 return Err(self.error_at_token(
1974 &seg,
1975 format!("Expected an identifier after '.', found {}", seg.kind),
1976 ));
1977 }
1978 segments.push(seg.text.clone());
1979 }
1980
1981 Ok(Reference::from_path(segments))
1982 }
1983}
1984
1985fn unquote_string(s: &str) -> String {
1990 if s.len() >= 2 && s.starts_with('"') && s.ends_with('"') {
1991 s[1..s.len() - 1].to_string()
1992 } else {
1993 s.to_string()
1994 }
1995}
1996
1997fn parse_decimal_string(text: &str, span: &Span, parser: &Parser) -> Result<Decimal, Error> {
1998 let clean = text.replace(['_', ','], "");
1999 Decimal::from_str(&clean).map_err(|_| {
2000 Error::parsing(
2001 format!(
2002 "Invalid number: '{}'. Expected a valid decimal number (e.g., 42, 3.14, 1_000_000)",
2003 text
2004 ),
2005 parser.make_source(span.clone()),
2006 None::<String>,
2007 )
2008 })
2009}
2010
2011fn is_comparison_operator(kind: &TokenKind) -> bool {
2012 matches!(
2013 kind,
2014 TokenKind::Gt | TokenKind::Lt | TokenKind::Gte | TokenKind::Lte | TokenKind::Is
2015 )
2016}
2017
2018impl TokenKind {
2020 fn is_identifier_like(&self) -> bool {
2021 matches!(self, TokenKind::Identifier)
2022 || can_be_label(self)
2023 || is_type_keyword(self)
2024 || is_boolean_keyword(self)
2025 || is_duration_unit(self)
2026 || is_math_function(self)
2027 }
2028}