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_repository_qualifier_segment, is_boolean_keyword, is_keyword,
6 is_math_function, is_spec_body_keyword, token_is_calendar_period_marker,
7 token_kind_to_boolean_value, token_kind_to_primitive, Lexer, LexerCheckpoint, Token, TokenKind,
8};
9use crate::parsing::source::Source;
10use indexmap::IndexMap;
11use rust_decimal::Decimal;
12use std::sync::Arc;
13
14#[derive(Debug)]
15pub struct ParseResult {
16 pub repositories: IndexMap<Arc<LemmaRepository>, Vec<LemmaSpec>>,
17 pub expression_count: usize,
18}
19
20impl ParseResult {
21 #[must_use]
23 pub fn flatten_specs(&self) -> Vec<&LemmaSpec> {
24 self.repositories
25 .values()
26 .flat_map(|specs| specs.iter())
27 .collect()
28 }
29
30 #[must_use]
31 pub fn into_flattened_specs(self) -> Vec<LemmaSpec> {
32 self.repositories.into_values().flatten().collect()
33 }
34}
35
36pub fn parse(
37 content: &str,
38 source_type: crate::parsing::source::SourceType,
39 limits: &ResourceLimits,
40) -> Result<ParseResult, Error> {
41 if content.len() > limits.max_source_size_bytes {
42 return Err(Error::resource_limit_exceeded(
43 "max_source_size_bytes",
44 format!(
45 "{} bytes ({} MB)",
46 limits.max_source_size_bytes,
47 limits.max_source_size_bytes / (1024 * 1024)
48 ),
49 format!(
50 "{} bytes ({:.2} MB)",
51 content.len(),
52 content.len() as f64 / (1024.0 * 1024.0)
53 ),
54 "Reduce source size or split into multiple specs",
55 None,
56 None,
57 None,
58 ));
59 }
60
61 let mut parser = Parser::new(content, source_type, limits);
62 let repositories = parser.parse_file()?;
63 let mut result = ParseResult {
64 repositories,
65 expression_count: parser.expression_count,
66 };
67 canonicalize_parse_result(&mut result);
68 Ok(result)
69}
70
71fn canonicalize_parse_result(result: &mut ParseResult) {
72 let old = std::mem::take(&mut result.repositories);
73 let mut new_map: IndexMap<Arc<LemmaRepository>, Vec<LemmaSpec>> = IndexMap::new();
74 for (repo, mut specs) in old {
75 let mut canonical_repo = (*repo).clone();
76 canonicalize_repository(&mut canonical_repo);
77 for spec in &mut specs {
78 canonicalize_lemma_spec(spec);
79 }
80 new_map
81 .entry(Arc::new(canonical_repo))
82 .or_default()
83 .extend(specs);
84 }
85 result.repositories = new_map;
86}
87
88struct Parser {
89 lexer: Lexer,
90 source_type: crate::parsing::source::SourceType,
91 depth_tracker: DepthTracker,
92 expression_count: usize,
93 max_expression_count: usize,
94 max_spec_name_length: usize,
95 max_data_name_length: usize,
96 max_rule_name_length: usize,
97 last_span: Span,
98}
99
100impl Parser {
101 fn new(
102 content: &str,
103 source_type: crate::parsing::source::SourceType,
104 limits: &ResourceLimits,
105 ) -> Self {
106 Parser {
107 lexer: Lexer::new(content, &source_type),
108 source_type,
109 depth_tracker: DepthTracker::with_max_depth(limits.max_expression_depth),
110 expression_count: 0,
111 max_expression_count: limits.max_expression_count,
112 max_spec_name_length: crate::limits::MAX_SPEC_NAME_LENGTH,
113 max_data_name_length: crate::limits::MAX_DATA_NAME_LENGTH,
114 max_rule_name_length: crate::limits::MAX_RULE_NAME_LENGTH,
115 last_span: Span {
116 start: 0,
117 end: 0,
118 line: 1,
119 col: 0,
120 },
121 }
122 }
123
124 fn source_type(&self) -> crate::parsing::source::SourceType {
125 self.source_type.clone()
126 }
127
128 fn peek(&mut self) -> Result<&Token, Error> {
129 self.lexer.peek()
130 }
131
132 fn next(&mut self) -> Result<Token, Error> {
133 let token = self.lexer.next_token()?;
134 self.last_span = token.span.clone();
135 Ok(token)
136 }
137
138 fn at(&mut self, kind: &TokenKind) -> Result<bool, Error> {
139 Ok(&self.peek()?.kind == kind)
140 }
141
142 fn at_any(&mut self, kinds: &[TokenKind]) -> Result<bool, Error> {
143 let current = &self.peek()?.kind;
144 Ok(kinds.contains(current))
145 }
146
147 fn checkpoint(&self) -> (LexerCheckpoint, usize) {
148 (self.lexer.checkpoint(), self.expression_count)
149 }
150
151 fn restore(&mut self, checkpoint: (LexerCheckpoint, usize)) {
152 self.lexer.restore(checkpoint.0);
153 self.expression_count = checkpoint.1;
154 }
155
156 fn expect(&mut self, kind: &TokenKind) -> Result<Token, Error> {
157 let token = self.next()?;
158 if &token.kind == kind {
159 Ok(token)
160 } else {
161 Err(self.error_at_token(&token, format!("Expected {}, found {}", kind, token.kind)))
162 }
163 }
164
165 fn at_calendar_period_marker(&mut self) -> Result<bool, Error> {
166 Ok(token_is_calendar_period_marker(self.peek()?))
167 }
168
169 fn expect_calendar_period_marker(&mut self) -> Result<Token, Error> {
170 let token = self.next()?;
171 if token_is_calendar_period_marker(&token) {
172 Ok(token)
173 } else {
174 Err(self.error_at_token(&token, "Expected 'calendar' (date-period predicate marker)"))
175 }
176 }
177
178 fn next_calendar_period_marker(&mut self) -> Result<Token, Error> {
179 self.expect_calendar_period_marker()
180 }
181
182 fn error_at_token(&self, token: &Token, message: impl Into<String>) -> Error {
183 Error::parsing(
184 message,
185 Source::new(self.source_type(), token.span.clone()),
186 None::<String>,
187 )
188 }
189
190 fn error_at_token_with_suggestion(
191 &self,
192 token: &Token,
193 message: impl Into<String>,
194 suggestion: impl Into<String>,
195 ) -> Error {
196 Error::parsing(
197 message,
198 Source::new(self.source_type(), token.span.clone()),
199 Some(suggestion),
200 )
201 }
202
203 fn parse_spec_ref_trailing_effective(&mut self) -> Result<Option<DateTimeValue>, Error> {
204 let mut effective = None;
205 if self.at(&TokenKind::NumberLit)? {
206 let peeked = self.peek()?;
207 if peeked.text.len() == 4 && peeked.text.chars().all(|c| c.is_ascii_digit()) {
208 effective = self.try_parse_effective_from()?;
209 }
210 }
211 Ok(effective)
212 }
213
214 fn make_source(&self, span: Span) -> Source {
215 Source::new(self.source_type(), span)
216 }
217
218 fn span_from(&self, start: &Span) -> Span {
219 Span {
222 start: start.start,
223 end: start.end.max(start.start),
224 line: start.line,
225 col: start.col,
226 }
227 }
228
229 fn span_covering(&self, start: &Span, end: &Span) -> Span {
230 Span {
231 start: start.start,
232 end: end.end,
233 line: start.line,
234 col: start.col,
235 }
236 }
237
238 fn parse_file(&mut self) -> Result<IndexMap<Arc<LemmaRepository>, Vec<LemmaSpec>>, Error> {
243 let mut map: IndexMap<Arc<LemmaRepository>, Vec<LemmaSpec>> = IndexMap::new();
244 let mut current_repo = Arc::new(LemmaRepository::new(None));
245
246 loop {
247 if self.at(&TokenKind::Eof)? {
248 break;
249 }
250
251 if self.at(&TokenKind::Repo)? {
252 let repo_token = self.expect(&TokenKind::Repo)?;
253 let start_line = repo_token.span.line;
254 let (qualifier, _) = self.parse_repository_qualifier()?;
255 crate::limits::check_max_length(
256 &qualifier.name,
257 self.max_spec_name_length,
258 "repository name",
259 Some(Source::new(self.source_type(), repo_token.span)),
260 )?;
261 current_repo = Arc::new(
262 LemmaRepository::new(Some(qualifier.name)).with_start_line(start_line),
263 );
264 map.entry(Arc::clone(¤t_repo)).or_default();
265 continue;
266 }
267
268 if self.at(&TokenKind::Spec)? {
269 let spec = self.parse_spec()?;
270 map.entry(Arc::clone(¤t_repo)).or_default().push(spec);
271 continue;
272 }
273
274 let token = self.next()?;
275 return Err(self.error_at_token_with_suggestion(
276 &token,
277 format!(
278 "Expected a top-level `repo` or `spec` declaration, found {}",
279 token.kind
280 ),
281 "Each Lemma file is a sequence of optional `repo <name>` sections followed by `spec <name>` blocks",
282 ));
283 }
284
285 Ok(map)
286 }
287
288 fn parse_spec(&mut self) -> Result<LemmaSpec, Error> {
289 let spec_token = self.expect(&TokenKind::Spec)?;
290 let start_line = spec_token.span.line;
291
292 let (name, name_span) = self.parse_spec_name()?;
293 crate::limits::check_max_length(
294 &name,
295 self.max_spec_name_length,
296 "spec",
297 Some(Source::new(self.source_type(), name_span)),
298 )?;
299
300 let effective_from = self.try_parse_effective_from()?;
301
302 let commentary = self.try_parse_commentary()?;
303
304 let mut spec = LemmaSpec::new(name.clone())
305 .with_source_type(self.source_type())
306 .with_start_line(start_line);
307 spec.effective_from = crate::parsing::ast::EffectiveDate::from_option(effective_from);
308
309 if let Some(commentary_text) = commentary {
310 spec = spec.set_commentary(commentary_text);
311 }
312
313 let mut data = Vec::new();
317 let mut rules = Vec::new();
318 let mut meta_fields = Vec::new();
319
320 loop {
321 let peek_kind = self.peek()?.kind.clone();
322 match peek_kind {
323 TokenKind::Data => {
324 let datum = self.parse_data()?;
325 data.push(datum);
326 }
327 TokenKind::With => {
328 let datum = self.parse_with()?;
329 data.push(datum);
330 }
331 TokenKind::Rule => {
332 let rule = self.parse_rule()?;
333 rules.push(rule);
334 }
335 TokenKind::Meta => {
336 let meta = self.parse_meta()?;
337 meta_fields.push(meta);
338 }
339 TokenKind::Uses => {
340 let uses_data = self.parse_uses_statement()?;
341 data.push(uses_data);
342 }
343 TokenKind::Spec | TokenKind::Repo | TokenKind::Eof => break,
344 _ => {
345 let token = self.next()?;
346 return Err(self.error_at_token_with_suggestion(
347 &token,
348 format!(
349 "Expected 'data', 'with', 'rule', 'meta', 'uses', or a new 'spec', found '{}'",
350 token.text
351 ),
352 "Check the spelling or add the appropriate keyword",
353 ));
354 }
355 }
356 }
357
358 for data in data {
359 spec = spec.add_data(data);
360 }
361 for rule in rules {
362 spec = spec.add_rule(rule);
363 }
364 for meta in meta_fields {
365 spec = spec.add_meta_field(meta);
366 }
367
368 Ok(spec)
369 }
370
371 fn parse_spec_name(&mut self) -> Result<(String, Span), Error> {
377 if self.at(&TokenKind::At)? {
378 let at_tok = self.next()?;
379 return Err(Error::parsing(
380 "'@' is not allowed in spec names; it is valid for repository names (`repo @org/name`) and qualifiers (`uses @org/name`)",
381 self.make_source(at_tok.span),
382 Some(
383 "Write `spec my_spec`, then reference registry specs as `uses alias: @org/repo spec_name` or `data x: alias.TypeName` after importing with `uses`.",
384 ),
385 ));
386 }
387
388 let first = self.next()?;
389 if !first.kind.is_identifier_like() {
390 return Err(self.error_at_token(
391 &first,
392 format!("Expected a spec name, found {}", first.kind),
393 ));
394 }
395 let mut name = first.text.clone();
396 let start_span = first.span.clone();
397 let mut end_span = first.span.clone();
398
399 loop {
400 if self.at(&TokenKind::Slash)? {
401 self.next()?;
402 let seg = self.next()?;
403 if !seg.kind.is_identifier_like() {
404 return Err(self.error_at_token(
405 &seg,
406 format!(
407 "Expected identifier after '/' in spec name, found {}",
408 seg.kind
409 ),
410 ));
411 }
412 name.push('/');
413 name.push_str(&seg.text);
414 end_span = seg.span.clone();
415 } else if self.at(&TokenKind::Dot)? {
416 self.next()?;
417 let seg = self.next()?;
418 if !seg.kind.is_identifier_like() {
419 return Err(self.error_at_token(
420 &seg,
421 format!(
422 "Expected identifier after '.' in spec name, found {}",
423 seg.kind
424 ),
425 ));
426 }
427 name.push('.');
428 name.push_str(&seg.text);
429 end_span = seg.span.clone();
430 } else if self.at(&TokenKind::Minus)? {
431 let minus_span = self.peek()?.span.clone();
432 self.next()?;
433 let peeked = self.peek()?;
434 if !peeked.kind.is_identifier_like() {
435 let span = self.span_covering(&start_span, &minus_span);
436 return Err(Error::parsing(
437 "Trailing '-' after spec name",
438 self.make_source(span),
439 None::<String>,
440 ));
441 }
442 let seg = self.next()?;
443 name.push('-');
444 name.push_str(&seg.text);
445 end_span = seg.span.clone();
446 } else {
447 break;
448 }
449 }
450
451 let full_span = self.span_covering(&start_span, &end_span);
452 Ok((name, full_span))
453 }
454
455 fn parse_repository_qualifier(&mut self) -> Result<(RepositoryQualifier, Span), Error> {
463 let has_at = self.at(&TokenKind::At)?;
464 let start_span = if has_at {
465 let at_tok = self.next()?;
466 at_tok.span.clone()
467 } else {
468 Span {
469 start: 0,
470 end: 0,
471 line: 0,
472 col: 0,
473 }
474 };
475
476 let first = self.next()?;
477 if !can_be_repository_qualifier_segment(&first.kind) {
478 return Err(self.error_at_token(
479 &first,
480 format!(
481 "Expected a repository qualifier segment, found {}",
482 first.kind
483 ),
484 ));
485 }
486 if !has_at && is_keyword(&first.kind) {
487 return Err(self.error_at_token(
488 &first,
489 format!(
490 "'{}' is a reserved keyword and cannot be used as a repository name",
491 first.text
492 ),
493 ));
494 }
495 let start_span = if has_at {
496 start_span
497 } else {
498 first.span.clone()
499 };
500 let mut name = first.text.clone();
501
502 loop {
503 let next_kind = self.peek()?.kind.clone();
504 match next_kind {
505 TokenKind::Slash => {
506 self.next()?;
507 name.push('/');
508 let seg = self.next()?;
509 if !can_be_repository_qualifier_segment(&seg.kind) {
510 return Err(self.error_at_token(
511 &seg,
512 format!(
513 "Expected identifier after '/' in repository qualifier segment, found {}",
514 seg.kind
515 ),
516 ));
517 }
518 name.push_str(&seg.text);
519 }
520 TokenKind::Dot => {
521 self.next()?;
522 name.push('.');
523 let seg = self.next()?;
524 if !can_be_repository_qualifier_segment(&seg.kind) {
525 return Err(self.error_at_token(
526 &seg,
527 format!(
528 "Expected identifier after '.' in repository qualifier segment, found {}",
529 seg.kind
530 ),
531 ));
532 }
533 name.push_str(&seg.text);
534 }
535 TokenKind::Minus => {
536 let minus_text_peek = self.lexer.peek_second()?;
537 if !can_be_repository_qualifier_segment(&minus_text_peek.kind) {
538 break;
539 }
540 self.next()?;
541 name.push('-');
542 let seg = self.next()?;
543 name.push_str(&seg.text);
544 }
545 _ => break,
546 }
547 }
548
549 if has_at {
550 name.insert(0, '@');
551 }
552
553 let full_span = self.span_covering(&start_span, &self.last_span);
554 Ok((RepositoryQualifier { name }, full_span))
555 }
556
557 pub fn parse_spec_ref_target(&mut self) -> Result<SpecRef, Error> {
559 let mut repository = None;
560 let mut repository_span = None;
561
562 if self.at(&TokenKind::At)? {
563 let (q, span) = self.parse_repository_qualifier()?;
564 repository = Some(q);
565 repository_span = Some(span);
566 } else {
567 let saved_state = self.lexer.clone();
568 if let Ok((potential_repository, span)) = self.parse_repository_qualifier() {
569 if let Ok(next_tok) = self.peek() {
570 if next_tok.kind.is_identifier_like() {
571 repository = Some(potential_repository);
572 repository_span = Some(span);
573 } else {
574 self.lexer = saved_state;
575 }
576 } else {
577 self.lexer = saved_state;
578 }
579 } else {
580 self.lexer = saved_state;
581 }
582 }
583
584 let (spec_name, spec_name_span) = self.parse_spec_name()?;
585 let effective = self.parse_spec_ref_trailing_effective()?;
586 let target_span = self.span_covering(&spec_name_span, &self.last_span);
587
588 let has_repository = repository.is_some();
589 Ok(SpecRef {
590 name: spec_name,
591 repository,
592 effective,
593 repository_span: if has_repository {
594 repository_span
595 } else {
596 None
597 },
598 target_span: Some(target_span),
599 })
600 }
601
602 fn try_parse_effective_from(&mut self) -> Result<Option<DateTimeValue>, Error> {
603 if !self.at(&TokenKind::NumberLit)? {
608 return Ok(None);
609 }
610
611 let peeked = self.peek()?;
612 let peeked_text = peeked.text.clone();
613 let peeked_span = peeked.span.clone();
614
615 if peeked_text.len() == 4 && peeked_text.chars().all(|c| c.is_ascii_digit()) {
617 let mut dt_str = String::new();
619 let num_tok = self.next()?; dt_str.push_str(&num_tok.text);
621
622 while self.at(&TokenKind::Minus)? {
624 self.next()?; dt_str.push('-');
626 let part = self.next()?;
627 dt_str.push_str(&part.text);
628 }
629
630 if self.at(&TokenKind::Identifier)? {
632 let peeked = self.peek()?;
633 if peeked.text.starts_with('T') || peeked.text.starts_with('t') {
634 let time_part = self.next()?;
635 dt_str.push_str(&time_part.text);
636 while self.at(&TokenKind::Colon)? {
638 self.next()?;
639 dt_str.push(':');
640 let part = self.next()?;
641 dt_str.push_str(&part.text);
642 }
643 if self.at(&TokenKind::Plus)? {
645 self.next()?;
646 dt_str.push('+');
647 let tz_part = self.next()?;
648 dt_str.push_str(&tz_part.text);
649 if self.at(&TokenKind::Colon)? {
650 self.next()?;
651 dt_str.push(':');
652 let tz_min = self.next()?;
653 dt_str.push_str(&tz_min.text);
654 }
655 }
656 }
657 }
658
659 if let Ok(dtv) = dt_str.parse::<DateTimeValue>() {
661 return Ok(Some(dtv));
662 }
663
664 return Err(Error::parsing(
665 format!("Invalid date/time in spec declaration: '{}'", dt_str),
666 self.make_source(peeked_span),
667 None::<String>,
668 ));
669 }
670
671 Ok(None)
672 }
673
674 fn try_parse_commentary(&mut self) -> Result<Option<String>, Error> {
675 if !self.at(&TokenKind::Commentary)? {
676 return Ok(None);
677 }
678 let token = self.next()?;
679 let trimmed = token.text.trim().to_string();
680 if trimmed.is_empty() {
681 Ok(None)
682 } else {
683 Ok(Some(trimmed))
684 }
685 }
686
687 fn parse_data(&mut self) -> Result<LemmaData, Error> {
692 let data_token = self.expect(&TokenKind::Data)?;
693 let start_span = data_token.span.clone();
694
695 let reference = self.parse_reference()?;
696 for segment in reference
697 .segments
698 .iter()
699 .chain(std::iter::once(&reference.name))
700 {
701 crate::limits::check_max_length(
702 segment,
703 self.max_data_name_length,
704 "data",
705 Some(Source::new(self.source_type(), start_span.clone())),
706 )?;
707 }
708
709 self.expect(&TokenKind::Colon)?;
710
711 if !reference.segments.is_empty() {
712 let tok = self.peek()?.clone();
713 return Err(self.error_at_token_with_suggestion(
714 &tok,
715 "Dotted paths require `with`; `data` declares types and values on local names only.",
716 "Use `with path.to.slot: <value or reference>` to assign on an imported or nested slot.",
717 ));
718 }
719
720 let value = self.parse_data_value()?;
721
722 let span = self.span_covering(&start_span, &self.last_span);
723 let source = self.make_source(span);
724
725 Ok(LemmaData::new(reference, value, source))
726 }
727
728 fn parse_with(&mut self) -> Result<LemmaData, Error> {
729 let with_token = self.expect(&TokenKind::With)?;
730 let start_span = with_token.span.clone();
731
732 let reference = self.parse_reference()?;
733 for segment in reference
734 .segments
735 .iter()
736 .chain(std::iter::once(&reference.name))
737 {
738 crate::limits::check_max_length(
739 segment,
740 self.max_data_name_length,
741 "with",
742 Some(Source::new(self.source_type(), start_span.clone())),
743 )?;
744 }
745
746 if reference.segments.is_empty() {
747 return Err(self.error_at_token_with_suggestion(
748 &with_token,
749 "`with` must target data on an imported spec (`with alias.field: …`), not a local name.",
750 "Use `data name: …` for local slots, or `with alias.field: …` to set data on a spec you `uses`.",
751 ));
752 }
753
754 self.expect(&TokenKind::Colon)?;
755
756 let value = self.parse_with_value()?;
757
758 let span = self.span_covering(&start_span, &self.last_span);
759 let source = self.make_source(span);
760
761 Ok(LemmaData::new(reference, value, source))
762 }
763
764 fn with_rhs_starts_as_literal(&self, kind: &TokenKind) -> bool {
765 matches!(
766 kind,
767 TokenKind::StringLit | TokenKind::NumberLit | TokenKind::Minus | TokenKind::Plus
768 ) || is_boolean_keyword(kind)
769 }
770
771 fn parse_with_value(&mut self) -> Result<DataValue, Error> {
772 let peek_kind = self.peek()?.kind.clone();
773
774 if self.with_rhs_starts_as_literal(&peek_kind) {
775 let value = self.parse_literal_value()?;
776 return Ok(DataValue::With(WithRhs::Literal(value)));
777 }
778
779 if can_be_label(&peek_kind) {
780 let target = self.parse_reference()?;
781 if self.at(&TokenKind::Arrow)? {
782 let tok = self.peek()?.clone();
783 return Err(self.error_at_token_with_suggestion(
784 &tok,
785 "Constraint chains (`-> ...`) are not allowed on `with`; use `data` to declare types and constraints.",
786 "Use `data name: <type> -> ...` for constraints, then `with alias.field: <reference or literal>` to assign on an imported spec.",
787 ));
788 }
789 return Ok(DataValue::With(WithRhs::Reference { target }));
790 }
791
792 let tok = self.peek()?.clone();
793 Err(self.error_at_token(
794 &tok,
795 format!(
796 "Expected a reference or literal after `with ...:`, found {}",
797 tok.kind
798 ),
799 ))
800 }
801
802 fn parse_reference(&mut self) -> Result<Reference, Error> {
803 let mut segments = Vec::new();
804
805 let first = self.next()?;
806 if is_keyword(&first.kind) {
808 return Err(self.error_at_token_with_suggestion(
809 &first,
810 format!(
811 "'{}' is a reserved keyword and cannot be used as a name",
812 first.text
813 ),
814 "Choose a different name that is not a reserved keyword",
815 ));
816 }
817
818 if !can_be_label(&first.kind) {
819 return Err(self.error_at_token(
820 &first,
821 format!("Expected an identifier, found {}", first.kind),
822 ));
823 }
824
825 segments.push(first.text.clone());
826
827 while self.at(&TokenKind::Dot)? {
829 self.next()?; let seg = self.next()?;
831 if !can_be_label(&seg.kind) {
832 return Err(self.error_at_token(
833 &seg,
834 format!("Expected an identifier after '.', found {}", seg.kind),
835 ));
836 }
837 segments.push(seg.text.clone());
838 }
839
840 Ok(Reference::from_path(segments))
841 }
842
843 fn parse_data_value(&mut self) -> Result<DataValue, Error> {
844 if self.at(&TokenKind::Spec)? {
845 let token = self.next()?;
846 return Err(self.error_at_token_with_suggestion(
847 &token,
848 "Cannot import a spec with `data`; use `uses`",
849 "Use `uses <spec_name>` or `uses <alias>: <spec_name>`",
850 ));
851 }
852
853 let peek_kind = self.peek()?.kind.clone();
854
855 if token_kind_to_primitive(&peek_kind).is_some() || can_be_label(&peek_kind) {
856 let (base, constraints) = self.parse_type_arrow_chain()?;
857 return Ok(DataValue::Definition {
858 base: Some(base),
859 constraints,
860 value: None,
861 });
862 }
863
864 let value = self.parse_literal_value()?;
866 Ok(DataValue::Definition {
867 base: None,
868 constraints: None,
869 value: Some(value),
870 })
871 }
872
873 fn parse_uses_item(&mut self, start_span: &Span) -> Result<LemmaData, Error> {
876 let explicit_alias = if can_be_label(&self.peek()?.kind)
877 && self.lexer.peek_second()?.kind == TokenKind::Colon
878 {
879 let alias_tok = self.next()?;
880 self.expect(&TokenKind::Colon)?;
881 Some(alias_tok)
882 } else {
883 None
884 };
885
886 let spec_ref = self.parse_spec_ref_target()?;
887
888 let spec_name_source = spec_ref
889 .target_span
890 .as_ref()
891 .map(|sp| Source::new(self.source_type(), sp.clone()));
892
893 crate::limits::check_max_length(
894 &spec_ref.name,
895 self.max_spec_name_length,
896 "spec",
897 spec_name_source.clone(),
898 )?;
899
900 let alias = if let Some(ref alias_tok) = explicit_alias {
901 crate::limits::check_max_length(
902 &alias_tok.text,
903 self.max_data_name_length,
904 "data",
905 Some(Source::new(self.source_type(), alias_tok.span.clone())),
906 )?;
907 alias_tok.text.clone()
908 } else {
909 let implicit = spec_ref.name.clone();
910 crate::limits::check_max_length(
911 &implicit,
912 self.max_data_name_length,
913 "data",
914 spec_name_source,
915 )?;
916 implicit
917 };
918
919 let span = self.span_covering(start_span, &self.last_span);
920 Ok(LemmaData::new(
921 Reference::local(alias),
922 DataValue::Import(spec_ref),
923 self.make_source(span),
924 ))
925 }
926
927 fn parse_uses_statement(&mut self) -> Result<LemmaData, Error> {
928 let uses_token = self.expect(&TokenKind::Uses)?;
929 let start_span = uses_token.span.clone();
930 self.parse_uses_item(&start_span)
931 }
932
933 fn parse_rule(&mut self) -> Result<LemmaRule, Error> {
938 let rule_token = self.expect(&TokenKind::Rule)?;
939 let start_span = rule_token.span.clone();
940
941 let name_tok = self.next()?;
942 if is_keyword(&name_tok.kind) {
943 return Err(self.error_at_token_with_suggestion(
944 &name_tok,
945 format!(
946 "'{}' is a reserved keyword and cannot be used as a rule name",
947 name_tok.text
948 ),
949 "Choose a different name that is not a reserved keyword",
950 ));
951 }
952 if !can_be_label(&name_tok.kind) {
953 return Err(self.error_at_token(
954 &name_tok,
955 format!("Expected a rule name, found {}", name_tok.kind),
956 ));
957 }
958 let rule_name = name_tok.text.clone();
959 crate::limits::check_max_length(
960 &rule_name,
961 self.max_rule_name_length,
962 "rule",
963 Some(Source::new(self.source_type(), name_tok.span.clone())),
964 )?;
965
966 self.expect(&TokenKind::Colon)?;
967
968 let expression = if self.at(&TokenKind::Veto)? && !self.at_bare_veto_followed_by_is()? {
970 self.parse_veto_expression()?
971 } else {
972 self.parse_expression()?
973 };
974
975 let mut unless_clauses = Vec::new();
977 while self.at(&TokenKind::Unless)? {
978 unless_clauses.push(self.parse_unless_clause()?);
979 }
980
981 let end_span = if let Some(last_unless) = unless_clauses.last() {
982 last_unless.source_location.span.clone()
983 } else if let Some(ref loc) = expression.source_location {
984 loc.span.clone()
985 } else {
986 start_span.clone()
987 };
988
989 let span = self.span_covering(&start_span, &end_span);
990 Ok(LemmaRule {
991 name: rule_name,
992 expression,
993 unless_clauses,
994 source_location: self.make_source(span),
995 })
996 }
997
998 fn parse_veto_expression(&mut self) -> Result<Expression, Error> {
999 let veto_tok = self.expect(&TokenKind::Veto)?;
1000 let start_span = veto_tok.span.clone();
1001
1002 let message = if self.at(&TokenKind::StringLit)? {
1003 let str_tok = self.next()?;
1004 let content = unquote_string(&str_tok.text);
1005 Some(content)
1006 } else {
1007 None
1008 };
1009
1010 let span = self.span_from(&start_span);
1011 self.new_expression(
1012 ExpressionKind::Veto(VetoExpression { message }),
1013 self.make_source(span),
1014 )
1015 }
1016
1017 fn parse_unless_clause(&mut self) -> Result<UnlessClause, Error> {
1018 let unless_tok = self.expect(&TokenKind::Unless)?;
1019 let start_span = unless_tok.span.clone();
1020
1021 let condition = self.parse_expression()?;
1022
1023 self.expect(&TokenKind::Then)?;
1024
1025 let result = if self.at(&TokenKind::Veto)? {
1026 self.parse_veto_expression()?
1027 } else {
1028 self.parse_expression()?
1029 };
1030
1031 let end_span = result
1032 .source_location
1033 .as_ref()
1034 .map(|s| s.span.clone())
1035 .unwrap_or_else(|| start_span.clone());
1036 let span = self.span_covering(&start_span, &end_span);
1037
1038 Ok(UnlessClause {
1039 condition,
1040 result,
1041 source_location: self.make_source(span),
1042 })
1043 }
1044
1045 fn parse_leaf_parent_type(&mut self) -> Result<ParentType, Error> {
1046 let name_tok = self.next()?;
1047 self.parse_leaf_parent_type_from_first_token(name_tok)
1048 }
1049
1050 fn parse_leaf_parent_type_from_first_token(
1051 &mut self,
1052 name_tok: Token,
1053 ) -> Result<ParentType, Error> {
1054 if let Some(kind) = token_kind_to_primitive(&name_tok.kind) {
1055 Ok(ParentType::Primitive { primitive: kind })
1056 } else if can_be_label(&name_tok.kind) {
1057 Ok(ParentType::Custom {
1058 name: name_tok.text.clone(),
1059 })
1060 } else {
1061 Err(self.error_at_token(
1062 &name_tok,
1063 format!("Expected a type name, found {}", name_tok.kind),
1064 ))
1065 }
1066 }
1067
1068 fn parse_type_arrow_chain(&mut self) -> Result<(ParentType, Option<Vec<Constraint>>), Error> {
1070 let first = self.parse_leaf_parent_type()?;
1071
1072 let base = if let ParentType::Custom { name } = &first {
1073 if self.at(&TokenKind::Dot)? {
1074 self.next()?;
1075 let inner = self.parse_leaf_parent_type()?;
1076 ParentType::Qualified {
1077 spec_alias: name.clone(),
1078 inner: Box::new(inner),
1079 }
1080 } else {
1081 first
1082 }
1083 } else {
1084 if self.at(&TokenKind::Dot)? {
1085 let dot_tok = self.peek()?.clone();
1086 return Err(self.error_at_token_with_suggestion(
1087 &dot_tok,
1088 "A primitive type cannot be the left segment of a qualified parent path",
1089 "Use `data name: alias.typename` where `alias` is the `uses` import name and `typename` is the parent type.",
1090 ));
1091 }
1092 first
1093 };
1094
1095 let base = if self.at(&TokenKind::Identifier)? && self.peek()?.text == "range" {
1096 self.next()?;
1097 ParentType::Ranged {
1098 inner: Box::new(base),
1099 }
1100 } else {
1101 base
1102 };
1103
1104 let constraints = self.parse_trailing_constraints()?;
1105
1106 Ok((base, constraints))
1107 }
1108
1109 fn parse_trailing_constraints(&mut self) -> Result<Option<Vec<Constraint>>, Error> {
1110 let mut commands = Vec::new();
1111 while self.at(&TokenKind::Arrow)? {
1112 self.next()?;
1113 let (cmd, cmd_args) = self.parse_command()?;
1114 commands.push((cmd, cmd_args));
1115 }
1116 let constraints = if commands.is_empty() {
1117 None
1118 } else {
1119 Some(commands)
1120 };
1121 Ok(constraints)
1122 }
1123
1124 fn parse_command(&mut self) -> Result<(TypeConstraintCommand, Vec<CommandArg>), Error> {
1125 let name_tok = self.next()?;
1126 if !can_be_label(&name_tok.kind) {
1127 return Err(self.error_at_token(
1128 &name_tok,
1129 format!("Expected a command name, found {}", name_tok.kind),
1130 ));
1131 }
1132 let cmd = try_parse_type_constraint_command(&name_tok.text).ok_or_else(|| {
1133 self.error_at_token(
1134 &name_tok,
1135 format!(
1136 "Unknown constraint command '{}'. Valid commands: help, suggest, unit, trait, minimum, maximum, decimals, option, options, length",
1137 name_tok.text
1138 ),
1139 )
1140 })?;
1141
1142 let args = if cmd == TypeConstraintCommand::Unit {
1143 self.parse_unit_command_args()?
1144 } else {
1145 self.parse_generic_command_args()?
1146 };
1147
1148 Ok((cmd, args))
1149 }
1150
1151 fn parse_generic_command_args(&mut self) -> Result<Vec<CommandArg>, Error> {
1153 let mut args = Vec::new();
1154 loop {
1155 if self.at(&TokenKind::Arrow)?
1156 || self.at(&TokenKind::Eof)?
1157 || is_spec_body_keyword(&self.peek()?.kind)
1158 || self.at(&TokenKind::Spec)?
1159 {
1160 break;
1161 }
1162
1163 let peek_kind = self.peek()?.kind.clone();
1164 match peek_kind {
1165 TokenKind::NumberLit
1166 | TokenKind::Minus
1167 | TokenKind::Plus
1168 | TokenKind::StringLit => {
1169 let value = self.parse_literal_value()?;
1170 args.push(CommandArg::Literal(value));
1171 }
1172 ref k if is_boolean_keyword(k) => {
1173 let value = self.parse_literal_value()?;
1174 args.push(CommandArg::Literal(value));
1175 }
1176 ref k if can_be_label(k) => {
1177 let tok = self.next()?;
1178 args.push(CommandArg::Label(tok.text));
1179 }
1180 _ => break,
1181 }
1182 }
1183 Ok(args)
1184 }
1185
1186 fn parse_scalar_literal_value(&mut self) -> Result<Value, Error> {
1187 let peeked = self.peek()?;
1188 match &peeked.kind {
1189 TokenKind::StringLit => {
1190 let tok = self.next()?;
1191 let content = unquote_string(&tok.text);
1192 Ok(Value::Text(content))
1193 }
1194 k if is_boolean_keyword(k) => {
1195 let tok = self.next()?;
1196 Ok(Value::Boolean(token_kind_to_boolean_value(&tok.kind)))
1197 }
1198 TokenKind::NumberLit => self.parse_number_literal(),
1199 TokenKind::Minus | TokenKind::Plus => self.parse_signed_number_literal(),
1200 _ => {
1201 let tok = self.next()?;
1202 Err(self.error_at_token(
1203 &tok,
1204 format!(
1205 "Expected a value (number, text, boolean, date, etc.), found '{}'",
1206 tok.text
1207 ),
1208 ))
1209 }
1210 }
1211 }
1212
1213 fn at_command_terminator(&mut self) -> Result<bool, Error> {
1215 if self.at(&TokenKind::Arrow)? || self.at(&TokenKind::Eof)? || self.at(&TokenKind::Spec)? {
1216 return Ok(true);
1217 }
1218 Ok(is_spec_body_keyword(&self.peek()?.kind))
1219 }
1220
1221 fn parse_unit_command_args(&mut self) -> Result<Vec<CommandArg>, Error> {
1231 if self.at_command_terminator()? {
1232 return Ok(Vec::new());
1234 }
1235
1236 let peek_kind = self.peek()?.kind.clone();
1237 if !can_be_label(&peek_kind) {
1238 return Ok(Vec::new());
1240 }
1241
1242 let unit_name_tok = self.next()?;
1243 let unit_name_arg = CommandArg::Label(unit_name_tok.text.clone());
1244
1245 let numeric_prefix: Option<Decimal> = if self.at(&TokenKind::NumberLit)? {
1248 let num_tok = self.next()?;
1249 Some(parse_decimal_string(&num_tok.text, &num_tok.span, self)?)
1250 } else {
1251 None
1252 };
1253
1254 let peek_kind_after_prefix = self.peek()?.kind.clone();
1257 let has_compound_expr =
1258 can_be_label(&peek_kind_after_prefix) && !self.at_command_terminator()?;
1259
1260 if has_compound_expr {
1261 let factors = self.parse_unit_factors()?;
1262 let prefix = numeric_prefix.unwrap_or(Decimal::ONE);
1263 let unit_arg = CommandArg::UnitExpr(UnitArg::Expr(prefix, factors));
1264 Ok(vec![unit_name_arg, unit_arg])
1265 } else if let Some(factor) = numeric_prefix {
1266 let unit_arg = CommandArg::UnitExpr(UnitArg::Factor(factor));
1267 Ok(vec![unit_name_arg, unit_arg])
1268 } else {
1269 Ok(vec![unit_name_arg])
1272 }
1273 }
1274
1275 fn parse_unit_factors(&mut self) -> Result<Vec<UnitFactor>, Error> {
1292 let mut factors: Vec<UnitFactor> = Vec::new();
1293 let mut denominator_mode = false;
1294 let mut operator_just_consumed = true;
1298
1299 loop {
1300 if self.at_command_terminator()? {
1301 if !operator_just_consumed {
1302 break;
1303 }
1304 break;
1308 }
1309
1310 if self.at(&TokenKind::Star)? {
1312 if operator_just_consumed && !factors.is_empty() {
1313 let bad_tok = self.next()?;
1314 return Err(self.error_at_token(
1315 &bad_tok,
1316 "Unexpected '*' in unit expression: two consecutive operators".to_string(),
1317 ));
1318 }
1319 self.next()?;
1320 denominator_mode = false;
1321 operator_just_consumed = true;
1322 continue;
1323 }
1324
1325 if self.at(&TokenKind::Slash)? {
1327 if operator_just_consumed && !factors.is_empty() {
1328 let bad_tok = self.next()?;
1329 return Err(self.error_at_token(
1330 &bad_tok,
1331 "Unexpected '/' in unit expression: two consecutive operators".to_string(),
1332 ));
1333 }
1334 self.next()?;
1335 denominator_mode = true;
1336 operator_just_consumed = true;
1337 continue;
1338 }
1339
1340 let peek_kind = self.peek()?.kind.clone();
1342 if !can_be_label(&peek_kind) {
1343 break;
1344 }
1345
1346 if !operator_just_consumed {
1349 break;
1350 }
1351 operator_just_consumed = false;
1352
1353 let (measure_ref, _end_span) = self.parse_unit_path()?;
1354
1355 let explicit_exp: Option<i32> = if self.at(&TokenKind::Caret)? {
1357 self.next()?; let negative = if self.at(&TokenKind::Minus)? {
1360 self.next()?; true
1362 } else {
1363 false
1364 };
1365
1366 if !self.at(&TokenKind::NumberLit)? {
1367 let bad_tok = self.next()?;
1368 return Err(self.error_at_token(
1369 &bad_tok,
1370 format!(
1371 "Expected an integer exponent after '^' in unit expression, found {}",
1372 bad_tok.kind
1373 ),
1374 ));
1375 }
1376
1377 let exp_tok = self.next()?;
1378 let raw: i32 = exp_tok.text.parse::<i32>().map_err(|_| {
1379 self.error_at_token(
1380 &exp_tok,
1381 format!(
1382 "Exponent '{}' is not a valid integer in unit expression",
1383 exp_tok.text
1384 ),
1385 )
1386 })?;
1387
1388 if raw == 0 {
1389 return Err(self.error_at_token(
1390 &exp_tok,
1391 "Exponent cannot be zero in a unit expression".to_string(),
1392 ));
1393 }
1394
1395 Some(if negative { -raw } else { raw })
1396 } else {
1397 None
1398 };
1399
1400 let final_exp = match (explicit_exp, denominator_mode) {
1402 (Some(exponent), true) => -exponent,
1403 (Some(exponent), false) => exponent,
1404 (None, true) => -1,
1405 (None, false) => 1,
1406 };
1407
1408 factors.push(UnitFactor {
1409 measure_ref,
1410 exp: final_exp,
1411 });
1412 }
1413
1414 Ok(factors)
1415 }
1416
1417 fn parse_meta(&mut self) -> Result<MetaField, Error> {
1422 let meta_tok = self.expect(&TokenKind::Meta)?;
1423 let start_span = meta_tok.span.clone();
1424
1425 let key_tok = self.next()?;
1426 let key = key_tok.text.clone();
1427
1428 self.expect(&TokenKind::Colon)?;
1429
1430 let value = self.parse_meta_value()?;
1431
1432 let span = self.span_covering(&start_span, &self.last_span);
1433
1434 Ok(MetaField {
1435 key,
1436 value,
1437 source_location: self.make_source(span),
1438 })
1439 }
1440
1441 fn parse_meta_value(&mut self) -> Result<MetaValue, Error> {
1442 let peeked = self.peek()?;
1444 match &peeked.kind {
1445 TokenKind::StringLit => {
1446 let value = self.parse_literal_value()?;
1447 return Ok(MetaValue::Literal(value));
1448 }
1449 TokenKind::NumberLit => {
1450 let value = self.parse_literal_value()?;
1451 return Ok(MetaValue::Literal(value));
1452 }
1453 k if is_boolean_keyword(k) => {
1454 let value = self.parse_literal_value()?;
1455 return Ok(MetaValue::Literal(value));
1456 }
1457 _ => {}
1458 }
1459
1460 let mut ident = String::new();
1463 loop {
1464 let peeked = self.peek()?;
1465 match &peeked.kind {
1466 k if k.is_identifier_like() => {
1467 let tok = self.next()?;
1468 ident.push_str(&tok.text);
1469 }
1470 TokenKind::Dot => {
1471 self.next()?;
1472 ident.push('.');
1473 }
1474 TokenKind::Slash => {
1475 self.next()?;
1476 ident.push('/');
1477 }
1478 TokenKind::Minus => {
1479 self.next()?;
1480 ident.push('-');
1481 }
1482 TokenKind::NumberLit => {
1483 let tok = self.next()?;
1484 ident.push_str(&tok.text);
1485 }
1486 _ => break,
1487 }
1488 }
1489
1490 if ident.is_empty() {
1491 let tok = self.peek()?.clone();
1492 return Err(self.error_at_token(&tok, "Expected a meta value"));
1493 }
1494
1495 Ok(MetaValue::Unquoted(ident))
1496 }
1497
1498 fn parse_literal_value(&mut self) -> Result<Value, Error> {
1503 let left = self.parse_scalar_literal_value()?;
1504 if self.at(&TokenKind::Ellipsis)? {
1505 self.next()?;
1506 let right = self.parse_scalar_literal_value()?;
1507 Ok(Value::Range(Box::new(left), Box::new(right)))
1508 } else {
1509 Ok(left)
1510 }
1511 }
1512
1513 fn parse_signed_number_literal(&mut self) -> Result<Value, Error> {
1514 let sign_tok = self.next()?;
1515 let sign_span = sign_tok.span.clone();
1516 let is_negative = sign_tok.kind == TokenKind::Minus;
1517
1518 if !self.at(&TokenKind::NumberLit)? {
1519 let tok = self.peek()?.clone();
1520 return Err(self.error_at_token(
1521 &tok,
1522 format!(
1523 "Expected a number after '{}', found '{}'",
1524 sign_tok.text, tok.text
1525 ),
1526 ));
1527 }
1528
1529 let value = self.parse_number_literal()?;
1530 if !is_negative {
1531 return Ok(value);
1532 }
1533 match try_negate_numeric_literal(value) {
1534 Ok(negated) => Ok(negated),
1535 Err(other) => Err(Error::parsing(
1536 format!("Cannot negate this value: {}", other),
1537 self.make_source(sign_span),
1538 None::<String>,
1539 )),
1540 }
1541 }
1542
1543 fn parse_number_literal(&mut self) -> Result<Value, Error> {
1544 let num_tok = self.next()?;
1545 let num_text = &num_tok.text;
1546 let num_span = num_tok.span.clone();
1547
1548 if num_text.len() == 4
1550 && num_text.chars().all(|c| c.is_ascii_digit())
1551 && self.at(&TokenKind::Minus)?
1552 {
1553 return self.parse_date_literal(num_text.clone(), num_span);
1554 }
1555
1556 let peeked = self.peek()?;
1558
1559 if num_text.len() == 2
1561 && num_text.chars().all(|c| c.is_ascii_digit())
1562 && peeked.kind == TokenKind::Colon
1563 {
1564 return self.try_parse_time_literal(num_text.clone(), num_span);
1571 }
1572
1573 if peeked.kind == TokenKind::PercentPercent {
1575 let pp_tok = self.next()?;
1576 if let Ok(next_peek) = self.peek() {
1578 if next_peek.kind == TokenKind::NumberLit {
1579 return Err(self.error_at_token(
1580 &pp_tok,
1581 "Permille literal cannot be followed by a digit",
1582 ));
1583 }
1584 }
1585 let decimal = parse_decimal_string(num_text, &num_span, self)?;
1586 return Ok(Value::NumberWithUnit(decimal, "permille".to_string()));
1587 }
1588
1589 if peeked.kind == TokenKind::Percent {
1591 let pct_tok = self.next()?;
1592 if let Ok(next_peek) = self.peek() {
1594 if next_peek.kind == TokenKind::NumberLit || next_peek.kind == TokenKind::Percent {
1595 return Err(self.error_at_token(
1596 &pct_tok,
1597 "Percent literal cannot be followed by a digit",
1598 ));
1599 }
1600 }
1601 let decimal = parse_decimal_string(num_text, &num_span, self)?;
1602 return Ok(Value::NumberWithUnit(decimal, "percent".to_string()));
1603 }
1604
1605 if peeked.kind == TokenKind::Permille {
1607 self.next()?; let decimal = parse_decimal_string(num_text, &num_span, self)?;
1609 return Ok(Value::NumberWithUnit(decimal, "permille".to_string()));
1610 }
1611
1612 if can_be_label(&peeked.kind) {
1613 let (unit_path, _end_span) = self.parse_unit_path()?;
1614 let decimal = parse_decimal_string(num_text, &num_span, self)?;
1615 return Ok(Value::NumberWithUnit(decimal, unit_path));
1616 }
1617
1618 let decimal = parse_decimal_string(num_text, &num_span, self)?;
1620 Ok(Value::Number(decimal))
1621 }
1622
1623 fn parse_unit_path(&mut self) -> Result<(String, Span), Error> {
1625 let first = self.next()?;
1626 if !can_be_label(&first.kind) {
1627 return Err(self.error_at_token(
1628 &first,
1629 format!("Expected a unit name, found {}", first.kind),
1630 ));
1631 }
1632 let mut path = first.text.clone();
1633 let mut end_span = first.span.clone();
1634 while self.at(&TokenKind::Dot)? {
1635 self.next()?;
1636 let seg = self.next()?;
1637 if !can_be_label(&seg.kind) {
1638 return Err(self.error_at_token(
1639 &seg,
1640 format!("Expected a unit path segment after '.', found {}", seg.kind),
1641 ));
1642 }
1643 path.push('.');
1644 path.push_str(&seg.text);
1645 end_span = seg.span.clone();
1646 }
1647 Ok((path, end_span))
1648 }
1649
1650 fn parse_date_literal(&mut self, year_text: String, start_span: Span) -> Result<Value, Error> {
1651 let mut dt_str = year_text;
1652
1653 self.expect(&TokenKind::Minus)?;
1655 dt_str.push('-');
1656 let month_tok = self.expect(&TokenKind::NumberLit)?;
1657 dt_str.push_str(&month_tok.text);
1658
1659 self.expect(&TokenKind::Minus)?;
1661 dt_str.push('-');
1662 let day_tok = self.expect(&TokenKind::NumberLit)?;
1663 dt_str.push_str(&day_tok.text);
1664
1665 if self.at(&TokenKind::Identifier)? {
1667 let peeked = self.peek()?;
1668 if peeked.text.len() >= 2
1669 && (peeked.text.starts_with('T') || peeked.text.starts_with('t'))
1670 {
1671 let t_tok = self.next()?;
1673 dt_str.push_str(&t_tok.text);
1674
1675 if self.at(&TokenKind::Colon)? {
1677 self.next()?;
1678 dt_str.push(':');
1679 let min_tok = self.next()?;
1680 dt_str.push_str(&min_tok.text);
1681
1682 if self.at(&TokenKind::Colon)? {
1684 self.next()?;
1685 dt_str.push(':');
1686 let sec_tok = self.next()?;
1687 dt_str.push_str(&sec_tok.text);
1688
1689 if self.at(&TokenKind::Dot)? {
1691 self.next()?;
1692 dt_str.push('.');
1693 let frac_tok = self.expect(&TokenKind::NumberLit)?;
1694 dt_str.push_str(&frac_tok.text);
1695 }
1696 }
1697 }
1698
1699 self.try_consume_timezone(&mut dt_str)?;
1701 }
1702 }
1703
1704 if let Ok(dtv) = dt_str.parse::<crate::literals::DateTimeValue>() {
1705 return Ok(Value::Date(dtv));
1706 }
1707
1708 Err(Error::parsing(
1709 format!("Invalid date/time format: '{}'", dt_str),
1710 self.make_source(start_span),
1711 None::<String>,
1712 ))
1713 }
1714
1715 fn try_consume_timezone(&mut self, dt_str: &mut String) -> Result<(), Error> {
1716 if self.at(&TokenKind::Identifier)? {
1718 let peeked = self.peek()?;
1719 if (peeked.text == "Z" || peeked.text == "z") && peeked.span.start == self.last_span.end
1720 {
1721 let z_tok = self.next()?;
1722 dt_str.push_str(&z_tok.text);
1723 return Ok(());
1724 }
1725 }
1726
1727 if self.at(&TokenKind::Plus)? || self.at(&TokenKind::Minus)? {
1729 let mut lookahead = self.lexer.clone();
1730 let sign_tok = lookahead.next_token()?;
1731 let hour_tok = lookahead.next_token()?;
1732 let colon_tok = lookahead.next_token()?;
1733 let minute_tok = lookahead.next_token()?;
1734
1735 let attached = sign_tok.span.start == self.last_span.end;
1736 let is_timezone_shape = hour_tok.kind == TokenKind::NumberLit
1737 && colon_tok.kind == TokenKind::Colon
1738 && minute_tok.kind == TokenKind::NumberLit;
1739
1740 if attached && is_timezone_shape {
1741 let sign_tok = self.next()?;
1742 dt_str.push_str(&sign_tok.text);
1743 let hour_tok = self.expect(&TokenKind::NumberLit)?;
1744 dt_str.push_str(&hour_tok.text);
1745 self.expect(&TokenKind::Colon)?;
1746 dt_str.push(':');
1747 let min_tok = self.expect(&TokenKind::NumberLit)?;
1748 dt_str.push_str(&min_tok.text);
1749 }
1750 }
1751
1752 Ok(())
1753 }
1754
1755 fn try_parse_time_literal(
1756 &mut self,
1757 hour_text: String,
1758 start_span: Span,
1759 ) -> Result<Value, Error> {
1760 let mut time_str = hour_text;
1761
1762 self.expect(&TokenKind::Colon)?;
1764 time_str.push(':');
1765 let min_tok = self.expect(&TokenKind::NumberLit)?;
1766 time_str.push_str(&min_tok.text);
1767
1768 if self.at(&TokenKind::Colon)? {
1770 self.next()?;
1771 time_str.push(':');
1772 let sec_tok = self.expect(&TokenKind::NumberLit)?;
1773 time_str.push_str(&sec_tok.text);
1774
1775 if self.at(&TokenKind::Dot)? {
1777 self.next()?;
1778 time_str.push('.');
1779 let frac_tok = self.expect(&TokenKind::NumberLit)?;
1780 time_str.push_str(&frac_tok.text);
1781 }
1782 }
1783
1784 self.try_consume_timezone(&mut time_str)?;
1786
1787 if let Ok(t) = time_str.parse::<TimeValue>() {
1788 return Ok(Value::Time(TimeValue {
1789 hour: t.hour,
1790 minute: t.minute,
1791 second: t.second,
1792 microsecond: t.microsecond,
1793 timezone: t.timezone,
1794 }));
1795 }
1796
1797 Err(Error::parsing(
1798 format!("Invalid time format: '{}'", time_str),
1799 self.make_source(start_span),
1800 None::<String>,
1801 ))
1802 }
1803
1804 fn new_expression(
1809 &mut self,
1810 kind: ExpressionKind,
1811 source: Source,
1812 ) -> Result<Expression, Error> {
1813 self.expression_count += 1;
1814 if self.expression_count > self.max_expression_count {
1815 return Err(Error::resource_limit_exceeded(
1816 "max_expression_count",
1817 self.max_expression_count.to_string(),
1818 self.expression_count.to_string(),
1819 "Split logic into multiple rules to reduce expression count",
1820 Some(source),
1821 None,
1822 None,
1823 ));
1824 }
1825 Ok(Expression::new(kind, source))
1826 }
1827
1828 fn check_depth(&mut self) -> Result<(), Error> {
1829 if let Err(actual) = self.depth_tracker.push_depth() {
1830 let span = self.peek()?.span.clone();
1831 self.depth_tracker.pop_depth();
1832 return Err(Error::resource_limit_exceeded(
1833 "max_expression_depth",
1834 self.depth_tracker.max_depth().to_string(),
1835 actual.to_string(),
1836 "Simplify nested expressions or break into separate rules",
1837 Some(self.make_source(span)),
1838 None,
1839 None,
1840 ));
1841 }
1842 Ok(())
1843 }
1844
1845 fn parse_expression(&mut self) -> Result<Expression, Error> {
1846 self.check_depth()?;
1847 let result = self.parse_and_expression();
1848 self.depth_tracker.pop_depth();
1849 result
1850 }
1851
1852 fn parse_and_expression(&mut self) -> Result<Expression, Error> {
1853 let start_span = self.peek()?.span.clone();
1854 let mut left = self.parse_and_operand()?;
1855
1856 while self.at(&TokenKind::And)? {
1857 self.next()?; let right = self.parse_and_operand()?;
1859 let span = self.span_covering(
1860 &start_span,
1861 &right
1862 .source_location
1863 .as_ref()
1864 .map(|s| s.span.clone())
1865 .unwrap_or_else(|| start_span.clone()),
1866 );
1867 left = self.new_expression(
1868 ExpressionKind::LogicalAnd(Arc::new(left), Arc::new(right)),
1869 self.make_source(span),
1870 )?;
1871 }
1872
1873 Ok(left)
1874 }
1875
1876 fn at_bare_veto_token(&mut self) -> Result<bool, Error> {
1877 if !self.at(&TokenKind::Veto)? {
1878 return Ok(false);
1879 }
1880 let checkpoint = self.checkpoint();
1881 self.next()?;
1882 let bare = !self.at(&TokenKind::StringLit)?;
1883 self.restore(checkpoint);
1884 Ok(bare)
1885 }
1886
1887 fn at_bare_veto_followed_by_is(&mut self) -> Result<bool, Error> {
1888 if !self.at_bare_veto_token()? {
1889 return Ok(false);
1890 }
1891 let checkpoint = self.checkpoint();
1892 self.next()?;
1893 let followed = self.at(&TokenKind::Is)?;
1894 self.restore(checkpoint);
1895 Ok(followed)
1896 }
1897
1898 fn at_not_bare_veto_followed_by_is(&mut self) -> Result<bool, Error> {
1899 if !self.at(&TokenKind::Not)? {
1900 return Ok(false);
1901 }
1902 let checkpoint = self.checkpoint();
1903 self.next()?;
1904 if !self.at(&TokenKind::Veto)? {
1905 self.restore(checkpoint);
1906 return Ok(false);
1907 }
1908 self.next()?;
1909 if self.at(&TokenKind::StringLit)? {
1910 self.restore(checkpoint);
1911 return Ok(false);
1912 }
1913 let followed = self.at(&TokenKind::Is)?;
1914 self.restore(checkpoint);
1915 Ok(followed)
1916 }
1917
1918 fn wrap_result_is_veto_expression(
1919 &mut self,
1920 operand: Expression,
1921 operator_is_not: bool,
1922 keyword_was_negated: bool,
1923 start_span: Span,
1924 ) -> Result<Expression, Error> {
1925 let negate = operator_is_not ^ keyword_was_negated;
1926 let end_span = operand
1927 .source_location
1928 .as_ref()
1929 .map(|source| source.span.clone())
1930 .unwrap_or_else(|| start_span.clone());
1931 let span = self.span_covering(&start_span, &end_span);
1932 let core = self.new_expression(
1933 ExpressionKind::ResultIsVeto(Arc::new(operand)),
1934 self.make_source(span.clone()),
1935 )?;
1936 if negate {
1937 self.new_expression(
1938 ExpressionKind::LogicalNegation(Arc::new(core), NegationType::Not),
1939 self.make_source(span),
1940 )
1941 } else {
1942 Ok(core)
1943 }
1944 }
1945
1946 fn parse_veto_status_lhs_is_comparison(&mut self) -> Result<Expression, Error> {
1947 let start_span = self.peek()?.span.clone();
1948 let keyword_was_negated = if self.at(&TokenKind::Not)? {
1949 self.next()?;
1950 true
1951 } else {
1952 false
1953 };
1954 self.expect(&TokenKind::Veto)?;
1955 if self.at(&TokenKind::StringLit)? {
1956 let tok = self.peek()?.clone();
1957 return Err(self.error_at_token(
1958 &tok,
1959 "veto with a message is only valid as a rule or unless result, not in `is veto` comparisons",
1960 ));
1961 }
1962 let operator = self.parse_comparison_operator()?;
1963 let operator_is_not = matches!(operator, ComparisonComputation::IsNot);
1964 if !matches!(
1965 operator,
1966 ComparisonComputation::Is | ComparisonComputation::IsNot
1967 ) {
1968 let tok = self.peek()?.clone();
1969 return Err(self.error_at_token(
1970 &tok,
1971 "Expected `is` or `is not` after `veto` in a veto-status comparison",
1972 ));
1973 }
1974 let operand = self.parse_range_expression()?;
1975 self.wrap_result_is_veto_expression(
1976 operand,
1977 operator_is_not,
1978 keyword_was_negated,
1979 start_span,
1980 )
1981 }
1982
1983 fn parse_and_operand(&mut self) -> Result<Expression, Error> {
1984 if self.at_not_bare_veto_followed_by_is()? || self.at_bare_veto_followed_by_is()? {
1985 return self.parse_veto_status_lhs_is_comparison();
1986 }
1987
1988 if self.at(&TokenKind::Not)? {
1990 return self.parse_not_expression();
1991 }
1992
1993 self.parse_repository_with_suffix()
1995 }
1996
1997 fn parse_not_expression(&mut self) -> Result<Expression, Error> {
1998 let not_tok = self.expect(&TokenKind::Not)?;
1999 let start_span = not_tok.span.clone();
2000
2001 self.check_depth()?;
2002 let operand = self.parse_and_operand()?;
2003 self.depth_tracker.pop_depth();
2004
2005 let end_span = operand
2006 .source_location
2007 .as_ref()
2008 .map(|s| s.span.clone())
2009 .unwrap_or_else(|| start_span.clone());
2010 let span = self.span_covering(&start_span, &end_span);
2011
2012 self.new_expression(
2013 ExpressionKind::LogicalNegation(Arc::new(operand), NegationType::Not),
2014 self.make_source(span),
2015 )
2016 }
2017
2018 fn parse_repository_with_suffix(&mut self) -> Result<Expression, Error> {
2019 let start_span = self.peek()?.span.clone();
2020 let repository = self.parse_range_expression()?;
2021 self.continue_repository_operand(repository, start_span)
2022 }
2023
2024 fn continue_repository_operand(
2026 &mut self,
2027 mut expr: Expression,
2028 start_span: Span,
2029 ) -> Result<Expression, Error> {
2030 loop {
2031 let peeked = self.peek()?;
2032
2033 if is_comparison_operator(&peeked.kind) {
2034 return self.parse_comparison_suffix(expr, start_span);
2035 }
2036
2037 if peeked.kind == TokenKind::Not {
2038 expr = self.parse_not_in_calendar_suffix(expr, start_span.clone())?;
2039 continue;
2040 }
2041
2042 if peeked.kind == TokenKind::In {
2043 expr = self.parse_in_suffix(expr, start_span.clone())?;
2044 continue;
2045 }
2046
2047 if peeked.kind == TokenKind::As {
2048 expr = self.parse_as_chain(expr, start_span.clone())?;
2049 continue;
2050 }
2051
2052 break;
2053 }
2054
2055 if self.at_expression_suffix_end()? {
2056 return Ok(expr);
2057 }
2058
2059 let tok = self.peek()?.clone();
2060 Err(self.error_at_token(
2061 &tok,
2062 format!("Unexpected token '{}' after expression", tok.text),
2063 ))
2064 }
2065
2066 fn parse_comparison_suffix(
2067 &mut self,
2068 left: Expression,
2069 start_span: Span,
2070 ) -> Result<Expression, Error> {
2071 let operator = self.parse_comparison_operator()?;
2072 let operator_is_not = matches!(operator, ComparisonComputation::IsNot);
2073
2074 if matches!(
2075 operator,
2076 ComparisonComputation::Is | ComparisonComputation::IsNot
2077 ) && self.at_bare_veto_token()?
2078 {
2079 self.expect(&TokenKind::Veto)?;
2080 if self.at(&TokenKind::StringLit)? {
2081 let tok = self.peek()?.clone();
2082 return Err(self.error_at_token(
2083 &tok,
2084 "veto with a message is only valid as a rule or unless result, not in `is veto` comparisons",
2085 ));
2086 }
2087 return self.wrap_result_is_veto_expression(left, operator_is_not, false, start_span);
2088 }
2089
2090 let right = if self.at(&TokenKind::Not)? {
2092 self.parse_not_expression()?
2093 } else {
2094 self.parse_range_expression()?
2095 };
2096
2097 let end_span = right
2098 .source_location
2099 .as_ref()
2100 .map(|s| s.span.clone())
2101 .unwrap_or_else(|| start_span.clone());
2102 let span = self.span_covering(&start_span, &end_span);
2103
2104 self.new_expression(
2105 ExpressionKind::Comparison(Arc::new(left), operator, Arc::new(right)),
2106 self.make_source(span),
2107 )
2108 }
2109
2110 fn parse_comparison_operator(&mut self) -> Result<ComparisonComputation, Error> {
2111 let tok = self.next()?;
2112 match tok.kind {
2113 TokenKind::Gt => Ok(ComparisonComputation::GreaterThan),
2114 TokenKind::Lt => Ok(ComparisonComputation::LessThan),
2115 TokenKind::Gte => Ok(ComparisonComputation::GreaterThanOrEqual),
2116 TokenKind::Lte => Ok(ComparisonComputation::LessThanOrEqual),
2117 TokenKind::Is => {
2118 if self.at(&TokenKind::Not)? {
2120 self.next()?; Ok(ComparisonComputation::IsNot)
2122 } else {
2123 Ok(ComparisonComputation::Is)
2124 }
2125 }
2126 _ => Err(self.error_at_token(
2127 &tok,
2128 format!("Expected a comparison operator, found {}", tok.kind),
2129 )),
2130 }
2131 }
2132
2133 fn parse_not_in_calendar_suffix(
2134 &mut self,
2135 repository: Expression,
2136 start_span: Span,
2137 ) -> Result<Expression, Error> {
2138 self.expect(&TokenKind::Not)?;
2139 self.expect(&TokenKind::In)?;
2140 self.expect_calendar_period_marker()?;
2141 let unit = self.parse_calendar_unit()?;
2142 let end = self.peek()?.span.clone();
2143 let span = self.span_covering(&start_span, &end);
2144 self.new_expression(
2145 ExpressionKind::DateCalendar(DateCalendarKind::NotIn, unit, Arc::new(repository)),
2146 self.make_source(span),
2147 )
2148 }
2149
2150 fn parse_in_suffix(
2151 &mut self,
2152 repository: Expression,
2153 start_span: Span,
2154 ) -> Result<Expression, Error> {
2155 self.expect(&TokenKind::In)?;
2156
2157 let peeked = self.peek()?;
2158
2159 if peeked.kind == TokenKind::Past || peeked.kind == TokenKind::Future {
2161 let direction = self.next()?;
2162 let rel_kind = if direction.kind == TokenKind::Past {
2163 DateRelativeKind::InPast
2164 } else {
2165 DateRelativeKind::InFuture
2166 };
2167
2168 if self.at_calendar_period_marker()? {
2170 self.next_calendar_period_marker()?;
2171 let cal_kind = if direction.kind == TokenKind::Past {
2172 DateCalendarKind::Past
2173 } else {
2174 DateCalendarKind::Future
2175 };
2176 let unit = self.parse_calendar_unit()?;
2177 let end = self.peek()?.span.clone();
2178 let span = self.span_covering(&start_span, &end);
2179 return self.new_expression(
2180 ExpressionKind::DateCalendar(cal_kind, unit, Arc::new(repository)),
2181 self.make_source(span),
2182 );
2183 }
2184
2185 if self.at(&TokenKind::And)?
2186 || self.at(&TokenKind::Unless)?
2187 || self.at(&TokenKind::Then)?
2188 || self.at(&TokenKind::RParen)?
2189 || self.at(&TokenKind::Eof)?
2190 || is_comparison_operator(&self.peek()?.kind)
2191 {
2192 let end = self.peek()?.span.clone();
2193 let span = self.span_covering(&start_span, &end);
2194 return self.new_expression(
2195 ExpressionKind::DateRelative(rel_kind, Arc::new(repository)),
2196 self.make_source(span),
2197 );
2198 }
2199
2200 let offset = self.parse_repository_expression()?;
2201 let offset_end_span = offset
2202 .source_location
2203 .as_ref()
2204 .map(|s| s.span.clone())
2205 .unwrap_or_else(|| start_span.clone());
2206 let range = self.new_expression(
2207 ExpressionKind::PastFutureRange(rel_kind, Arc::new(offset)),
2208 self.make_source(self.span_covering(&direction.span, &offset_end_span)),
2209 )?;
2210 let span = self.span_covering(&start_span, &offset_end_span);
2211 return self.new_expression(
2212 ExpressionKind::RangeContainment(Arc::new(repository), Arc::new(range)),
2213 self.make_source(span),
2214 );
2215 }
2216
2217 if token_is_calendar_period_marker(peeked) {
2219 self.next_calendar_period_marker()?;
2220 let unit = self.parse_calendar_unit()?;
2221 let end = self.peek()?.span.clone();
2222 let span = self.span_covering(&start_span, &end);
2223 return self.new_expression(
2224 ExpressionKind::DateCalendar(DateCalendarKind::Current, unit, Arc::new(repository)),
2225 self.make_source(span),
2226 );
2227 }
2228
2229 let range = self.parse_range_expression()?;
2230 let end_span = range
2231 .source_location
2232 .as_ref()
2233 .map(|s| s.span.clone())
2234 .unwrap_or_else(|| start_span.clone());
2235 let span = self.span_covering(&start_span, &end_span);
2236 self.new_expression(
2237 ExpressionKind::RangeContainment(Arc::new(repository), Arc::new(range)),
2238 self.make_source(span),
2239 )
2240 }
2241
2242 fn parse_as_chain(
2243 &mut self,
2244 mut expr: Expression,
2245 start_span: Span,
2246 ) -> Result<Expression, Error> {
2247 while self.at(&TokenKind::As)? {
2248 self.expect(&TokenKind::As)?;
2249 let target_tok = self.next()?;
2250 let target = if matches!(target_tok.kind, TokenKind::Permille) {
2251 ConversionTarget::Unit {
2252 unit_name: "permille".to_string(),
2253 }
2254 } else if let Some(primitive) = token_kind_to_primitive(&target_tok.kind) {
2255 ConversionTarget::Type(primitive)
2256 } else if can_be_label(&target_tok.kind) {
2257 let mut unit_path = target_tok.text.clone();
2258 let mut end_span = target_tok.span.clone();
2259 while self.at(&TokenKind::Dot)? {
2260 self.next()?;
2261 let seg = self.next()?;
2262 if !can_be_label(&seg.kind) {
2263 return Err(self.error_at_token(
2264 &seg,
2265 format!("Expected a unit path segment after '.', found {}", seg.kind),
2266 ));
2267 }
2268 unit_path.push('.');
2269 unit_path.push_str(&seg.text);
2270 end_span = seg.span.clone();
2271 }
2272 let target = ConversionTarget::Unit {
2273 unit_name: unit_path,
2274 };
2275 expr = self.new_expression(
2276 ExpressionKind::UnitConversion(Arc::new(expr), target),
2277 self.make_source(self.span_covering(&start_span, &end_span)),
2278 )?;
2279 continue;
2280 } else {
2281 return Err(self.error_at_token(
2282 &target_tok,
2283 format!(
2284 "Expected a type keyword or unit name after 'as', found {}",
2285 target_tok.kind
2286 ),
2287 ));
2288 };
2289 expr = self.new_expression(
2290 ExpressionKind::UnitConversion(Arc::new(expr), target),
2291 self.make_source(self.span_covering(&start_span, &target_tok.span)),
2292 )?;
2293 }
2294 Ok(expr)
2295 }
2296
2297 fn is_plain_number_literal(expr: &Expression) -> bool {
2298 matches!(expr.kind, ExpressionKind::Literal(Value::Number(_)))
2299 }
2300
2301 fn is_unit_conversion(expr: &Expression) -> bool {
2302 matches!(expr.kind, ExpressionKind::UnitConversion(..))
2303 }
2304
2305 fn at_expression_suffix_end(&mut self) -> Result<bool, Error> {
2310 Ok(self.at(&TokenKind::And)?
2311 || self.at(&TokenKind::Unless)?
2312 || self.at(&TokenKind::Then)?
2313 || self.at(&TokenKind::RParen)?
2314 || self.at(&TokenKind::Eof)?
2315 || self.at(&TokenKind::Spec)?
2316 || self.at(&TokenKind::Repo)?
2317 || self.at(&TokenKind::Uses)?
2318 || is_spec_body_keyword(&self.peek()?.kind))
2319 }
2320
2321 fn parse_calendar_unit(&mut self) -> Result<CalendarPeriodUnit, Error> {
2322 let tok = self.next()?;
2323 if let Some(unit) = CalendarPeriodUnit::from_keyword(&tok.text) {
2324 return Ok(unit);
2325 }
2326 Err(self.error_at_token(
2327 &tok,
2328 format!("Expected 'year', 'month', or 'week', found '{}'", tok.text),
2329 ))
2330 }
2331
2332 fn parse_range_expression(&mut self) -> Result<Expression, Error> {
2337 self.parse_repository_expression()
2338 }
2339
2340 fn parse_range_operand(&mut self) -> Result<Expression, Error> {
2345 let start_span = self.peek()?.span.clone();
2346 let checkpoint = self.checkpoint();
2347 let left = self.parse_range_ellipsis_bound()?;
2348 if !self.at(&TokenKind::Ellipsis)? {
2349 self.restore(checkpoint);
2350 return self.parse_factor();
2351 }
2352
2353 self.next()?;
2354 let right = self.parse_range_ellipsis_bound()?;
2355 let end_span = right
2356 .source_location
2357 .as_ref()
2358 .map(|s| s.span.clone())
2359 .unwrap_or_else(|| start_span.clone());
2360 let span = self.span_covering(&start_span, &end_span);
2361 self.new_expression(
2362 ExpressionKind::RangeLiteral(Arc::new(left), Arc::new(right)),
2363 self.make_source(span),
2364 )
2365 }
2366
2367 fn parse_range_ellipsis_bound(&mut self) -> Result<Expression, Error> {
2369 let start_span = self.peek()?.span.clone();
2370 let mut left = self.parse_power_for_range_bound()?;
2371
2372 while self.at_any(&[TokenKind::Plus, TokenKind::Minus])? {
2373 let op_tok = self.next()?;
2374 let operation = match op_tok.kind {
2375 TokenKind::Plus => ArithmeticComputation::Add,
2376 TokenKind::Minus => ArithmeticComputation::Subtract,
2377 _ => unreachable!("BUG: only + and - should reach here"),
2378 };
2379
2380 let right = self.parse_power_for_range_bound()?;
2381 let end_span = right
2382 .source_location
2383 .as_ref()
2384 .map(|s| s.span.clone())
2385 .unwrap_or_else(|| start_span.clone());
2386 let span = self.span_covering(&start_span, &end_span);
2387
2388 left = self.new_expression(
2389 ExpressionKind::Arithmetic(Arc::new(left), operation, Arc::new(right)),
2390 self.make_source(span),
2391 )?;
2392 }
2393
2394 Ok(left)
2395 }
2396
2397 fn parse_power_for_range_bound(&mut self) -> Result<Expression, Error> {
2398 let start_span = self.peek()?.span.clone();
2399 let left = self.parse_factor()?;
2400
2401 if self.at(&TokenKind::Caret)? {
2402 self.next()?;
2403 self.check_depth()?;
2404 let right = self.parse_power_for_range_bound()?;
2405 self.depth_tracker.pop_depth();
2406 let end_span = right
2407 .source_location
2408 .as_ref()
2409 .map(|s| s.span.clone())
2410 .unwrap_or_else(|| start_span.clone());
2411 let span = self.span_covering(&start_span, &end_span);
2412
2413 return self.new_expression(
2414 ExpressionKind::Arithmetic(
2415 Arc::new(left),
2416 ArithmeticComputation::Power,
2417 Arc::new(right),
2418 ),
2419 self.make_source(span),
2420 );
2421 }
2422
2423 Ok(left)
2424 }
2425
2426 fn parse_repository_expression(&mut self) -> Result<Expression, Error> {
2427 let start_span = self.peek()?.span.clone();
2428 let mut left = self.parse_term()?;
2429
2430 while self.at_any(&[TokenKind::Plus, TokenKind::Minus])? {
2431 let op_tok = self.next()?;
2434 let operation = match op_tok.kind {
2435 TokenKind::Plus => ArithmeticComputation::Add,
2436 TokenKind::Minus => ArithmeticComputation::Subtract,
2437 _ => unreachable!("BUG: only + and - should reach here"),
2438 };
2439
2440 let right = self.parse_term()?;
2441 if Self::is_plain_number_literal(&left) && Self::is_unit_conversion(&right) {
2442 let source = right
2443 .source_location
2444 .clone()
2445 .unwrap_or_else(|| self.make_source(start_span.clone()));
2446 return Err(Error::parsing(
2447 "Cannot add a plain number to a converted value; convert each operand before \
2448 '+' (e.g. '5 as usd + c as usd')",
2449 source,
2450 None::<String>,
2451 ));
2452 }
2453
2454 let end_span = right
2455 .source_location
2456 .as_ref()
2457 .map(|s| s.span.clone())
2458 .unwrap_or_else(|| start_span.clone());
2459 let span = self.span_covering(&start_span, &end_span);
2460
2461 left = self.new_expression(
2462 ExpressionKind::Arithmetic(Arc::new(left), operation, Arc::new(right)),
2463 self.make_source(span),
2464 )?;
2465 }
2466
2467 Ok(left)
2468 }
2469
2470 fn parse_term(&mut self) -> Result<Expression, Error> {
2471 self.parse_term_with_as(true)
2472 }
2473
2474 fn parse_term_with_as(&mut self, allow_as: bool) -> Result<Expression, Error> {
2475 let start_span = self.peek()?.span.clone();
2476 let mut left = self.parse_power()?;
2477 if allow_as {
2478 left = self.parse_as_chain(left, start_span.clone())?;
2479 }
2480
2481 while self.at_any(&[TokenKind::Star, TokenKind::Slash, TokenKind::Percent])? {
2482 let op_tok = self.next()?;
2485 let operation = match op_tok.kind {
2486 TokenKind::Star => ArithmeticComputation::Multiply,
2487 TokenKind::Slash => ArithmeticComputation::Divide,
2488 TokenKind::Percent => ArithmeticComputation::Modulo,
2489 _ => unreachable!("BUG: only *, /, % should reach here"),
2490 };
2491
2492 let right_start_span = self.peek()?.span.clone();
2493 let mut right = self.parse_power()?;
2494 if allow_as {
2495 right = self.parse_as_chain(right, right_start_span)?;
2496 }
2497 let end_span = right
2498 .source_location
2499 .as_ref()
2500 .map(|s| s.span.clone())
2501 .unwrap_or_else(|| start_span.clone());
2502 let span = self.span_covering(&start_span, &end_span);
2503
2504 left = self.new_expression(
2505 ExpressionKind::Arithmetic(Arc::new(left), operation, Arc::new(right)),
2506 self.make_source(span),
2507 )?;
2508 }
2509
2510 Ok(left)
2511 }
2512
2513 fn parse_power(&mut self) -> Result<Expression, Error> {
2514 let start_span = self.peek()?.span.clone();
2515 let left = self.parse_range_operand()?;
2516
2517 if self.at(&TokenKind::Caret)? {
2518 self.next()?;
2519 self.check_depth()?;
2520 let right = self.parse_power()?;
2521 self.depth_tracker.pop_depth();
2522 let end_span = right
2523 .source_location
2524 .as_ref()
2525 .map(|s| s.span.clone())
2526 .unwrap_or_else(|| start_span.clone());
2527 let span = self.span_covering(&start_span, &end_span);
2528
2529 return self.new_expression(
2530 ExpressionKind::Arithmetic(
2531 Arc::new(left),
2532 ArithmeticComputation::Power,
2533 Arc::new(right),
2534 ),
2535 self.make_source(span),
2536 );
2537 }
2538
2539 Ok(left)
2540 }
2541
2542 fn parse_factor(&mut self) -> Result<Expression, Error> {
2543 let peeked = self.peek()?;
2544 let start_span = peeked.span.clone();
2545
2546 if peeked.kind == TokenKind::Minus {
2547 self.next()?;
2548 let operand = self.parse_primary_or_math()?;
2549 let end_span = operand
2550 .source_location
2551 .as_ref()
2552 .map(|s| s.span.clone())
2553 .unwrap_or_else(|| start_span.clone());
2554 let span = self.span_covering(&start_span, &end_span);
2555
2556 if let ExpressionKind::Literal(value) = &operand.kind {
2557 if let Ok(negated) = try_negate_numeric_literal(value.clone()) {
2558 return self
2559 .new_expression(ExpressionKind::Literal(negated), self.make_source(span));
2560 }
2561 }
2562
2563 let zero = self.new_expression(
2564 ExpressionKind::Literal(Value::Number(Decimal::ZERO)),
2565 self.make_source(start_span),
2566 )?;
2567 return self.new_expression(
2568 ExpressionKind::Arithmetic(
2569 Arc::new(zero),
2570 ArithmeticComputation::Subtract,
2571 Arc::new(operand),
2572 ),
2573 self.make_source(span),
2574 );
2575 }
2576
2577 if peeked.kind == TokenKind::Plus {
2578 self.next()?;
2579 return self.parse_primary_or_math();
2580 }
2581
2582 self.parse_primary_or_math()
2583 }
2584
2585 fn parse_primary_or_math(&mut self) -> Result<Expression, Error> {
2586 let peeked = self.peek()?;
2587
2588 if is_math_function(&peeked.kind) {
2590 return self.parse_math_function();
2591 }
2592
2593 self.parse_primary()
2594 }
2595
2596 fn parse_math_function(&mut self) -> Result<Expression, Error> {
2597 let func_tok = self.next()?;
2598 let start_span = func_tok.span.clone();
2599
2600 let operator = match func_tok.kind {
2601 TokenKind::Sqrt => MathematicalComputation::Sqrt,
2602 TokenKind::Sin => MathematicalComputation::Sin,
2603 TokenKind::Cos => MathematicalComputation::Cos,
2604 TokenKind::Tan => MathematicalComputation::Tan,
2605 TokenKind::Asin => MathematicalComputation::Asin,
2606 TokenKind::Acos => MathematicalComputation::Acos,
2607 TokenKind::Atan => MathematicalComputation::Atan,
2608 TokenKind::Log => MathematicalComputation::Log,
2609 TokenKind::Exp => MathematicalComputation::Exp,
2610 TokenKind::Abs => MathematicalComputation::Abs,
2611 TokenKind::Floor => MathematicalComputation::Floor,
2612 TokenKind::Ceil => MathematicalComputation::Ceil,
2613 TokenKind::Round => MathematicalComputation::Round,
2614 _ => unreachable!("BUG: only math functions should reach here"),
2615 };
2616
2617 self.check_depth()?;
2618 let operand = self.parse_repository_expression()?;
2619 self.depth_tracker.pop_depth();
2620
2621 let end_span = operand
2622 .source_location
2623 .as_ref()
2624 .map(|s| s.span.clone())
2625 .unwrap_or_else(|| start_span.clone());
2626 let span = self.span_covering(&start_span, &end_span);
2627
2628 self.new_expression(
2629 ExpressionKind::MathematicalComputation(operator, Arc::new(operand)),
2630 self.make_source(span),
2631 )
2632 }
2633
2634 fn parse_primary(&mut self) -> Result<Expression, Error> {
2635 let peeked = self.peek()?;
2636 let start_span = peeked.span.clone();
2637
2638 match &peeked.kind {
2639 TokenKind::LParen => {
2641 self.next()?; let inner = self.parse_expression()?;
2643 self.expect(&TokenKind::RParen)?;
2644 Ok(inner)
2645 }
2646
2647 TokenKind::Now => {
2649 let tok = self.next()?;
2650 self.new_expression(ExpressionKind::Now, self.make_source(tok.span))
2651 }
2652
2653 TokenKind::Past | TokenKind::Future => {
2654 let tok = self.next()?;
2655 let kind = if tok.kind == TokenKind::Past {
2656 DateRelativeKind::InPast
2657 } else {
2658 DateRelativeKind::InFuture
2659 };
2660 let offset = self.parse_repository_expression()?;
2661 let span = self.span_covering(
2662 &start_span,
2663 &offset
2664 .source_location
2665 .as_ref()
2666 .map(|s| s.span.clone())
2667 .unwrap_or(start_span.clone()),
2668 );
2669 self.new_expression(
2670 ExpressionKind::PastFutureRange(kind, Arc::new(offset)),
2671 self.make_source(span),
2672 )
2673 }
2674
2675 TokenKind::StringLit => {
2677 let tok = self.next()?;
2678 let content = unquote_string(&tok.text);
2679 self.new_expression(
2680 ExpressionKind::Literal(Value::Text(content)),
2681 self.make_source(tok.span),
2682 )
2683 }
2684
2685 k if is_boolean_keyword(k) => {
2687 let tok = self.next()?;
2688 self.new_expression(
2689 ExpressionKind::Literal(Value::Boolean(token_kind_to_boolean_value(&tok.kind))),
2690 self.make_source(tok.span),
2691 )
2692 }
2693
2694 TokenKind::NumberLit => self.parse_number_expression(),
2696
2697 k if can_be_label(k) => {
2699 let reference = self.parse_expression_reference()?;
2700 let span = self.span_covering(&start_span, &self.last_span);
2701 self.new_expression(ExpressionKind::Reference(reference), self.make_source(span))
2702 }
2703
2704 _ => {
2705 let tok = self.next()?;
2706 Err(self.error_at_token(
2707 &tok,
2708 format!("Expected an expression, found '{}'", tok.text),
2709 ))
2710 }
2711 }
2712 }
2713
2714 fn parse_number_expression(&mut self) -> Result<Expression, Error> {
2715 let num_tok = self.next()?;
2716 let num_text = num_tok.text.clone();
2717 let start_span = num_tok.span.clone();
2718
2719 if num_text.len() == 4
2721 && num_text.chars().all(|c| c.is_ascii_digit())
2722 && self.at(&TokenKind::Minus)?
2723 {
2724 let minus_span = self.peek()?.span.clone();
2731 if minus_span.start == start_span.end {
2733 let value = self.parse_date_literal(num_text, start_span.clone())?;
2734 return self
2735 .new_expression(ExpressionKind::Literal(value), self.make_source(start_span));
2736 }
2737 }
2738
2739 if num_text.len() == 2
2741 && num_text.chars().all(|c| c.is_ascii_digit())
2742 && self.at(&TokenKind::Colon)?
2743 {
2744 let colon_span = self.peek()?.span.clone();
2745 if colon_span.start == start_span.end {
2746 let value = self.try_parse_time_literal(num_text, start_span.clone())?;
2747 return self
2748 .new_expression(ExpressionKind::Literal(value), self.make_source(start_span));
2749 }
2750 }
2751
2752 if self.at(&TokenKind::PercentPercent)? {
2754 let pp_tok = self.next()?;
2755 if let Ok(next_peek) = self.peek() {
2756 if next_peek.kind == TokenKind::NumberLit {
2757 return Err(self.error_at_token(
2758 &pp_tok,
2759 "Permille literal cannot be followed by a digit",
2760 ));
2761 }
2762 }
2763 let decimal = parse_decimal_string(&num_text, &start_span, self)?;
2764 return self.new_expression(
2765 ExpressionKind::Literal(Value::NumberWithUnit(decimal, "permille".to_string())),
2766 self.make_source(start_span),
2767 );
2768 }
2769
2770 if self.at(&TokenKind::Percent)? {
2772 let pct_span = self.peek()?.span.clone();
2773 let pct_tok = self.next()?;
2776 if let Ok(next_peek) = self.peek() {
2777 if next_peek.kind == TokenKind::NumberLit || next_peek.kind == TokenKind::Percent {
2778 return Err(self.error_at_token(
2779 &pct_tok,
2780 "Percent literal cannot be followed by a digit",
2781 ));
2782 }
2783 }
2784 let decimal = parse_decimal_string(&num_text, &start_span, self)?;
2785 return self.new_expression(
2786 ExpressionKind::Literal(Value::NumberWithUnit(decimal, "percent".to_string())),
2787 self.make_source(self.span_covering(&start_span, &pct_span)),
2788 );
2789 }
2790
2791 if self.at(&TokenKind::Permille)? {
2793 self.next()?;
2794 let decimal = parse_decimal_string(&num_text, &start_span, self)?;
2795 return self.new_expression(
2796 ExpressionKind::Literal(Value::NumberWithUnit(decimal, "permille".to_string())),
2797 self.make_source(start_span),
2798 );
2799 }
2800
2801 if can_be_label(&self.peek()?.kind) {
2802 let (unit_path, end_span) = self.parse_unit_path()?;
2803 let decimal = parse_decimal_string(&num_text, &start_span, self)?;
2804 return self.new_expression(
2805 ExpressionKind::Literal(Value::NumberWithUnit(decimal, unit_path)),
2806 self.make_source(self.span_covering(&start_span, &end_span)),
2807 );
2808 }
2809
2810 let decimal = parse_decimal_string(&num_text, &start_span, self)?;
2812 self.new_expression(
2813 ExpressionKind::Literal(Value::Number(decimal)),
2814 self.make_source(start_span),
2815 )
2816 }
2817
2818 fn parse_expression_reference(&mut self) -> Result<Reference, Error> {
2819 let mut segments = Vec::new();
2820
2821 let first = self.next()?;
2822 segments.push(first.text.clone());
2823
2824 while self.at(&TokenKind::Dot)? {
2825 self.next()?; let seg = self.next()?;
2827 if !can_be_label(&seg.kind) {
2828 return Err(self.error_at_token(
2829 &seg,
2830 format!("Expected an identifier after '.', found {}", seg.kind),
2831 ));
2832 }
2833 segments.push(seg.text.clone());
2834 }
2835
2836 Ok(Reference::from_path(segments))
2837 }
2838}
2839
2840fn unquote_string(s: &str) -> String {
2845 if s.len() >= 2 && s.starts_with('"') && s.ends_with('"') {
2846 s[1..s.len() - 1].to_string()
2847 } else {
2848 s.to_string()
2849 }
2850}
2851
2852fn parse_decimal_string(text: &str, span: &Span, parser: &Parser) -> Result<Decimal, Error> {
2853 text.parse::<crate::literals::NumberLiteral>()
2854 .map(|parsed| parsed.0)
2855 .map_err(|message| {
2856 Error::parsing(message, parser.make_source(span.clone()), None::<String>)
2857 })
2858}
2859
2860fn try_negate_numeric_literal(value: Value) -> Result<Value, Value> {
2862 match value {
2863 Value::Number(d) => Ok(Value::Number(-d)),
2864 Value::NumberWithUnit(d, unit) => Ok(Value::NumberWithUnit(-d, unit)),
2865 other => Err(other),
2866 }
2867}
2868
2869fn is_comparison_operator(kind: &TokenKind) -> bool {
2870 matches!(
2871 kind,
2872 TokenKind::Gt | TokenKind::Lt | TokenKind::Gte | TokenKind::Lte | TokenKind::Is
2873 )
2874}
2875
2876impl TokenKind {
2878 fn is_identifier_like(&self) -> bool {
2879 matches!(self, TokenKind::Identifier)
2880 || can_be_label(self)
2881 || is_boolean_keyword(self)
2882 || is_math_function(self)
2883 }
2884}