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_spec_name_spelling, can_be_unit_name, is_boolean_keyword, is_keyword,
6 is_math_function, is_reserved_repository_name, is_spec_body_keyword,
7 token_is_calendar_period_marker, token_kind_to_boolean_value, token_kind_to_primitive, Lexer,
8 LexerCheckpoint, Token, TokenKind,
9};
10use crate::parsing::source::Source;
11use indexmap::IndexMap;
12use rust_decimal::Decimal;
13use std::sync::Arc;
14
15#[derive(Debug)]
16pub struct ParseResult {
17 pub repositories: IndexMap<Arc<LemmaRepository>, Vec<LemmaSpec>>,
18 pub expression_count: usize,
19}
20
21impl ParseResult {
22 #[must_use]
24 pub fn flatten_specs(&self) -> Vec<&LemmaSpec> {
25 self.repositories
26 .values()
27 .flat_map(|specs| specs.iter())
28 .collect()
29 }
30
31 #[must_use]
32 pub fn into_flattened_specs(self) -> Vec<LemmaSpec> {
33 self.repositories.into_values().flatten().collect()
34 }
35}
36
37pub fn parse_repository_qualifier_str(
40 input: &str,
41) -> Result<crate::parsing::ast::RepositoryQualifier, Error> {
42 let limits = ResourceLimits::default();
43 let mut parser = Parser::new(
44 input.trim(),
45 crate::parsing::source::SourceType::Volatile,
46 &limits,
47 );
48 let (qualifier, _) = parser.parse_repository_qualifier()?;
49 if !parser.at(&TokenKind::Eof)? {
50 let tok = parser.peek()?.clone();
51 return Err(parser.error_at_token(
52 &tok,
53 format!(
54 "Unexpected {} after repository qualifier '{}'",
55 tok.kind, qualifier.name
56 ),
57 ));
58 }
59 Ok(qualifier)
60}
61
62pub fn parse(
63 content: &str,
64 source_type: crate::parsing::source::SourceType,
65 limits: &ResourceLimits,
66) -> Result<ParseResult, Error> {
67 if content.len() > limits.max_source_size_bytes {
68 return Err(Error::resource_limit_exceeded(
69 "max_source_size_bytes",
70 format!(
71 "{} bytes ({} MB)",
72 limits.max_source_size_bytes,
73 limits.max_source_size_bytes / (1024 * 1024)
74 ),
75 format!(
76 "{} bytes ({:.2} MB)",
77 content.len(),
78 content.len() as f64 / (1024.0 * 1024.0)
79 ),
80 "Reduce source size or split into multiple specs",
81 None,
82 None,
83 None,
84 ));
85 }
86
87 let mut parser = Parser::new(content, source_type, limits);
88 let repositories = parser.parse_file()?;
89 let mut result = ParseResult {
90 repositories,
91 expression_count: parser.expression_count,
92 };
93 canonicalize_parse_result(&mut result);
94 Ok(result)
95}
96
97fn canonicalize_parse_result(result: &mut ParseResult) {
98 let old = std::mem::take(&mut result.repositories);
99 let mut new_map: IndexMap<Arc<LemmaRepository>, Vec<LemmaSpec>> = IndexMap::new();
100 for (repo, mut specs) in old {
101 let mut canonical_repo = (*repo).clone();
102 canonicalize_repository(&mut canonical_repo);
103 for spec in &mut specs {
104 canonicalize_lemma_spec(spec);
105 }
106 new_map
107 .entry(Arc::new(canonical_repo))
108 .or_default()
109 .extend(specs);
110 }
111 result.repositories = new_map;
112}
113
114struct ParserCheckpoint {
116 lexer: LexerCheckpoint,
117 expression_count: usize,
118 table_len: usize,
119}
120
121struct Parser {
122 lexer: Lexer,
123 source_type: crate::parsing::source::SourceType,
124 depth_tracker: DepthTracker,
125 expression_count: usize,
126 max_expression_count: usize,
127 max_spec_name_length: usize,
128 max_data_name_length: usize,
129 max_rule_name_length: usize,
130 last_span: Span,
131 bare_operand: bool,
133 call_argument_depth: usize,
135 bound_chain_starts: Vec<usize>,
137 no_range_at: std::collections::HashMap<usize, ExprFlags>,
140 table: ExprTable<ExpressionKind>,
141 expr_frames: Vec<ExprCont>,
144}
145
146impl Parser {
147 fn new(
148 content: &str,
149 source_type: crate::parsing::source::SourceType,
150 limits: &ResourceLimits,
151 ) -> Self {
152 Parser {
153 lexer: Lexer::new(content, &source_type),
154 source_type,
155 depth_tracker: DepthTracker::with_max_depth(limits.max_expression_depth),
156 expression_count: 0,
157 max_expression_count: limits.max_expression_count,
158 max_spec_name_length: crate::limits::MAX_SPEC_NAME_LENGTH,
159 max_data_name_length: crate::limits::MAX_DATA_NAME_LENGTH,
160 max_rule_name_length: crate::limits::MAX_RULE_NAME_LENGTH,
161 last_span: Span {
162 start: 0,
163 end: 0,
164 line: 1,
165 col: 0,
166 },
167 bare_operand: false,
168 call_argument_depth: 0,
169 bound_chain_starts: Vec::new(),
170 no_range_at: std::collections::HashMap::new(),
171 expr_frames: Vec::new(),
172 table: ExprTable::default(),
173 }
174 }
175
176 fn source_type(&self) -> crate::parsing::source::SourceType {
177 self.source_type.clone()
178 }
179
180 fn peek(&mut self) -> Result<&Token, Error> {
181 self.lexer.peek()
182 }
183
184 fn next(&mut self) -> Result<Token, Error> {
185 let token = self.lexer.next_token()?;
186 self.last_span = token.span.clone();
187 Ok(token)
188 }
189
190 fn at(&mut self, kind: &TokenKind) -> Result<bool, Error> {
191 Ok(&self.peek()?.kind == kind)
192 }
193
194 fn at_any(&mut self, kinds: &[TokenKind]) -> Result<bool, Error> {
195 let current = &self.peek()?.kind;
196 Ok(kinds.contains(current))
197 }
198
199 fn checkpoint(&self) -> ParserCheckpoint {
200 ParserCheckpoint {
201 lexer: self.lexer.checkpoint(),
202 expression_count: self.expression_count,
203 table_len: self.table.len(),
204 }
205 }
206
207 fn restore(&mut self, checkpoint: ParserCheckpoint) {
209 self.lexer.restore(checkpoint.lexer);
210 self.expression_count = checkpoint.expression_count;
211 self.table.truncate(checkpoint.table_len);
212 }
213
214 fn expect(&mut self, kind: &TokenKind) -> Result<Token, Error> {
215 let token = self.next()?;
216 if &token.kind == kind {
217 Ok(token)
218 } else {
219 Err(self.error_at_token(&token, format!("Expected {}, found {}", kind, token.kind)))
220 }
221 }
222
223 fn at_calendar_period_marker(&mut self) -> Result<bool, Error> {
224 Ok(token_is_calendar_period_marker(self.peek()?))
225 }
226
227 fn expect_calendar_period_marker(&mut self) -> Result<Token, Error> {
228 let token = self.next()?;
229 if token_is_calendar_period_marker(&token) {
230 Ok(token)
231 } else {
232 Err(self.error_at_token(&token, "Expected 'calendar' (date-period predicate marker)"))
233 }
234 }
235
236 fn next_calendar_period_marker(&mut self) -> Result<Token, Error> {
237 self.expect_calendar_period_marker()
238 }
239
240 fn error_at_token(&self, token: &Token, message: impl Into<String>) -> Error {
241 Error::parsing(
242 message,
243 Source::new(self.source_type(), token.span.clone()),
244 None::<String>,
245 )
246 }
247
248 fn error_at_token_with_suggestion(
249 &self,
250 token: &Token,
251 message: impl Into<String>,
252 suggestion: impl Into<String>,
253 ) -> Error {
254 Error::parsing(
255 message,
256 Source::new(self.source_type(), token.span.clone()),
257 Some(suggestion),
258 )
259 }
260
261 fn parse_spec_ref_trailing_effective(&mut self) -> Result<Option<DateTimeValue>, Error> {
262 let mut effective = None;
263 if self.at(&TokenKind::NumberLit)? {
264 let peeked = self.peek()?;
265 if peeked.text.len() == 4 && peeked.text.chars().all(|c| c.is_ascii_digit()) {
266 effective = self.try_parse_effective_from()?;
267 }
268 }
269 Ok(effective)
270 }
271
272 fn make_source(&self, span: Span) -> Source {
273 Source::new(self.source_type(), span)
274 }
275
276 fn span_from(&self, start: &Span) -> Span {
277 Span {
280 start: start.start,
281 end: start.end.max(start.start),
282 line: start.line,
283 col: start.col,
284 }
285 }
286
287 fn span_covering(&self, start: &Span, end: &Span) -> Span {
288 Span {
289 start: start.start,
290 end: end.end,
291 line: start.line,
292 col: start.col,
293 }
294 }
295
296 fn parse_file(&mut self) -> Result<IndexMap<Arc<LemmaRepository>, Vec<LemmaSpec>>, Error> {
301 let mut map: IndexMap<Arc<LemmaRepository>, Vec<LemmaSpec>> = IndexMap::new();
302 let mut current_repo = Arc::new(LemmaRepository::new(None));
303
304 loop {
305 if self.at(&TokenKind::Eof)? {
306 break;
307 }
308
309 if self.at(&TokenKind::Repo)? {
310 let repo_token = self.expect(&TokenKind::Repo)?;
311 let start_line = repo_token.span.line;
312 let (qualifier, _) = self.parse_repository_qualifier()?;
313 crate::limits::check_max_length(
314 &qualifier.name,
315 self.max_spec_name_length,
316 "repository name",
317 Some(Source::new(self.source_type(), repo_token.span)),
318 )?;
319 current_repo = Arc::new(
320 LemmaRepository::new(Some(qualifier.name)).with_start_line(start_line),
321 );
322 map.entry(Arc::clone(¤t_repo)).or_default();
323 continue;
324 }
325
326 if self.at(&TokenKind::Spec)? {
327 let spec = self.parse_spec()?;
328 map.entry(Arc::clone(¤t_repo)).or_default().push(spec);
329 continue;
330 }
331
332 let token = self.next()?;
333 return Err(self.error_at_token_with_suggestion(
334 &token,
335 format!(
336 "Expected a top-level `repo` or `spec` declaration, found {}",
337 token.kind
338 ),
339 "Each Lemma file is a sequence of optional `repo <name>` sections followed by `spec <name>` blocks",
340 ));
341 }
342
343 Ok(map)
344 }
345
346 fn parse_spec(&mut self) -> Result<LemmaSpec, Error> {
347 let spec_token = self.expect(&TokenKind::Spec)?;
348 let start_line = spec_token.span.line;
349
350 let (name, name_span) = self.parse_spec_name()?;
351 crate::limits::check_max_length(
352 &name,
353 self.max_spec_name_length,
354 "spec",
355 Some(Source::new(self.source_type(), name_span)),
356 )?;
357
358 let effective_from = self.try_parse_effective_from()?;
359
360 let commentary = self.try_parse_commentary()?;
361
362 let mut spec = LemmaSpec::new(name.clone())
363 .with_source_type(self.source_type())
364 .with_start_line(start_line);
365 spec.effective_from = crate::parsing::ast::EffectiveDate::from_option(effective_from);
366
367 if let Some(commentary_text) = commentary {
368 spec = spec.set_commentary(commentary_text);
369 }
370
371 let mut data = Vec::new();
375 let mut rules = Vec::new();
376 let mut meta_fields = Vec::new();
377
378 loop {
379 let peek_kind = self.peek()?.kind.clone();
380 match peek_kind {
381 TokenKind::Data => {
382 let datum = self.parse_data()?;
383 data.push(datum);
384 }
385 TokenKind::Rule => {
386 let rule = self.parse_rule()?;
387 rules.push(rule);
388 }
389 TokenKind::Meta => {
390 let meta = self.parse_meta()?;
391 meta_fields.push(meta);
392 }
393 TokenKind::Uses => {
394 let uses_data = self.parse_uses_statement()?;
395 data.push(uses_data);
396 }
397 TokenKind::Spec | TokenKind::Repo | TokenKind::Eof => break,
398 TokenKind::With => {
399 let token = self.next()?;
400 return Err(self.error_at_token_with_suggestion(
401 &token,
402 "Standalone `with alias.field: value` is not allowed".to_string(),
403 "Use `uses alias: spec -> with field: value`",
404 ));
405 }
406 _ => {
407 let token = self.next()?;
408 return Err(self.error_at_token_with_suggestion(
409 &token,
410 format!(
411 "Expected 'data', 'rule', 'meta', 'uses', or a new 'spec', found '{}'",
412 token.text
413 ),
414 "Check the spelling or add the appropriate keyword",
415 ));
416 }
417 }
418 }
419
420 for data in data {
421 spec = spec.add_data(data);
422 }
423 for rule in rules {
424 spec = spec.add_rule(rule);
425 }
426 for meta in meta_fields {
427 spec = spec.add_meta_field(meta);
428 }
429
430 Ok(spec)
431 }
432
433 fn next_logical_name(&mut self) -> Result<Token, Error> {
434 let token = self.lexer.next_logical_name()?;
435 self.last_span = token.span.clone();
436 Ok(token)
437 }
438
439 fn parse_spec_name(&mut self) -> Result<(String, Span), Error> {
440 let tok = self.next_logical_name()?;
441 if tok.text.starts_with('@') {
442 return Err(Error::parsing(
443 "'@' is not allowed in spec names; it is valid for repository names (`repo @org/name`) and qualifiers (`uses @org/name`)",
444 self.make_source(tok.span),
445 Some(
446 "Write `spec my_spec`, then reference registry specs as `uses alias: @org/repo spec_name` or `data x: alias.TypeName` after importing with `uses`.",
447 ),
448 ));
449 }
450 if !can_be_spec_name_spelling(&tok.text) {
451 return Err(
452 self.error_at_token(&tok, format!("Expected a spec name, found '{}'", tok.text))
453 );
454 }
455 Ok((tok.text, tok.span))
456 }
457
458 fn parse_repository_qualifier(&mut self) -> Result<(RepositoryQualifier, Span), Error> {
460 let tok = self.next_logical_name()?;
461 if !tok.text.starts_with('@') && is_reserved_repository_name(&tok.text) {
462 return Err(self.error_at_token(
463 &tok,
464 format!(
465 "'{}' is a reserved keyword and cannot be used as a repository name",
466 tok.text.to_ascii_lowercase()
467 ),
468 ));
469 }
470 Ok((RepositoryQualifier { name: tok.text }, tok.span))
471 }
472
473 pub fn parse_spec_ref_target(&mut self) -> Result<SpecRef, Error> {
475 let first = self.next_logical_name()?;
476 let mut repository = None;
477 let mut repository_span = None;
478 let (spec_name, spec_name_span) = if first.text.starts_with('@') {
479 repository = Some(RepositoryQualifier {
480 name: first.text.clone(),
481 });
482 repository_span = Some(first.span.clone());
483 self.parse_spec_name()?
484 } else if can_be_label(&self.peek()?.kind) {
485 if is_reserved_repository_name(&first.text) {
486 return Err(self.error_at_token(
487 &first,
488 format!(
489 "'{}' is a reserved keyword and cannot be used as a repository name",
490 first.text.to_ascii_lowercase()
491 ),
492 ));
493 }
494 repository = Some(RepositoryQualifier {
495 name: first.text.clone(),
496 });
497 repository_span = Some(first.span.clone());
498 self.parse_spec_name()?
499 } else {
500 (first.text, first.span)
501 };
502 let effective = self.parse_spec_ref_trailing_effective()?;
503 let target_span = self.span_covering(&spec_name_span, &self.last_span);
504
505 let has_repository = repository.is_some();
506 Ok(SpecRef {
507 name: spec_name,
508 repository,
509 effective,
510 repository_span: if has_repository {
511 repository_span
512 } else {
513 None
514 },
515 target_span: Some(target_span),
516 })
517 }
518
519 fn try_parse_effective_from(&mut self) -> Result<Option<DateTimeValue>, Error> {
520 if !self.at(&TokenKind::NumberLit)? {
525 return Ok(None);
526 }
527
528 let peeked = self.peek()?;
529 let peeked_text = peeked.text.clone();
530 let peeked_span = peeked.span.clone();
531
532 if peeked_text.len() == 4 && peeked_text.chars().all(|c| c.is_ascii_digit()) {
534 let mut dt_str = String::new();
536 let num_tok = self.next()?; dt_str.push_str(&num_tok.text);
538
539 while self.at(&TokenKind::Minus)? {
541 self.next()?; dt_str.push('-');
543 let part = self.next()?;
544 dt_str.push_str(&part.text);
545 }
546
547 if self.at(&TokenKind::Identifier)? {
549 let peeked = self.peek()?;
550 if peeked.text.starts_with('T') || peeked.text.starts_with('t') {
551 let time_part = self.next()?;
552 dt_str.push_str(&time_part.text);
553 while self.at(&TokenKind::Colon)? {
555 self.next()?;
556 dt_str.push(':');
557 let part = self.next()?;
558 dt_str.push_str(&part.text);
559 }
560 if self.at(&TokenKind::Plus)? {
562 self.next()?;
563 dt_str.push('+');
564 let tz_part = self.next()?;
565 dt_str.push_str(&tz_part.text);
566 if self.at(&TokenKind::Colon)? {
567 self.next()?;
568 dt_str.push(':');
569 let tz_min = self.next()?;
570 dt_str.push_str(&tz_min.text);
571 }
572 }
573 }
574 }
575
576 if let Ok(dtv) = dt_str.parse::<DateTimeValue>() {
578 return Ok(Some(dtv));
579 }
580
581 return Err(Error::parsing(
582 format!("Invalid date/time in spec declaration: '{}'", dt_str),
583 self.make_source(peeked_span),
584 None::<String>,
585 ));
586 }
587
588 Ok(None)
589 }
590
591 fn try_parse_commentary(&mut self) -> Result<Option<String>, Error> {
592 if !self.at(&TokenKind::Commentary)? {
593 return Ok(None);
594 }
595 let token = self.next()?;
596 let trimmed = token.text.trim().to_string();
597 if trimmed.is_empty() {
598 Ok(None)
599 } else {
600 Ok(Some(trimmed))
601 }
602 }
603
604 fn parse_data(&mut self) -> Result<LemmaData, Error> {
609 let data_token = self.expect(&TokenKind::Data)?;
610 let start_span = data_token.span.clone();
611
612 let reference = self.parse_reference()?;
613 for segment in reference
614 .segments
615 .iter()
616 .chain(std::iter::once(&reference.name))
617 {
618 crate::limits::check_max_length(
619 segment,
620 self.max_data_name_length,
621 "data",
622 Some(Source::new(self.source_type(), start_span.clone())),
623 )?;
624 }
625
626 self.expect(&TokenKind::Colon)?;
627
628 if !reference.segments.is_empty() {
629 let tok = self.peek()?.clone();
630 return Err(self.error_at_token_with_suggestion(
631 &tok,
632 "Dotted paths require `uses` with `-> with`; `data` declares types and values on local names only.",
633 "Use `uses alias: spec` with ` -> with path.to.slot: <value or reference>`.",
634 ));
635 }
636
637 let value = self.parse_data_value()?;
638
639 let span = self.span_covering(&start_span, &self.last_span);
640 let source = self.make_source(span);
641
642 Ok(LemmaData::new(reference, value, source))
643 }
644
645 fn with_rhs_starts_as_literal(kind: &TokenKind) -> bool {
646 matches!(
647 kind,
648 TokenKind::StringLit | TokenKind::NumberLit | TokenKind::Minus | TokenKind::Plus
649 ) || is_boolean_keyword(kind)
650 }
651
652 fn parse_with_rhs(&mut self) -> Result<WithRhs, Error> {
653 let peek_kind = self.peek()?.kind.clone();
654
655 if Self::with_rhs_starts_as_literal(&peek_kind) {
656 let value = self.parse_literal_value()?;
657 return Ok(WithRhs::Literal(value));
658 }
659
660 if can_be_label(&peek_kind) {
661 let target = self.parse_reference()?;
662 if self.at(&TokenKind::Arrow)? && self.lexer.peek_second()?.kind != TokenKind::With {
663 let tok = self.peek()?.clone();
664 return Err(self.error_at_token_with_suggestion(
665 &tok,
666 "Constraint chains (`-> ...`) are not allowed on a `uses` binding reference.",
667 "Use `data name: <type> -> ...` for type constraints on local slots.",
668 ));
669 }
670 return Ok(WithRhs::Reference { target });
671 }
672
673 let tok = self.peek()?.clone();
674 Err(self.error_at_token(
675 &tok,
676 format!(
677 "Expected a reference or literal after `-> with ...:`, found {}",
678 tok.kind
679 ),
680 ))
681 }
682
683 fn parse_reference(&mut self) -> Result<Reference, Error> {
684 let mut segments = Vec::new();
685
686 let first = self.next()?;
687 if is_keyword(&first.kind) {
689 return Err(self.error_at_token_with_suggestion(
690 &first,
691 format!(
692 "'{}' is a reserved keyword and cannot be used as a name",
693 first.text.to_ascii_lowercase()
694 ),
695 "Choose a different name that is not a reserved keyword",
696 ));
697 }
698
699 if !can_be_label(&first.kind) {
700 return Err(self.error_at_token(
701 &first,
702 format!("Expected an identifier, found {}", first.kind),
703 ));
704 }
705
706 segments.push(first.text.clone());
707
708 while self.at(&TokenKind::Dot)? {
710 self.next()?; let seg = self.next()?;
712 if !can_be_label(&seg.kind) {
713 return Err(self.error_at_token(
714 &seg,
715 format!("Expected an identifier after '.', found {}", seg.kind),
716 ));
717 }
718 segments.push(seg.text.clone());
719 }
720
721 Ok(Reference::from_path(segments))
722 }
723
724 fn parse_data_value(&mut self) -> Result<DataValue, Error> {
725 if self.at(&TokenKind::Spec)? {
726 let token = self.next()?;
727 return Err(self.error_at_token_with_suggestion(
728 &token,
729 "Cannot import a spec with `data`; use `uses`",
730 "Use `uses <spec_name>` or `uses <alias>: <spec_name>`",
731 ));
732 }
733
734 let peek_kind = self.peek()?.kind.clone();
735
736 if token_kind_to_primitive(&peek_kind).is_some() || can_be_label(&peek_kind) {
737 let (base, constraints) = self.parse_type_arrow_chain()?;
738 return Ok(DataValue::Definition {
739 base: Some(base),
740 constraints,
741 value: None,
742 });
743 }
744
745 let value = self.parse_literal_value()?;
747 Ok(DataValue::Definition {
748 base: None,
749 constraints: None,
750 value: Some(value),
751 })
752 }
753
754 fn parse_uses_item(&mut self, start_span: &Span) -> Result<LemmaData, Error> {
757 let explicit_alias = if self.lexer.peek_second()?.kind == TokenKind::Colon {
758 let peek = self.peek()?.clone();
759 if is_keyword(&peek.kind) {
760 return Err(self.error_at_token_with_suggestion(
761 &peek,
762 format!(
763 "'{}' is a reserved keyword and cannot be used as a name",
764 peek.text.to_ascii_lowercase()
765 ),
766 "Choose a different name that is not a reserved keyword",
767 ));
768 }
769 if can_be_label(&peek.kind) {
770 let alias_tok = self.next()?;
771 self.expect(&TokenKind::Colon)?;
772 Some(alias_tok)
773 } else {
774 None
775 }
776 } else {
777 None
778 };
779
780 let spec_ref = self.parse_spec_ref_target()?;
781
782 let spec_name_source = spec_ref
783 .target_span
784 .as_ref()
785 .map(|sp| Source::new(self.source_type(), sp.clone()));
786
787 crate::limits::check_max_length(
788 &spec_ref.name,
789 self.max_spec_name_length,
790 "spec",
791 spec_name_source.clone(),
792 )?;
793
794 let alias = if let Some(ref alias_tok) = explicit_alias {
795 crate::limits::check_max_length(
796 &alias_tok.text,
797 self.max_data_name_length,
798 "data",
799 Some(Source::new(self.source_type(), alias_tok.span.clone())),
800 )?;
801 alias_tok.text.clone()
802 } else {
803 let implicit = spec_ref.name.clone();
804 crate::limits::check_max_length(
805 &implicit,
806 self.max_data_name_length,
807 "data",
808 spec_name_source,
809 )?;
810 implicit
811 };
812
813 if self.at(&TokenKind::List)? {
814 self.next()?;
815 let list = self.parse_uses_list(&alias)?;
816 let span = self.span_covering(start_span, &self.last_span);
817 return Ok(LemmaData::new(
818 Reference::local(alias),
819 DataValue::ImportList { spec_ref, list },
820 self.make_source(span),
821 ));
822 }
823
824 let mut bindings = Vec::new();
825 while self.at(&TokenKind::Arrow)? {
826 if self.lexer.peek_second()?.kind != TokenKind::With {
827 let tok = self.peek()?.clone();
828 return Err(self.error_at_token_with_suggestion(
829 &tok,
830 "Expected `with` after `->` in a `uses` block.",
831 "Write ` -> with path.to.slot: <value or reference>` under the `uses` line.",
832 ));
833 }
834 self.next()?; let with_token = self.expect(&TokenKind::With)?;
836 bindings.extend(self.parse_uses_field_pairs(&alias, &with_token)?);
837 }
838
839 let span = self.span_covering(start_span, &self.last_span);
840 Ok(LemmaData::new(
841 Reference::local(alias),
842 DataValue::Import { spec_ref, bindings },
843 self.make_source(span),
844 ))
845 }
846
847 fn parse_uses_list(&mut self, alias: &str) -> Result<UsesList, Error> {
849 let mut list = UsesList {
850 key: None,
851 rows: Vec::new(),
852 };
853 while self.at(&TokenKind::Arrow)? {
854 let arrow = self.next()?;
855 let name_tok = self.next()?;
856 match name_tok.kind {
857 TokenKind::Key => {
858 if list.key.is_some() {
859 return Err(self.error_at_token(
860 &name_tok,
861 format!("`{alias}` declares `-> key` twice; list every key field in one `-> key`"),
862 ));
863 }
864 let mut fields = vec![self.parse_reference()?];
865 while self.at(&TokenKind::Comma)? {
866 self.next()?;
867 fields.push(self.parse_reference()?);
868 }
869 let span = self.span_covering(&arrow.span, &self.last_span);
870 list.key = Some(UsesListKey {
871 fields,
872 source_location: self.make_source(span),
873 });
874 }
875 TokenKind::With => {
876 let row = if self.at_uses_field_pair()? {
877 let bindings = self.parse_uses_field_pairs(alias, &name_tok)?;
878 let span = self.span_covering(&arrow.span, &self.last_span);
879 UsesListRow::Fields {
880 bindings,
881 source_location: self.make_source(span),
882 }
883 } else {
884 let values = self.parse_uses_list_values()?;
885 let span = self.span_covering(&arrow.span, &self.last_span);
886 UsesListRow::Values {
887 values,
888 source_location: self.make_source(span),
889 }
890 };
891 list.rows.push(row);
892 }
893 _ => {
894 let command = self.parse_list_command_body(name_tok)?;
895 let command = display_list_command(&self.table, &command);
896 return Err(self.error_at_token(
897 &arrow,
898 format!(
899 "data supplies values; `-> {command}` is a query on `{alias}`, write it in a rule"
900 ),
901 ));
902 }
903 }
904 }
905 Ok(list)
906 }
907
908 fn parse_uses_list_values(&mut self) -> Result<Vec<WithRhs>, Error> {
911 let mut values = Vec::new();
912 loop {
913 values.push(self.parse_with_rhs()?);
914 if !self.at(&TokenKind::Comma)? {
915 break;
916 }
917 self.next()?;
918 if self.at_command_terminator()? || self.at(&TokenKind::Comma)? {
919 let tok = self.peek()?.clone();
920 return Err(self.error_at_token_with_suggestion(
921 &tok,
922 "Trailing or empty comma in list".to_string(),
923 "Remove the extra comma, or add the missing row",
924 ));
925 }
926 }
927 if self.at_uses_field_pair()? {
928 let tok = self.peek()?.clone();
929 return Err(self.error_at_token_with_suggestion(
930 &tok,
931 "A `-> with` line holds either references or field pairs, not both".to_string(),
932 "Put the field pairs on their own `-> with` line",
933 ));
934 }
935 Ok(values)
936 }
937
938 fn parse_uses_field_pairs(
940 &mut self,
941 alias: &str,
942 with_token: &Token,
943 ) -> Result<Vec<UsesBinding>, Error> {
944 let mut bindings = Vec::new();
945 let mut binding_start_span = with_token.span.clone();
946 loop {
947 let path = self.parse_reference()?;
948 for segment in path.segments.iter().chain(std::iter::once(&path.name)) {
949 crate::limits::check_max_length(
950 segment,
951 self.max_data_name_length,
952 "uses binding",
953 Some(Source::new(self.source_type(), binding_start_span.clone())),
954 )?;
955 }
956 if path
957 .segments
958 .first()
959 .is_some_and(|segment| segment == alias)
960 {
961 return Err(self.error_at_token_with_suggestion(
962 with_token,
963 format!(
964 "Binding path must be relative to the imported spec, not prefixed with import alias `{alias}`."
965 ),
966 format!(
967 "Use `-> with {}: …` without the `{alias}.` prefix.",
968 path.name
969 ),
970 ));
971 }
972
973 let (rhs, _) =
974 self.parse_assignment_after_key(|parser| parser.parse_with_rhs(), "with", false)?;
975
976 let binding_span = self.span_covering(&binding_start_span, &self.last_span);
977 bindings.push(UsesBinding {
978 path,
979 rhs,
980 source_location: self.make_source(binding_span),
981 });
982
983 if self.at(&TokenKind::Comma)? {
984 self.next()?;
985 if self.at_command_terminator()? || self.at(&TokenKind::Comma)? {
986 let tok = self.peek()?.clone();
987 return Err(self.error_at_token_with_suggestion(
988 &tok,
989 "Trailing or empty comma in list".to_string(),
990 "Remove the extra comma, or add the missing field pair",
991 ));
992 }
993 if !self.at_uses_field_pair()? {
994 let tok = self.peek()?.clone();
995 return Err(self.error_at_token_with_suggestion(
996 &tok,
997 "Expected a field pair after comma".to_string(),
998 "Remove the extra comma, or add `path: value`",
999 ));
1000 }
1001 binding_start_span = self.peek()?.span.clone();
1002 continue;
1003 }
1004
1005 if self.at_uses_field_pair()? {
1006 let tok = self.peek()?.clone();
1007 return Err(self.error_at_token_with_suggestion(
1008 &tok,
1009 "Expected a comma between field pairs".to_string(),
1010 "Separate field pairs with commas, for example `-> with qty: 3, sku: \"latte\"`",
1011 ));
1012 }
1013 return Ok(bindings);
1014 }
1015 }
1016
1017 fn at_uses_field_pair(&mut self) -> Result<bool, Error> {
1018 if self.at_command_terminator()? {
1019 return Ok(false);
1020 }
1021 self.at_path_then_colon()
1022 }
1023
1024 fn at_path_then_colon(&mut self) -> Result<bool, Error> {
1027 if !can_be_label(&self.peek()?.kind) {
1028 return Ok(false);
1029 }
1030 let checkpoint = self.checkpoint();
1031 let result = self.scan_path_then_colon();
1032 self.restore(checkpoint);
1033 result
1034 }
1035
1036 fn scan_path_then_colon(&mut self) -> Result<bool, Error> {
1037 self.next()?;
1038 loop {
1039 match self.peek()?.kind {
1040 TokenKind::Colon => return Ok(true),
1041 TokenKind::Dot => {
1042 self.next()?;
1043 if !can_be_label(&self.peek()?.kind) {
1044 return Ok(false);
1045 }
1046 self.next()?;
1047 }
1048 _ => return Ok(false),
1049 }
1050 }
1051 }
1052
1053 fn parse_uses_statement(&mut self) -> Result<LemmaData, Error> {
1054 let uses_token = self.expect(&TokenKind::Uses)?;
1055 let start_span = uses_token.span.clone();
1056 self.parse_uses_item(&start_span)
1057 }
1058
1059 fn parse_rule(&mut self) -> Result<LemmaRule, Error> {
1064 let rule_token = self.expect(&TokenKind::Rule)?;
1065 let start_span = rule_token.span.clone();
1066
1067 let name_tok = self.next()?;
1068 if is_keyword(&name_tok.kind) {
1069 return Err(self.error_at_token_with_suggestion(
1070 &name_tok,
1071 format!(
1072 "'{}' is a reserved keyword and cannot be used as a rule name",
1073 name_tok.text.to_ascii_lowercase()
1074 ),
1075 "Choose a different name that is not a reserved keyword",
1076 ));
1077 }
1078 if !can_be_label(&name_tok.kind) {
1079 return Err(self.error_at_token(
1080 &name_tok,
1081 format!("Expected a rule name, found {}", name_tok.kind),
1082 ));
1083 }
1084 let rule_name = name_tok.text.clone();
1085 crate::limits::check_max_length(
1086 &rule_name,
1087 self.max_rule_name_length,
1088 "rule",
1089 Some(Source::new(self.source_type(), name_tok.span.clone())),
1090 )?;
1091
1092 self.expect(&TokenKind::Colon)?;
1093
1094 let root = if self.at(&TokenKind::Veto)? && !self.at_bare_veto_followed_by_is()? {
1096 self.parse_veto_expression()?
1097 } else {
1098 self.parse_expression()?
1099 };
1100
1101 let expression = self.finish_expression(root);
1102
1103 let mut unless_clauses = Vec::new();
1105 while self.at(&TokenKind::Unless)? {
1106 unless_clauses.push(self.parse_unless_clause()?);
1107 }
1108
1109 let end_span = if let Some(last_unless) = unless_clauses.last() {
1110 last_unless.source_location.span.clone()
1111 } else if let Some(loc) = expression.root_source() {
1112 loc.span.clone()
1113 } else {
1114 start_span.clone()
1115 };
1116
1117 let span = self.span_covering(&start_span, &end_span);
1118 Ok(LemmaRule {
1119 name: rule_name,
1120 expression,
1121 unless_clauses,
1122 source_location: self.make_source(span),
1123 })
1124 }
1125
1126 fn parse_veto_expression(&mut self) -> Result<ExprId, Error> {
1127 let veto_tok = self.expect(&TokenKind::Veto)?;
1128 let start_span = veto_tok.span.clone();
1129
1130 let message = if self.at(&TokenKind::StringLit)? {
1131 let str_tok = self.next()?;
1132 Some(str_tok.text)
1133 } else {
1134 None
1135 };
1136
1137 let span = self.span_from(&start_span);
1138 self.new_expression(
1139 ExpressionKind::Veto(VetoExpression { message }),
1140 self.make_source(span),
1141 )
1142 }
1143
1144 fn parse_unless_clause(&mut self) -> Result<UnlessClause, Error> {
1145 let unless_tok = self.expect(&TokenKind::Unless)?;
1146 let start_span = unless_tok.span.clone();
1147
1148 let condition_root = self.parse_expression()?;
1149 let condition = self.finish_expression(condition_root);
1150
1151 self.expect(&TokenKind::Then)?;
1152
1153 let result_root = if self.at(&TokenKind::Veto)? {
1154 self.parse_veto_expression()?
1155 } else {
1156 self.parse_expression()?
1157 };
1158
1159 let end_span = self
1160 .expr_span(result_root)
1161 .unwrap_or_else(|| start_span.clone());
1162 let span = self.span_covering(&start_span, &end_span);
1163 let result = self.finish_expression(result_root);
1164
1165 Ok(UnlessClause {
1166 condition,
1167 result,
1168 source_location: self.make_source(span),
1169 })
1170 }
1171
1172 fn parse_type_arrow_chain(&mut self) -> Result<(ParentType, Option<Vec<Constraint>>), Error> {
1174 let peek_kind = self.peek()?.kind.clone();
1175 let base = if let Some(primitive) = token_kind_to_primitive(&peek_kind) {
1176 self.next()?;
1177 if self.at(&TokenKind::Dot)? {
1178 let dot_tok = self.peek()?.clone();
1179 return Err(self.error_at_token_with_suggestion(
1180 &dot_tok,
1181 "A primitive type cannot be the left segment of a qualified parent path",
1182 "Use `data name: alias.typename` where `alias` is the `uses` import name and `typename` is the parent type.",
1183 ));
1184 }
1185 ParentType::Primitive { primitive }
1186 } else {
1187 let (name, _) = self.parse_spec_name()?;
1188 if let Some((alias, type_name)) = name.rsplit_once('.') {
1189 ParentType::Qualified {
1190 spec_alias: alias.to_string(),
1191 inner: Box::new(ParentType::Custom {
1192 name: type_name.to_string(),
1193 }),
1194 }
1195 } else {
1196 ParentType::Custom { name }
1197 }
1198 };
1199
1200 let base = if self.at(&TokenKind::Identifier)? && self.peek()?.text == "range" {
1201 self.next()?;
1202 ParentType::Ranged {
1203 inner: Box::new(base),
1204 }
1205 } else {
1206 base
1207 };
1208
1209 let base = if self.at(&TokenKind::List)? {
1210 self.next()?;
1211 ParentType::List {
1212 inner: Box::new(base),
1213 }
1214 } else {
1215 base
1216 };
1217
1218 let constraints = self.parse_trailing_constraints()?;
1219
1220 Ok((base, constraints))
1221 }
1222
1223 fn parse_trailing_constraints(&mut self) -> Result<Option<Vec<Constraint>>, Error> {
1224 let mut commands = Vec::new();
1225 while self.at(&TokenKind::Arrow)? {
1226 let arrow_token = self.next()?;
1227 let constraint_start_span = arrow_token.span.clone();
1228 let (cmd, cmd_args, deprecated_without_colon) = self.parse_constraint_command()?;
1229 let constraint_span = self.span_covering(&constraint_start_span, &self.last_span);
1230 commands.push(Constraint {
1231 command: cmd,
1232 args: cmd_args,
1233 source_location: self.make_source(constraint_span),
1234 deprecated_without_colon,
1235 });
1236 }
1237 let constraints = if commands.is_empty() {
1238 None
1239 } else {
1240 Some(commands)
1241 };
1242 Ok(constraints)
1243 }
1244
1245 fn parse_constraint_command(
1246 &mut self,
1247 ) -> Result<(TypeConstraintCommand, Vec<CommandArg>, bool), Error> {
1248 let name_tok = self.next()?;
1249 if matches!(name_tok.kind, TokenKind::Key) {
1250 return Err(self.error_at_token(
1251 &name_tok,
1252 "value lists are numbered; `-> key` is for instance lists".to_string(),
1253 ));
1254 }
1255 if matches!(
1256 name_tok.kind,
1257 TokenKind::Find
1258 | TokenKind::First
1259 | TokenKind::Last
1260 | TokenKind::Sum
1261 | TokenKind::Avg
1262 | TokenKind::Product
1263 | TokenKind::Count
1264 | TokenKind::Min
1265 | TokenKind::Max
1266 | TokenKind::Any
1267 | TokenKind::All
1268 | TokenKind::Where
1269 | TokenKind::Sort
1270 | TokenKind::Top
1271 ) {
1272 return Err(self.error_at_token(
1273 &name_tok,
1274 "data supplies values; query commands belong on rules, not data declarations"
1275 .to_string(),
1276 ));
1277 }
1278 if !can_be_label(&name_tok.kind)
1279 && !matches!(
1280 name_tok.kind,
1281 TokenKind::Lower | TokenKind::Upper | TokenKind::With
1282 )
1283 {
1284 return Err(self.error_at_token(
1285 &name_tok,
1286 format!("Expected a command name, found {}", name_tok.kind),
1287 ));
1288 }
1289 let cmd = try_parse_type_constraint_command(&name_tok.text).ok_or_else(|| {
1290 self.error_at_token(
1291 &name_tok,
1292 format!(
1293 "Unknown constraint command '{}'. Valid commands: help, suggest, with, unit, trait, minimum, maximum, lower, upper, decimals, option, options, length",
1294 name_tok.text
1295 ),
1296 )
1297 })?;
1298
1299 match cmd.continuation_shape() {
1300 ContinuationShape::Assignment => {
1301 let (args, deprecated_without_colon) = self.parse_unit_as_assignment()?;
1302 Ok((cmd, args, deprecated_without_colon))
1303 }
1304 ContinuationShape::Single => Ok((cmd, self.parse_single_command_arg(cmd)?, false)),
1305 ContinuationShape::CommaSeparated => {
1306 Ok((cmd, self.parse_comma_separated_command_args()?, false))
1307 }
1308 }
1309 }
1310
1311 fn parse_assignment_after_key<T>(
1313 &mut self,
1314 parse_value: impl FnOnce(&mut Self) -> Result<T, Error>,
1315 assignment_context: &str,
1316 allow_deprecated_without_colon: bool,
1317 ) -> Result<(T, bool), Error> {
1318 if self.at(&TokenKind::Colon)? {
1319 self.next()?;
1320 let value = parse_value(self)?;
1321 return Ok((value, false));
1322 }
1323 if allow_deprecated_without_colon {
1324 let value = parse_value(self)?;
1325 return Ok((value, true));
1326 }
1327 let tok = self.peek()?.clone();
1328 Err(self.error_at_token_with_suggestion(
1329 &tok,
1330 format!("Expected `:` after `{assignment_context}` key."),
1331 format!("Use `-> {assignment_context} <key>: <value>`."),
1332 ))
1333 }
1334
1335 fn parse_unit_as_assignment(&mut self) -> Result<(Vec<CommandArg>, bool), Error> {
1336 if self.at_command_terminator()? {
1337 return Ok((Vec::new(), false));
1338 }
1339
1340 let peek_kind = self.peek()?.kind.clone();
1341 if is_keyword(&peek_kind) {
1342 let tok = self.peek()?.clone();
1343 return Err(self.error_at_token_with_suggestion(
1344 &tok,
1345 format!(
1346 "'{}' is a reserved keyword and cannot be used as a unit name",
1347 tok.text.to_ascii_lowercase()
1348 ),
1349 "Choose a different name that is not a reserved keyword",
1350 ));
1351 }
1352 if !can_be_label(&peek_kind) {
1353 return Ok((Vec::new(), false));
1354 }
1355
1356 let unit_name_tok = self.next()?;
1357 let unit_name_arg = CommandArg::Label(unit_name_tok.text.clone());
1358
1359 let (unit_arg, deprecated_without_colon) =
1360 self.parse_assignment_after_key(|parser| parser.parse_unit_payload(), "unit", true)?;
1361
1362 Ok((
1363 vec![unit_name_arg, CommandArg::UnitExpr(unit_arg)],
1364 deprecated_without_colon,
1365 ))
1366 }
1367
1368 fn parse_unit_payload(&mut self) -> Result<UnitArg, Error> {
1370 if self.at_command_terminator()? {
1371 let tok = self.peek()?.clone();
1372 return Err(self.error_at_token_with_suggestion(
1373 &tok,
1374 "Expected a unit conversion factor or compound unit expression after `:`.",
1375 "Use `-> unit <name>: <factor>` or `-> unit <name>: <compound>` (e.g. `unit eur: 1.00`, `unit eur_per_hour: eur/hour`).",
1376 ));
1377 }
1378
1379 let numeric_prefix: Option<Decimal> = if self.at(&TokenKind::NumberLit)? {
1380 let num_tok = self.next()?;
1381 Some(parse_decimal_string(&num_tok.text, &num_tok.span, self)?)
1382 } else {
1383 None
1384 };
1385
1386 let peek_kind_after_prefix = self.peek()?.kind.clone();
1387 let has_compound_expr =
1388 can_be_unit_name(&peek_kind_after_prefix) && !self.at_command_terminator()?;
1389
1390 if has_compound_expr {
1391 let factors = self.parse_unit_factors()?;
1392 let prefix = numeric_prefix.unwrap_or(Decimal::ONE);
1393 Ok(UnitArg::Expr(prefix, factors))
1394 } else if let Some(factor) = numeric_prefix {
1395 Ok(UnitArg::Factor(factor))
1396 } else {
1397 let tok = self.peek()?.clone();
1398 Err(self.error_at_token_with_suggestion(
1399 &tok,
1400 "Expected a unit conversion factor or compound unit expression after `:`.",
1401 "Use `-> unit <name>: <factor>` or `-> unit <name>: <compound>` (e.g. `unit eur: 1.00`, `unit eur_per_hour: eur/hour`).",
1402 ))
1403 }
1404 }
1405
1406 fn parse_single_command_arg(
1407 &mut self,
1408 cmd: TypeConstraintCommand,
1409 ) -> Result<Vec<CommandArg>, Error> {
1410 let Some(arg) = self.try_parse_one_command_arg()? else {
1411 return Ok(Vec::new());
1412 };
1413 if self.at(&TokenKind::Comma)? || self.command_arg_starts_without_comma()? {
1414 let tok = self.peek()?.clone();
1415 return Err(self.error_at_token_with_suggestion(
1416 &tok,
1417 format!("`-> {cmd}` takes one value"),
1418 format!("Write `-> {cmd}` with a single argument"),
1419 ));
1420 }
1421 Ok(vec![arg])
1422 }
1423
1424 fn try_parse_one_command_arg(&mut self) -> Result<Option<CommandArg>, Error> {
1425 if self.at(&TokenKind::Arrow)?
1426 || self.at(&TokenKind::Eof)?
1427 || is_spec_body_keyword(&self.peek()?.kind)
1428 || self.at(&TokenKind::Spec)?
1429 || self.at(&TokenKind::Comma)?
1430 {
1431 return Ok(None);
1432 }
1433
1434 let peek_kind = self.peek()?.kind.clone();
1435 match peek_kind {
1436 TokenKind::NumberLit | TokenKind::Minus | TokenKind::Plus | TokenKind::StringLit => {
1437 let value = self.parse_literal_value()?;
1438 Ok(Some(CommandArg::Literal(value)))
1439 }
1440 ref k if is_boolean_keyword(k) => {
1441 let value = self.parse_literal_value()?;
1442 Ok(Some(CommandArg::Literal(value)))
1443 }
1444 ref k if can_be_label(k) => {
1445 let tok = self.next()?;
1446 Ok(Some(CommandArg::Label(tok.text)))
1447 }
1448 _ => Ok(None),
1449 }
1450 }
1451
1452 fn parse_comma_separated_command_args(&mut self) -> Result<Vec<CommandArg>, Error> {
1453 let mut args = Vec::new();
1454 if self.at_command_terminator()? {
1455 return Ok(args);
1456 }
1457 if self.at(&TokenKind::Comma)? {
1458 let tok = self.next()?;
1459 return Err(self.error_at_token_with_suggestion(
1460 &tok,
1461 "Unexpected comma".to_string(),
1462 "Remove the extra comma, or put a value before it",
1463 ));
1464 }
1465
1466 loop {
1467 let Some(arg) = self.try_parse_one_command_arg()? else {
1468 let tok = self.peek()?.clone();
1469 return Err(self.error_at_token_with_suggestion(
1470 &tok,
1471 "Expected a value after comma".to_string(),
1472 "Remove the extra comma, or add the missing value",
1473 ));
1474 };
1475 args.push(arg);
1476
1477 if self.at(&TokenKind::Comma)? {
1478 self.next()?;
1479 if self.at_command_terminator()? || self.at(&TokenKind::Comma)? {
1480 let tok = self.peek()?.clone();
1481 return Err(self.error_at_token_with_suggestion(
1482 &tok,
1483 "Trailing or empty comma in list".to_string(),
1484 "Remove the extra comma, or add the missing value",
1485 ));
1486 }
1487 continue;
1488 }
1489
1490 if self.command_arg_starts_without_comma()? {
1491 let tok = self.peek()?.clone();
1492 return Err(self.error_at_token_with_suggestion(
1493 &tok,
1494 "Expected a comma between items".to_string(),
1495 "Separate items with commas, for example `-> options \"a\", \"b\"`",
1496 ));
1497 }
1498 break;
1499 }
1500 Ok(args)
1501 }
1502
1503 fn command_arg_starts_without_comma(&mut self) -> Result<bool, Error> {
1504 if self.at_command_terminator()? || self.at(&TokenKind::Comma)? {
1505 return Ok(false);
1506 }
1507 let peek_kind = self.peek()?.kind.clone();
1508 Ok(matches!(
1509 peek_kind,
1510 TokenKind::NumberLit | TokenKind::Minus | TokenKind::Plus | TokenKind::StringLit
1511 ) || is_boolean_keyword(&peek_kind)
1512 || can_be_label(&peek_kind))
1513 }
1514
1515 fn parse_scalar_literal_value(&mut self) -> Result<Value, Error> {
1516 self.parse_scalar_literal_value_with_context("value (number, text, boolean, date, etc.)")
1517 }
1518
1519 fn parse_scalar_literal_value_with_context(&mut self, expected: &str) -> Result<Value, Error> {
1520 let peeked = self.peek()?;
1521 match &peeked.kind {
1522 TokenKind::StringLit => {
1523 let tok = self.next()?;
1524 Ok(Value::Text(tok.text))
1525 }
1526 k if is_boolean_keyword(k) => {
1527 let tok = self.next()?;
1528 Ok(Value::Boolean(token_kind_to_boolean_value(&tok.kind)))
1529 }
1530 TokenKind::NumberLit => self.parse_number_literal(),
1531 TokenKind::Minus | TokenKind::Plus => self.parse_signed_number_literal(),
1532 _ => {
1533 let tok = self.next()?;
1534 Err(self
1535 .error_at_token(&tok, format!("Expected a {expected}, found '{}'", tok.text)))
1536 }
1537 }
1538 }
1539
1540 fn at_command_terminator(&mut self) -> Result<bool, Error> {
1542 if self.at(&TokenKind::Arrow)? || self.at(&TokenKind::Eof)? || self.at(&TokenKind::Spec)? {
1543 return Ok(true);
1544 }
1545 Ok(is_spec_body_keyword(&self.peek()?.kind))
1546 }
1547
1548 fn parse_unit_factors(&mut self) -> Result<Vec<UnitFactor>, Error> {
1565 let mut factors: Vec<UnitFactor> = Vec::new();
1566 let mut summed_exponents: std::collections::BTreeMap<String, i32> =
1567 std::collections::BTreeMap::new();
1568 let mut denominator_mode = false;
1569 let mut operator_just_consumed = true;
1573
1574 loop {
1575 if self.at_command_terminator()? {
1576 if !operator_just_consumed {
1577 break;
1578 }
1579 break;
1583 }
1584
1585 if self.at(&TokenKind::Star)? {
1587 if operator_just_consumed && !factors.is_empty() {
1588 let bad_tok = self.next()?;
1589 return Err(self.error_at_token(
1590 &bad_tok,
1591 "Unexpected '*' in unit expression: two consecutive operators".to_string(),
1592 ));
1593 }
1594 self.next()?;
1595 denominator_mode = false;
1596 operator_just_consumed = true;
1597 continue;
1598 }
1599
1600 if self.at(&TokenKind::Slash)? {
1602 if operator_just_consumed && !factors.is_empty() {
1603 let bad_tok = self.next()?;
1604 return Err(self.error_at_token(
1605 &bad_tok,
1606 "Unexpected '/' in unit expression: two consecutive operators".to_string(),
1607 ));
1608 }
1609 self.next()?;
1610 denominator_mode = true;
1611 operator_just_consumed = true;
1612 continue;
1613 }
1614
1615 let peek_kind = self.peek()?.kind.clone();
1617 if !can_be_unit_name(&peek_kind) {
1618 break;
1619 }
1620
1621 if !operator_just_consumed {
1624 break;
1625 }
1626 operator_just_consumed = false;
1627
1628 let (measure_ref, measure_span) = self.parse_unit_path()?;
1629
1630 let explicit_exp: Option<i32> = if self.at(&TokenKind::Caret)? {
1632 self.next()?; let negative = if self.at(&TokenKind::Minus)? {
1635 self.next()?; true
1637 } else {
1638 false
1639 };
1640
1641 if !self.at(&TokenKind::NumberLit)? {
1642 let bad_tok = self.next()?;
1643 return Err(self.error_at_token(
1644 &bad_tok,
1645 format!(
1646 "Expected an integer exponent after '^' in unit expression, found {}",
1647 bad_tok.kind
1648 ),
1649 ));
1650 }
1651
1652 let exp_tok = self.next()?;
1653 let raw: i32 = exp_tok.text.parse::<i32>().map_err(|_| {
1654 self.error_at_token(
1655 &exp_tok,
1656 format!(
1657 "Exponent '{}' is not a valid integer in unit expression",
1658 exp_tok.text
1659 ),
1660 )
1661 })?;
1662
1663 if raw == 0 {
1664 return Err(self.error_at_token(
1665 &exp_tok,
1666 "Exponent cannot be zero in a unit expression".to_string(),
1667 ));
1668 }
1669
1670 Some(if negative { -raw } else { raw })
1671 } else {
1672 None
1673 };
1674
1675 let final_exp = match (explicit_exp, denominator_mode) {
1677 (Some(exponent), true) => -exponent,
1678 (Some(exponent), false) => exponent,
1679 (None, true) => -1,
1680 (None, false) => 1,
1681 };
1682
1683 let summed = summed_exponents
1684 .entry(crate::parsing::ast::canonical_logical_name(&measure_ref).into_owned())
1685 .or_insert(0i32);
1686 *summed = summed
1687 .checked_add(final_exp)
1688 .filter(|sum| sum.unsigned_abs() <= crate::limits::MAX_UNIT_EXPONENT.unsigned_abs())
1689 .ok_or_else(|| {
1690 Error::parsing(
1691 format!(
1692 "Unit '{}' exceeds the maximum unit exponent of {} in this unit expression",
1693 measure_ref,
1694 crate::limits::MAX_UNIT_EXPONENT
1695 ),
1696 Source::new(self.source_type(), measure_span),
1697 None::<String>,
1698 )
1699 })?;
1700
1701 factors.push(UnitFactor {
1702 measure_ref,
1703 exp: final_exp,
1704 });
1705 }
1706
1707 Ok(factors)
1708 }
1709
1710 fn parse_meta(&mut self) -> Result<MetaField, Error> {
1715 let meta_tok = self.expect(&TokenKind::Meta)?;
1716 let start_span = meta_tok.span.clone();
1717
1718 let key_tok = self.next()?;
1719 let key = key_tok.text.clone();
1720
1721 self.expect(&TokenKind::Colon)?;
1722
1723 let value = self.parse_meta_literal_value()?;
1724
1725 let span = self.span_covering(&start_span, &self.last_span);
1726
1727 Ok(MetaField {
1728 key,
1729 value,
1730 source_location: self.make_source(span),
1731 })
1732 }
1733
1734 fn parse_meta_literal_value(&mut self) -> Result<Value, Error> {
1739 if self.at(&TokenKind::Ellipsis)? {
1740 let tok = self.peek()?.clone();
1741 return Err(self.error_at_token(&tok, "Expected a meta literal, found a range"));
1742 }
1743 self.parse_scalar_literal_value_with_context("meta literal")
1744 }
1745
1746 fn parse_literal_value(&mut self) -> Result<Value, Error> {
1747 let left = self.parse_scalar_literal_value()?;
1748 if self.at(&TokenKind::Ellipsis)? {
1749 self.next()?;
1750 let right = self.parse_scalar_literal_value()?;
1751 Ok(Value::Range(Box::new(left), Box::new(right)))
1752 } else {
1753 Ok(left)
1754 }
1755 }
1756
1757 fn parse_signed_number_literal(&mut self) -> Result<Value, Error> {
1758 let sign_tok = self.next()?;
1759 let sign_span = sign_tok.span.clone();
1760 let is_negative = sign_tok.kind == TokenKind::Minus;
1761
1762 if !self.at(&TokenKind::NumberLit)? {
1763 let tok = self.peek()?.clone();
1764 return Err(self.error_at_token(
1765 &tok,
1766 format!(
1767 "Expected a number after '{}', found '{}'",
1768 sign_tok.text, tok.text
1769 ),
1770 ));
1771 }
1772
1773 let value = self.parse_number_literal()?;
1774 if !is_negative {
1775 return Ok(value);
1776 }
1777 match try_negate_numeric_literal(value) {
1778 Ok(negated) => Ok(negated),
1779 Err(other) => Err(Error::parsing(
1780 format!("Cannot negate this value: {}", other),
1781 self.make_source(sign_span),
1782 None::<String>,
1783 )),
1784 }
1785 }
1786
1787 fn parse_number_literal(&mut self) -> Result<Value, Error> {
1788 let num_tok = self.next()?;
1789 let num_text = &num_tok.text;
1790 let num_span = num_tok.span.clone();
1791
1792 if self.at(&TokenKind::Comma)? {
1793 let comma = self.peek()?.clone();
1794 let next = self.lexer.peek_second()?.clone();
1795 let digits_grouped = next.kind == TokenKind::NumberLit
1796 && comma.span.start == num_span.end
1797 && next.span.start == comma.span.end;
1798 if digits_grouped {
1799 let grouped = format!("{}_{}", num_text, next.text);
1800 return Err(self.error_at_token_with_suggestion(
1801 &comma,
1802 format!(
1803 "`,` is a list separator, not a digit separator. Write `{grouped}` instead of `{num_text},{}`",
1804 next.text
1805 ),
1806 format!("Use `{grouped}`"),
1807 ));
1808 }
1809 }
1810
1811 if num_text.len() == 4
1813 && num_text.chars().all(|c| c.is_ascii_digit())
1814 && self.at(&TokenKind::Minus)?
1815 {
1816 return self.parse_date_literal(num_text.clone(), num_span);
1817 }
1818
1819 let peeked = self.peek()?;
1821
1822 if num_text.len() == 2
1824 && num_text.chars().all(|c| c.is_ascii_digit())
1825 && peeked.kind == TokenKind::Colon
1826 {
1827 return self.try_parse_time_literal(num_text.clone(), num_span);
1834 }
1835
1836 if peeked.kind == TokenKind::PercentPercent {
1838 let pp_tok = self.next()?;
1839 if let Ok(next_peek) = self.peek() {
1841 if next_peek.kind == TokenKind::NumberLit {
1842 return Err(self.error_at_token(
1843 &pp_tok,
1844 "Permille literal cannot be followed by a digit",
1845 ));
1846 }
1847 }
1848 let decimal = parse_decimal_string(num_text, &num_span, self)?;
1849 return Ok(Value::NumberWithUnit(decimal, "permille".to_string()));
1850 }
1851
1852 if peeked.kind == TokenKind::Percent {
1854 let pct_tok = self.next()?;
1855 if let Ok(next_peek) = self.peek() {
1857 if next_peek.kind == TokenKind::NumberLit || next_peek.kind == TokenKind::Percent {
1858 return Err(self.error_at_token(
1859 &pct_tok,
1860 "Percent literal cannot be followed by a digit",
1861 ));
1862 }
1863 }
1864 let decimal = parse_decimal_string(num_text, &num_span, self)?;
1865 return Ok(Value::NumberWithUnit(decimal, "percent".to_string()));
1866 }
1867
1868 if peeked.kind == TokenKind::Permille {
1870 self.next()?; let decimal = parse_decimal_string(num_text, &num_span, self)?;
1872 return Ok(Value::NumberWithUnit(decimal, "permille".to_string()));
1873 }
1874
1875 let starts_unit = can_be_unit_name(&peeked.kind);
1876 if starts_unit && !self.at_path_then_colon()? {
1877 let (unit_path, _) = self.parse_unit_path()?;
1878 let decimal = parse_decimal_string(num_text, &num_span, self)?;
1879 return Ok(Value::NumberWithUnit(decimal, unit_path));
1880 }
1881
1882 let decimal = parse_decimal_string(num_text, &num_span, self)?;
1884 Ok(Value::Number(decimal))
1885 }
1886
1887 fn parse_unit_path(&mut self) -> Result<(String, Span), Error> {
1889 let first = self.next()?;
1890 if !can_be_unit_name(&first.kind) {
1891 return Err(self.error_at_token(
1892 &first,
1893 format!("Expected a unit name, found {}", first.kind),
1894 ));
1895 }
1896 let mut path = first.text.clone();
1897 let mut end_span = first.span.clone();
1898 while self.at(&TokenKind::Dot)? {
1899 self.next()?;
1900 let seg = self.next()?;
1901 if !can_be_unit_name(&seg.kind) {
1902 return Err(self.error_at_token(
1903 &seg,
1904 format!("Expected a unit path segment after '.', found {}", seg.kind),
1905 ));
1906 }
1907 path.push('.');
1908 path.push_str(&seg.text);
1909 end_span = seg.span.clone();
1910 }
1911 Ok((path, end_span))
1912 }
1913
1914 fn parse_date_literal(&mut self, year_text: String, start_span: Span) -> Result<Value, Error> {
1915 let mut dt_str = year_text;
1916
1917 self.expect(&TokenKind::Minus)?;
1919 dt_str.push('-');
1920 let month_tok = self.expect(&TokenKind::NumberLit)?;
1921 dt_str.push_str(&month_tok.text);
1922
1923 self.expect(&TokenKind::Minus)?;
1925 dt_str.push('-');
1926 let day_tok = self.expect(&TokenKind::NumberLit)?;
1927 dt_str.push_str(&day_tok.text);
1928
1929 if self.at(&TokenKind::Identifier)? {
1931 let peeked = self.peek()?;
1932 if peeked.text.len() >= 2
1933 && (peeked.text.starts_with('T') || peeked.text.starts_with('t'))
1934 {
1935 let t_tok = self.next()?;
1937 dt_str.push_str(&t_tok.text);
1938
1939 if self.at(&TokenKind::Colon)? {
1941 self.next()?;
1942 dt_str.push(':');
1943 let min_tok = self.next()?;
1944 dt_str.push_str(&min_tok.text);
1945
1946 if self.at(&TokenKind::Colon)? {
1948 self.next()?;
1949 dt_str.push(':');
1950 let sec_tok = self.next()?;
1951 dt_str.push_str(&sec_tok.text);
1952
1953 if self.at(&TokenKind::Dot)? {
1955 self.next()?;
1956 dt_str.push('.');
1957 let frac_tok = self.expect(&TokenKind::NumberLit)?;
1958 dt_str.push_str(&frac_tok.text);
1959 }
1960 }
1961 }
1962
1963 self.try_consume_timezone(&mut dt_str)?;
1965 }
1966 }
1967
1968 if let Ok(dtv) = dt_str.parse::<crate::literals::DateTimeValue>() {
1969 return Ok(Value::Date(dtv));
1970 }
1971
1972 Err(Error::parsing(
1973 format!("Invalid date/time format: '{}'", dt_str),
1974 self.make_source(start_span),
1975 None::<String>,
1976 ))
1977 }
1978
1979 fn try_consume_timezone(&mut self, dt_str: &mut String) -> Result<(), Error> {
1980 if self.at(&TokenKind::Identifier)? {
1982 let peeked = self.peek()?;
1983 if (peeked.text == "Z" || peeked.text == "z") && peeked.span.start == self.last_span.end
1984 {
1985 let z_tok = self.next()?;
1986 dt_str.push_str(&z_tok.text);
1987 return Ok(());
1988 }
1989 }
1990
1991 if self.at(&TokenKind::Plus)? || self.at(&TokenKind::Minus)? {
1993 let mut lookahead = self.lexer.clone();
1994 let sign_tok = lookahead.next_token()?;
1995 let hour_tok = lookahead.next_token()?;
1996 let colon_tok = lookahead.next_token()?;
1997 let minute_tok = lookahead.next_token()?;
1998
1999 let attached = sign_tok.span.start == self.last_span.end;
2000 let is_timezone_shape = hour_tok.kind == TokenKind::NumberLit
2001 && colon_tok.kind == TokenKind::Colon
2002 && minute_tok.kind == TokenKind::NumberLit;
2003
2004 if attached && is_timezone_shape {
2005 let sign_tok = self.next()?;
2006 dt_str.push_str(&sign_tok.text);
2007 let hour_tok = self.expect(&TokenKind::NumberLit)?;
2008 dt_str.push_str(&hour_tok.text);
2009 self.expect(&TokenKind::Colon)?;
2010 dt_str.push(':');
2011 let min_tok = self.expect(&TokenKind::NumberLit)?;
2012 dt_str.push_str(&min_tok.text);
2013 }
2014 }
2015
2016 Ok(())
2017 }
2018
2019 fn try_parse_time_literal(
2020 &mut self,
2021 hour_text: String,
2022 start_span: Span,
2023 ) -> Result<Value, Error> {
2024 let mut time_str = hour_text;
2025
2026 self.expect(&TokenKind::Colon)?;
2028 time_str.push(':');
2029 let min_tok = self.expect(&TokenKind::NumberLit)?;
2030 time_str.push_str(&min_tok.text);
2031
2032 if self.at(&TokenKind::Colon)? {
2034 self.next()?;
2035 time_str.push(':');
2036 let sec_tok = self.expect(&TokenKind::NumberLit)?;
2037 time_str.push_str(&sec_tok.text);
2038
2039 if self.at(&TokenKind::Dot)? {
2041 self.next()?;
2042 time_str.push('.');
2043 let frac_tok = self.expect(&TokenKind::NumberLit)?;
2044 time_str.push_str(&frac_tok.text);
2045 }
2046 }
2047
2048 self.try_consume_timezone(&mut time_str)?;
2050
2051 if let Ok(t) = time_str.parse::<TimeValue>() {
2052 return Ok(Value::Time(TimeValue {
2053 hour: t.hour,
2054 minute: t.minute,
2055 second: t.second,
2056 microsecond: t.microsecond,
2057 timezone: t.timezone,
2058 }));
2059 }
2060
2061 Err(Error::parsing(
2062 format!("Invalid time format: '{}'", time_str),
2063 self.make_source(start_span),
2064 None::<String>,
2065 ))
2066 }
2067
2068 fn expr_span(&self, id: ExprId) -> Option<Span> {
2073 self.table.source(id).map(|source| source.span.clone())
2074 }
2075
2076 fn expr_source(&self, id: ExprId) -> Option<Source> {
2077 self.table.source(id).cloned()
2078 }
2079
2080 fn finish_expression(&mut self, root: ExprId) -> Expression {
2082 ExprTree::new(self.table.take_compact(), root)
2083 }
2084
2085 fn new_expression(&mut self, kind: ExpressionKind, source: Source) -> Result<ExprId, Error> {
2086 self.expression_count += 1;
2087 if self.expression_count > self.max_expression_count {
2088 return Err(Error::resource_limit_exceeded(
2089 "max_expression_count",
2090 self.max_expression_count.to_string(),
2091 self.expression_count.to_string(),
2092 "Split logic into multiple rules to reduce expression count",
2093 Some(source),
2094 None,
2095 None,
2096 ));
2097 }
2098 Ok(self.table.push(kind, Some(source)))
2099 }
2100
2101 fn check_depth(&mut self) -> Result<(), Error> {
2102 if let Err(actual) = self.depth_tracker.push_depth() {
2103 let span = self.peek()?.span.clone();
2104 self.depth_tracker.pop_depth();
2105 return Err(Error::resource_limit_exceeded(
2106 "max_expression_depth",
2107 self.depth_tracker.max_depth().to_string(),
2108 actual.to_string(),
2109 "Simplify nested expressions or break into separate rules",
2110 Some(self.make_source(span)),
2111 None,
2112 None,
2113 ));
2114 }
2115 Ok(())
2116 }
2117
2118 fn at_bare_veto_token(&mut self) -> Result<bool, Error> {
2119 if !self.at(&TokenKind::Veto)? {
2120 return Ok(false);
2121 }
2122 let checkpoint = self.checkpoint();
2123 self.next()?;
2124 let bare = !self.at(&TokenKind::StringLit)?;
2125 self.restore(checkpoint);
2126 Ok(bare)
2127 }
2128
2129 fn at_bare_veto_followed_by_is(&mut self) -> Result<bool, Error> {
2130 if !self.at_bare_veto_token()? {
2131 return Ok(false);
2132 }
2133 let checkpoint = self.checkpoint();
2134 self.next()?;
2135 let followed = self.at(&TokenKind::Is)?;
2136 self.restore(checkpoint);
2137 Ok(followed)
2138 }
2139
2140 fn at_not_bare_veto_followed_by_is(&mut self) -> Result<bool, Error> {
2141 if !self.at(&TokenKind::Not)? {
2142 return Ok(false);
2143 }
2144 let checkpoint = self.checkpoint();
2145 self.next()?;
2146 if !self.at(&TokenKind::Veto)? {
2147 self.restore(checkpoint);
2148 return Ok(false);
2149 }
2150 self.next()?;
2151 if self.at(&TokenKind::StringLit)? {
2152 self.restore(checkpoint);
2153 return Ok(false);
2154 }
2155 let followed = self.at(&TokenKind::Is)?;
2156 self.restore(checkpoint);
2157 Ok(followed)
2158 }
2159
2160 fn wrap_result_is_veto_expression(
2161 &mut self,
2162 operand: ExprId,
2163 operator_is_not: bool,
2164 keyword_was_negated: bool,
2165 start_span: Span,
2166 ) -> Result<ExprId, Error> {
2167 let negate = operator_is_not ^ keyword_was_negated;
2168 let end_span = self
2169 .expr_span(operand)
2170 .unwrap_or_else(|| start_span.clone());
2171 let span = self.span_covering(&start_span, &end_span);
2172 let core = self.new_expression(
2173 ExpressionKind::ResultIsVeto(operand),
2174 self.make_source(span.clone()),
2175 )?;
2176 if negate {
2177 self.new_expression(
2178 ExpressionKind::LogicalNegation(core, NegationType::Not),
2179 self.make_source(span),
2180 )
2181 } else {
2182 Ok(core)
2183 }
2184 }
2185
2186 fn next_is_list_type_suffix(&mut self) -> Result<bool, Error> {
2187 let checkpoint = self.checkpoint();
2188 self.next()?;
2189 let list_after_range = if self.at(&TokenKind::Identifier)? && self.peek()?.text == "range" {
2190 self.next()?;
2191 self.at(&TokenKind::List)?
2192 } else {
2193 self.at(&TokenKind::List)?
2194 };
2195 self.restore(checkpoint);
2196 Ok(list_after_range)
2197 }
2198
2199 fn wrap_list_type_suffix(&mut self, expr: ExprId, start_span: Span) -> Result<ExprId, Error> {
2200 if !self.at_list_type_suffix()? {
2201 return Ok(expr);
2202 }
2203 let ExpressionKind::Reference(reference) = self.table.kind(expr).clone() else {
2204 return Ok(expr);
2205 };
2206 let mut parent = parent_type_from_reference(&reference);
2207 if self.at(&TokenKind::Identifier)? && self.peek()?.text == "range" {
2208 self.next()?;
2209 parent = ParentType::Ranged {
2210 inner: Box::new(parent),
2211 };
2212 }
2213 self.expect(&TokenKind::List)?;
2214 parent = ParentType::List {
2215 inner: Box::new(parent),
2216 };
2217 let span = self.span_covering(&start_span, &self.last_span);
2218 self.new_expression(
2219 ExpressionKind::ListType { element: parent },
2220 self.make_source(span),
2221 )
2222 }
2223
2224 fn at_list_type_suffix(&mut self) -> Result<bool, Error> {
2225 if self.at(&TokenKind::List)? {
2226 return Ok(true);
2227 }
2228 if self.at(&TokenKind::Identifier)? && self.peek()?.text == "range" {
2229 let checkpoint = self.checkpoint();
2230 self.next()?;
2231 let list = self.at(&TokenKind::List)?;
2232 self.restore(checkpoint);
2233 return Ok(list);
2234 }
2235 Ok(false)
2236 }
2237
2238 fn parse_expression_parent_type(&mut self) -> Result<ParentType, Error> {
2239 let peek_kind = self.peek()?.kind.clone();
2240 let base = if let Some(primitive) = token_kind_to_primitive(&peek_kind) {
2241 self.next()?;
2242 ParentType::Primitive { primitive }
2243 } else {
2244 let (name, _) = self.parse_spec_name()?;
2245 if let Some((alias, type_name)) = name.rsplit_once('.') {
2246 ParentType::Qualified {
2247 spec_alias: alias.to_string(),
2248 inner: Box::new(ParentType::Custom {
2249 name: type_name.to_string(),
2250 }),
2251 }
2252 } else {
2253 ParentType::Custom { name }
2254 }
2255 };
2256 let base = if self.at(&TokenKind::Identifier)? && self.peek()?.text == "range" {
2257 self.next()?;
2258 ParentType::Ranged {
2259 inner: Box::new(base),
2260 }
2261 } else {
2262 base
2263 };
2264 self.expect(&TokenKind::List)?;
2265 Ok(ParentType::List {
2266 inner: Box::new(base),
2267 })
2268 }
2269
2270 fn at_bare_operand_start(&mut self) -> Result<bool, Error> {
2273 let kind = self.peek()?.kind.clone();
2274 if kind == TokenKind::Is {
2275 return Ok(false);
2276 }
2277 Ok(matches!(
2278 kind,
2279 TokenKind::NumberLit
2280 | TokenKind::StringLit
2281 | TokenKind::Now
2282 | TokenKind::Past
2283 | TokenKind::Future
2284 | TokenKind::Lower
2285 | TokenKind::Upper
2286 ) || is_boolean_keyword(&kind)
2287 || is_math_function(&kind)
2288 || can_be_label(&kind)
2289 || token_kind_to_primitive(&kind).is_some())
2290 }
2291
2292 fn at_command_argument_start(&mut self) -> Result<bool, Error> {
2293 Ok(self.at(&TokenKind::LParen)? || self.at_bare_operand_start()?)
2294 }
2295
2296 fn at_bare_argument_end(&mut self) -> Result<bool, Error> {
2298 Ok(self.at_any(&[
2299 TokenKind::Arrow,
2300 TokenKind::Then,
2301 TokenKind::Unless,
2302 TokenKind::RParen,
2303 TokenKind::Comma,
2304 TokenKind::Eof,
2305 TokenKind::Spec,
2306 TokenKind::Repo,
2307 TokenKind::Uses,
2308 ])? || is_spec_body_keyword(&self.peek()?.kind))
2309 }
2310
2311 fn bare_argument_error(&mut self, command: &str) -> Error {
2312 let tok = match self.peek() {
2313 Ok(tok) => tok.clone(),
2314 Err(error) => return error,
2315 };
2316 self.error_at_token(
2317 &tok,
2318 format!(
2319 "`{command}` without parentheses takes one operand, found '{}' after it; \
2320 write `{command}(...)` around the whole argument, or `(list -> {command} ...)` \
2321 to use the result",
2322 tok.text
2323 ),
2324 )
2325 }
2326
2327 fn reject_comma_after_call(&mut self, command: &str) -> Result<(), Error> {
2328 if self.call_argument_depth == 0 && self.at(&TokenKind::Comma)? {
2329 let tok = self.peek()?.clone();
2330 return Err(self.error_at_token(
2331 &tok,
2332 format!(
2333 "`,` after `{command}(...)`: put all arguments inside the parentheses, \
2334 `{command}(a, b)`"
2335 ),
2336 ));
2337 }
2338 Ok(())
2339 }
2340
2341 fn reject_command_argument(&mut self, command: &str) -> Result<(), Error> {
2342 if self.at_command_argument_start()? {
2343 let tok = self.peek()?.clone();
2344 return Err(self.error_at_token(&tok, format!("`{command}` takes no argument")));
2345 }
2346 Ok(())
2347 }
2348
2349 fn at_row_condition_operator(&mut self) -> Result<bool, Error> {
2350 Ok(is_comparison_operator(&self.peek()?.kind) || self.at(&TokenKind::In)?)
2351 }
2352
2353 fn parse_row_condition_operator(&mut self) -> Result<RowCondition, Error> {
2354 if self.at(&TokenKind::In)? {
2355 self.next()?;
2356 return Ok(RowCondition::In);
2357 }
2358 Ok(RowCondition::Compare(self.parse_comparison_operator()?))
2359 }
2360
2361 fn condition_error(&mut self, command: &str) -> Error {
2362 let tok = match self.peek() {
2363 Ok(tok) => tok.clone(),
2364 Err(error) => return error,
2365 };
2366 self.error_at_token(
2367 &tok,
2368 format!(
2369 "`{command}` condition without parentheses is one comparison between single \
2370 operands, found '{}'; write `{command}(...)` around the whole condition",
2371 tok.text
2372 ),
2373 )
2374 }
2375
2376 fn parse_sort_direction(&mut self) -> Result<bool, Error> {
2378 if self.at(&TokenKind::Desc)? {
2379 self.next()?;
2380 return Ok(true);
2381 }
2382 if self.at(&TokenKind::Asc)? {
2383 self.next()?;
2384 }
2385 Ok(false)
2386 }
2387
2388 fn parse_comparison_operator(&mut self) -> Result<ComparisonComputation, Error> {
2389 let tok = self.next()?;
2390 match tok.kind {
2391 TokenKind::Gt => Ok(ComparisonComputation::GreaterThan),
2392 TokenKind::Lt => Ok(ComparisonComputation::LessThan),
2393 TokenKind::Gte => Ok(ComparisonComputation::GreaterThanOrEqual),
2394 TokenKind::Lte => Ok(ComparisonComputation::LessThanOrEqual),
2395 TokenKind::Is => {
2396 if self.at(&TokenKind::Not)? {
2398 self.next()?; Ok(ComparisonComputation::IsNot)
2400 } else {
2401 Ok(ComparisonComputation::Is)
2402 }
2403 }
2404 _ => Err(self.error_at_token(
2405 &tok,
2406 format!("Expected a comparison operator, found {}", tok.kind),
2407 )),
2408 }
2409 }
2410
2411 fn parse_not_in_calendar_suffix(
2412 &mut self,
2413 repository: ExprId,
2414 start_span: Span,
2415 ) -> Result<ExprId, Error> {
2416 self.expect(&TokenKind::Not)?;
2417 self.expect(&TokenKind::In)?;
2418 self.expect_calendar_period_marker()?;
2419 let unit = self.parse_calendar_unit()?;
2420 let end = self.peek()?.span.clone();
2421 let span = self.span_covering(&start_span, &end);
2422 self.new_expression(
2423 ExpressionKind::DateCalendar(DateCalendarKind::NotIn, unit, repository),
2424 self.make_source(span),
2425 )
2426 }
2427
2428 fn parse_as_chain(&mut self, mut expr: ExprId, start_span: Span) -> Result<ExprId, Error> {
2429 while self.at(&TokenKind::As)? {
2430 self.expect(&TokenKind::As)?;
2431 let target_tok = self.next()?;
2432 let target = if matches!(target_tok.kind, TokenKind::Permille) {
2433 ConversionTarget::Unit {
2434 unit_name: "permille".to_string(),
2435 }
2436 } else if let Some(primitive) = token_kind_to_primitive(&target_tok.kind) {
2437 ConversionTarget::Type(primitive)
2438 } else if can_be_label(&target_tok.kind) {
2439 let mut unit_path = target_tok.text.clone();
2440 let mut end_span = target_tok.span.clone();
2441 while self.at(&TokenKind::Dot)? {
2442 self.next()?;
2443 let seg = self.next()?;
2444 if !can_be_label(&seg.kind) {
2445 return Err(self.error_at_token(
2446 &seg,
2447 format!("Expected a unit path segment after '.', found {}", seg.kind),
2448 ));
2449 }
2450 unit_path.push('.');
2451 unit_path.push_str(&seg.text);
2452 end_span = seg.span.clone();
2453 }
2454 let target = ConversionTarget::Unit {
2455 unit_name: unit_path,
2456 };
2457 expr = self.new_expression(
2458 ExpressionKind::UnitConversion(expr, target),
2459 self.make_source(self.span_covering(&start_span, &end_span)),
2460 )?;
2461 continue;
2462 } else {
2463 return Err(self.error_at_token(
2464 &target_tok,
2465 format!(
2466 "Expected a type keyword or unit name after 'as', found {}",
2467 target_tok.kind
2468 ),
2469 ));
2470 };
2471 expr = self.new_expression(
2472 ExpressionKind::UnitConversion(expr, target),
2473 self.make_source(self.span_covering(&start_span, &target_tok.span)),
2474 )?;
2475 }
2476 Ok(expr)
2477 }
2478
2479 fn is_plain_number_literal(&self, id: ExprId) -> bool {
2480 matches!(
2481 self.table.kind(id),
2482 ExpressionKind::Literal(Value::Number(_))
2483 )
2484 }
2485
2486 fn is_unit_conversion(&self, id: ExprId) -> bool {
2487 matches!(self.table.kind(id), ExpressionKind::UnitConversion(..))
2488 }
2489
2490 fn at_expression_suffix_end(&mut self) -> Result<bool, Error> {
2495 Ok(self.at(&TokenKind::And)?
2496 || self.at(&TokenKind::Unless)?
2497 || self.at(&TokenKind::Then)?
2498 || self.at(&TokenKind::RParen)?
2499 || self.at(&TokenKind::Eof)?
2500 || self.at(&TokenKind::Arrow)?
2501 || self.at(&TokenKind::Comma)?
2502 || self.at(&TokenKind::Spec)?
2503 || self.at(&TokenKind::Repo)?
2504 || self.at(&TokenKind::Uses)?
2505 || is_spec_body_keyword(&self.peek()?.kind))
2506 }
2507
2508 fn parse_calendar_unit(&mut self) -> Result<CalendarPeriodUnit, Error> {
2509 let tok = self.next()?;
2510 if let Some(unit) = CalendarPeriodUnit::from_keyword(&tok.text) {
2511 return Ok(unit);
2512 }
2513 Err(self.error_at_token(
2514 &tok,
2515 format!("Expected 'year', 'month', or 'week', found '{}'", tok.text),
2516 ))
2517 }
2518
2519 fn arithmetic_chain(
2525 &mut self,
2526 first: ExprId,
2527 steps: Vec<ChainStep<ArithmeticComputation>>,
2528 ) -> Result<ExprId, Error> {
2529 let source = match steps.last() {
2530 None => return Ok(first),
2531 Some(last) => last.source_location.clone(),
2532 };
2533 self.new_expression(ExpressionKind::Arithmetic { first, steps }, source)
2534 }
2535
2536 fn parse_number_expression(&mut self) -> Result<ExprId, Error> {
2537 let num_tok = self.next()?;
2538 let num_text = num_tok.text.clone();
2539 let start_span = num_tok.span.clone();
2540
2541 if num_text.len() == 4
2543 && num_text.chars().all(|c| c.is_ascii_digit())
2544 && self.at(&TokenKind::Minus)?
2545 {
2546 let minus_span = self.peek()?.span.clone();
2553 if minus_span.start == start_span.end {
2555 let value = self.parse_date_literal(num_text, start_span.clone())?;
2556 return self
2557 .new_expression(ExpressionKind::Literal(value), self.make_source(start_span));
2558 }
2559 }
2560
2561 if num_text.len() == 2
2563 && num_text.chars().all(|c| c.is_ascii_digit())
2564 && self.at(&TokenKind::Colon)?
2565 {
2566 let colon_span = self.peek()?.span.clone();
2567 if colon_span.start == start_span.end {
2568 let value = self.try_parse_time_literal(num_text, start_span.clone())?;
2569 return self
2570 .new_expression(ExpressionKind::Literal(value), self.make_source(start_span));
2571 }
2572 }
2573
2574 if self.at(&TokenKind::PercentPercent)? {
2576 let pp_tok = self.next()?;
2577 if let Ok(next_peek) = self.peek() {
2578 if next_peek.kind == TokenKind::NumberLit {
2579 return Err(self.error_at_token(
2580 &pp_tok,
2581 "Permille literal cannot be followed by a digit",
2582 ));
2583 }
2584 }
2585 let decimal = parse_decimal_string(&num_text, &start_span, self)?;
2586 return self.new_expression(
2587 ExpressionKind::Literal(Value::NumberWithUnit(decimal, "permille".to_string())),
2588 self.make_source(start_span),
2589 );
2590 }
2591
2592 if self.at(&TokenKind::Percent)? {
2594 let pct_span = self.peek()?.span.clone();
2595 let pct_tok = self.next()?;
2598 if let Ok(next_peek) = self.peek() {
2599 if next_peek.kind == TokenKind::NumberLit || next_peek.kind == TokenKind::Percent {
2600 return Err(self.error_at_token(
2601 &pct_tok,
2602 "Percent literal cannot be followed by a digit (use 'mod' for remainder)",
2603 ));
2604 }
2605 }
2606 let decimal = parse_decimal_string(&num_text, &start_span, self)?;
2607 return self.new_expression(
2608 ExpressionKind::Literal(Value::NumberWithUnit(decimal, "percent".to_string())),
2609 self.make_source(self.span_covering(&start_span, &pct_span)),
2610 );
2611 }
2612
2613 if self.at(&TokenKind::Permille)? {
2615 self.next()?;
2616 let decimal = parse_decimal_string(&num_text, &start_span, self)?;
2617 return self.new_expression(
2618 ExpressionKind::Literal(Value::NumberWithUnit(decimal, "permille".to_string())),
2619 self.make_source(start_span),
2620 );
2621 }
2622
2623 if can_be_unit_name(&self.peek()?.kind) {
2624 let (unit_path, end_span) = self.parse_unit_path()?;
2625 let decimal = parse_decimal_string(&num_text, &start_span, self)?;
2626 return self.new_expression(
2627 ExpressionKind::Literal(Value::NumberWithUnit(decimal, unit_path)),
2628 self.make_source(self.span_covering(&start_span, &end_span)),
2629 );
2630 }
2631
2632 let decimal = parse_decimal_string(&num_text, &start_span, self)?;
2634 self.new_expression(
2635 ExpressionKind::Literal(Value::Number(decimal)),
2636 self.make_source(start_span),
2637 )
2638 }
2639
2640 fn parse_expression_reference(&mut self) -> Result<Reference, Error> {
2641 let mut segments = Vec::new();
2642
2643 let first = self.next()?;
2644 segments.push(first.text.clone());
2645
2646 while self.at(&TokenKind::Dot)? {
2647 self.next()?; let seg = self.next()?;
2649 if !can_be_label(&seg.kind) {
2650 return Err(self.error_at_token(
2651 &seg,
2652 format!("Expected an identifier after '.', found {}", seg.kind),
2653 ));
2654 }
2655 segments.push(seg.text.clone());
2656 }
2657
2658 Ok(Reference::from_path(segments))
2659 }
2660 fn parse_expression(&mut self) -> Result<ExprId, Error> {
2661 Ok(expr_of(self.run_expression_machine(ExprTask::Expression)?))
2662 }
2663
2664 fn parse_list_command_body(&mut self, name_tok: Token) -> Result<ListCommand, Error> {
2665 Ok(command_of(self.run_expression_machine(
2666 ExprTask::ListCommandBody { name: name_tok },
2667 )?))
2668 }
2669
2670 fn save_flags(&self) -> ExprFlags {
2671 ExprFlags {
2672 bare_operand: self.bare_operand,
2673 call_argument_depth: self.call_argument_depth,
2674 }
2675 }
2676
2677 fn run_expression_machine(&mut self, root: ExprTask) -> Result<ExprVal, Error> {
2678 let mut frames = std::mem::take(&mut self.expr_frames);
2679 let result = self.drive_expression_machine(root, &mut frames);
2680 self.expr_frames = frames;
2681 result
2682 }
2683
2684 fn drive_expression_machine(
2685 &mut self,
2686 root: ExprTask,
2687 frames: &mut Vec<ExprCont>,
2688 ) -> Result<ExprVal, Error> {
2689 let mut step = ExprStep::Enter(root);
2690 loop {
2691 let next = match step {
2692 ExprStep::Enter(task) => self.enter_expression(task, frames),
2693 ExprStep::Yield(value) => match frames.pop() {
2694 None => return Ok(value),
2695 Some(cont) => self.resume_expression(cont, value, frames),
2696 },
2697 };
2698 match next {
2699 Ok(next_step) => step = next_step,
2700 Err(error) => {
2701 self.unwind_expression(frames);
2702 return Err(error);
2703 }
2704 }
2705 }
2706 }
2707
2708 fn unwind_expression(&mut self, frames: &mut Vec<ExprCont>) {
2709 while let Some(cont) = frames.pop() {
2710 match cont {
2711 ExprCont::Restore(flags) => {
2712 self.bare_operand = flags.bare_operand;
2713 self.call_argument_depth = flags.call_argument_depth;
2714 }
2715 ExprCont::PopDepth => self.depth_tracker.pop_depth(),
2716 _ => {}
2717 }
2718 }
2719 }
2720
2721 fn enter_expression(
2722 &mut self,
2723 task: ExprTask,
2724 frames: &mut Vec<ExprCont>,
2725 ) -> Result<ExprStep, Error> {
2726 match task {
2727 ExprTask::Expression => {
2728 self.check_depth()?;
2729 frames.push(ExprCont::PopDepth);
2730 Ok(ExprStep::Enter(ExprTask::AndExpression))
2731 }
2732 ExprTask::AndExpression => {
2733 let start_span = self.peek()?.span.clone();
2734 frames.push(ExprCont::AndFirst { start_span });
2735 Ok(ExprStep::Enter(ExprTask::AndOperand))
2736 }
2737 ExprTask::AndOperand => {
2738 if self.at_not_bare_veto_followed_by_is()? || self.at_bare_veto_followed_by_is()? {
2739 Ok(ExprStep::Enter(ExprTask::VetoStatus))
2740 } else if self.at(&TokenKind::Not)? {
2741 Ok(ExprStep::Enter(ExprTask::NotExpression))
2742 } else {
2743 Ok(ExprStep::Enter(ExprTask::RepositoryWithSuffix))
2744 }
2745 }
2746 ExprTask::VetoStatus => {
2747 let start_span = self.peek()?.span.clone();
2748 let keyword_was_negated = if self.at(&TokenKind::Not)? {
2749 self.next()?;
2750 true
2751 } else {
2752 false
2753 };
2754 self.expect(&TokenKind::Veto)?;
2755 if self.at(&TokenKind::StringLit)? {
2756 let tok = self.peek()?.clone();
2757 return Err(self.error_at_token(
2758 &tok,
2759 "veto with a message is only valid as a rule or unless result, not in `is veto` comparisons",
2760 ));
2761 }
2762 let operator = self.parse_comparison_operator()?;
2763 let operator_is_not = matches!(operator, ComparisonComputation::IsNot);
2764 if !matches!(
2765 operator,
2766 ComparisonComputation::Is | ComparisonComputation::IsNot
2767 ) {
2768 let tok = self.peek()?.clone();
2769 return Err(self.error_at_token(
2770 &tok,
2771 "Expected `is` or `is not` after `veto` in a veto-status comparison",
2772 ));
2773 }
2774 frames.push(ExprCont::VetoStatus {
2775 operator_is_not,
2776 keyword_was_negated,
2777 start_span,
2778 });
2779 Ok(ExprStep::Enter(ExprTask::RepositoryExpression))
2780 }
2781 ExprTask::NotExpression => {
2782 let not_tok = self.expect(&TokenKind::Not)?;
2783 frames.push(ExprCont::Negation {
2784 start_span: not_tok.span,
2785 });
2786 Ok(ExprStep::Enter(ExprTask::PrefixArgument {
2787 keyword: "not".to_string(),
2788 }))
2789 }
2790 ExprTask::RepositoryWithSuffix => {
2791 let start_span = self.peek()?.span.clone();
2792 frames.push(ExprCont::RepositorySuffix { start_span });
2793 Ok(ExprStep::Enter(ExprTask::RepositoryExpression))
2794 }
2795 ExprTask::ComparisonSuffix { left, start_span } => {
2796 self.enter_comparison_suffix(left, start_span, frames)
2797 }
2798 ExprTask::InSuffix {
2799 repository,
2800 start_span,
2801 } => self.enter_in_suffix(repository, start_span, frames),
2802 ExprTask::RepositoryExpression => {
2803 let start_span = self.peek()?.span.clone();
2804 frames.push(ExprCont::RepositoryFirst { start_span });
2805 Ok(ExprStep::Enter(ExprTask::Term { allow_as: true }))
2806 }
2807 ExprTask::Term { allow_as } => {
2808 let start_span = self.peek()?.span.clone();
2809 frames.push(ExprCont::TermFirst {
2810 allow_as,
2811 start_span,
2812 });
2813 Ok(ExprStep::Enter(ExprTask::Power))
2814 }
2815 ExprTask::Power => {
2816 let start_span = self.peek()?.span.clone();
2817 frames.push(ExprCont::PowerLeft {
2818 start_span,
2819 range_bound: false,
2820 });
2821 Ok(ExprStep::Enter(ExprTask::RangeOperand))
2822 }
2823 ExprTask::RangeOperand => {
2824 let start_span = self.peek()?.span.clone();
2825 let flags = self.save_flags();
2826 if self.no_range_at.get(&start_span.start) == Some(&flags) {
2827 return Ok(ExprStep::Enter(ExprTask::Factor));
2828 }
2829 frames.push(ExprCont::RangeFactor { start_span, flags });
2830 Ok(ExprStep::Enter(ExprTask::Factor))
2831 }
2832 ExprTask::RangeEllipsisBound => {
2833 let start_span = self.peek()?.span.clone();
2834 frames.push(ExprCont::EllipsisFirst { start_span });
2835 Ok(ExprStep::Enter(ExprTask::PowerForRangeBound))
2836 }
2837 ExprTask::PowerForRangeBound => {
2838 let start_span = self.peek()?.span.clone();
2839 frames.push(ExprCont::PowerLeft {
2840 start_span,
2841 range_bound: true,
2842 });
2843 Ok(ExprStep::Enter(ExprTask::Factor))
2844 }
2845 ExprTask::Factor => {
2846 let peeked = self.peek()?;
2847 let start_span = peeked.span.clone();
2848 let kind = peeked.kind.clone();
2849 if kind == TokenKind::Minus {
2850 self.next()?;
2851 frames.push(ExprCont::FactorNegate { start_span });
2852 return Ok(ExprStep::Enter(ExprTask::PrimaryOrMath));
2853 }
2854 if kind == TokenKind::Plus {
2855 self.next()?;
2856 }
2857 Ok(ExprStep::Enter(ExprTask::PrimaryOrMath))
2858 }
2859 ExprTask::PrimaryOrMath => {
2860 let peeked = self.peek()?;
2861 let start_span = peeked.span.clone();
2862 let kind = peeked.kind.clone();
2863 frames.push(ExprCont::PrimaryOrMathSuffix { start_span });
2864 if is_math_function(&kind) {
2865 return Ok(ExprStep::Enter(ExprTask::MathFunction));
2866 }
2867 if matches!(kind, TokenKind::Lower | TokenKind::Upper) {
2868 return Ok(ExprStep::Enter(ExprTask::LowerUpper));
2869 }
2870 Ok(ExprStep::Enter(ExprTask::Primary))
2871 }
2872 ExprTask::MathFunction => {
2873 let func_tok = self.next()?;
2874 let start_span = func_tok.span.clone();
2875 let operator = match func_tok.kind {
2876 TokenKind::Sqrt => MathematicalComputation::Sqrt,
2877 TokenKind::Sin => MathematicalComputation::Sin,
2878 TokenKind::Cos => MathematicalComputation::Cos,
2879 TokenKind::Tan => MathematicalComputation::Tan,
2880 TokenKind::Asin => MathematicalComputation::Asin,
2881 TokenKind::Acos => MathematicalComputation::Acos,
2882 TokenKind::Atan => MathematicalComputation::Atan,
2883 TokenKind::Log => MathematicalComputation::Log,
2884 TokenKind::Exp => MathematicalComputation::Exp,
2885 TokenKind::Abs => MathematicalComputation::Abs,
2886 TokenKind::Floor => MathematicalComputation::Floor,
2887 TokenKind::Ceil => MathematicalComputation::Ceil,
2888 TokenKind::Round => MathematicalComputation::Round,
2889 _ => unreachable!("BUG: only math functions should reach here"),
2890 };
2891 frames.push(ExprCont::Math {
2892 operator,
2893 start_span,
2894 });
2895 Ok(ExprStep::Enter(ExprTask::PrefixArgument {
2896 keyword: func_tok.text,
2897 }))
2898 }
2899 ExprTask::LowerUpper => {
2900 let bound_tok = self.next()?;
2901 let start_span = bound_tok.span.clone();
2902 let bound = match bound_tok.kind {
2903 TokenKind::Lower => RangeBound::Lower,
2904 TokenKind::Upper => RangeBound::Upper,
2905 _ => unreachable!("BUG: only lower and upper should reach parse_range_bound"),
2906 };
2907 frames.push(ExprCont::LowerUpperEnd { bound, start_span });
2908 Ok(ExprStep::Enter(ExprTask::PrefixArgument {
2909 keyword: bound_tok.text,
2910 }))
2911 }
2912 ExprTask::PrefixArgument { keyword } => self.enter_prefix_argument(keyword, frames),
2913 ExprTask::Primary => self.enter_primary(frames),
2914 ExprTask::ListCommandSuffix { list, start_span } => {
2915 self.expect(&TokenKind::Arrow)?;
2916 let name = self.next()?;
2917 frames.push(ExprCont::ListCommandDone { list, start_span });
2918 Ok(ExprStep::Enter(ExprTask::ListCommandBody { name }))
2919 }
2920 ExprTask::ListCommandBody { name } => self.enter_list_command_body(name, frames),
2921 ExprTask::FindKeys => {
2922 if self.at(&TokenKind::LParen)? {
2923 return Ok(ExprStep::Enter(ExprTask::CallArguments { command: "find" }));
2924 }
2925 if !self.at_bare_operand_start()? {
2926 let tok = self.peek()?.clone();
2927 return Err(self.error_at_token(&tok, "`find` needs a key"));
2928 }
2929 frames.push(ExprCont::FindKey { keys: Vec::new() });
2930 Ok(ExprStep::Enter(ExprTask::BareArgument { command: "find" }))
2931 }
2932 ExprTask::CallArguments { command } => {
2933 self.expect(&TokenKind::LParen)?;
2934 let saved = self.save_flags();
2935 self.bare_operand = false;
2936 self.call_argument_depth += 1;
2937 frames.push(ExprCont::CallArgumentsEnd { command });
2938 frames.push(ExprCont::Restore(saved));
2939 frames.push(ExprCont::CallArgumentItems {
2940 arguments: Vec::new(),
2941 });
2942 Ok(ExprStep::Enter(ExprTask::Expression))
2943 }
2944 ExprTask::SingleCallArgument { command } => {
2945 frames.push(ExprCont::SingleCallArgumentCheck { command });
2946 Ok(ExprStep::Enter(ExprTask::CallArguments { command }))
2947 }
2948 ExprTask::OptionalArgument { command } => {
2949 if self.at(&TokenKind::LParen)? {
2950 frames.push(ExprCont::WrapSome);
2951 return Ok(ExprStep::Enter(ExprTask::SingleCallArgument { command }));
2952 }
2953 if self.at_bare_operand_start()? {
2954 frames.push(ExprCont::WrapSome);
2955 return Ok(ExprStep::Enter(ExprTask::BareArgument { command }));
2956 }
2957 Ok(ExprStep::Yield(ExprVal::Optional(None)))
2958 }
2959 ExprTask::RequiredArgument { command } => {
2960 if self.at(&TokenKind::LParen)? {
2961 return Ok(ExprStep::Enter(ExprTask::SingleCallArgument { command }));
2962 }
2963 if self.at_bare_operand_start()? {
2964 return Ok(ExprStep::Enter(ExprTask::BareArgument { command }));
2965 }
2966 let tok = self.peek()?.clone();
2967 Err(self.error_at_token(&tok, format!("`{command}` needs an argument")))
2968 }
2969 ExprTask::BareArgument { command } => {
2970 frames.push(ExprCont::BareArgumentEnd { command });
2971 Ok(ExprStep::Enter(ExprTask::BareOperand))
2972 }
2973 ExprTask::BareOperand => {
2974 let saved = self.save_flags();
2975 self.bare_operand = true;
2976 frames.push(ExprCont::Restore(saved));
2977 Ok(ExprStep::Enter(ExprTask::RangeOperand))
2978 }
2979 ExprTask::ListPredicate { command } => self.enter_list_predicate(command, frames),
2980 ExprTask::CallListPredicate { command } => {
2981 let checkpoint = self.checkpoint();
2982 self.expect(&TokenKind::LParen)?;
2983 if !self.at_row_condition_operator()? {
2984 self.restore(checkpoint);
2985 frames.push(ExprCont::WrapInstance);
2986 return Ok(ExprStep::Enter(ExprTask::SingleCallArgument { command }));
2987 }
2988 let saved = self.save_flags();
2989 self.bare_operand = false;
2990 frames.push(ExprCont::CallPredicateEnd { command });
2991 frames.push(ExprCont::Restore(saved));
2992 Ok(ExprStep::Enter(ExprTask::ValuePredicateInParentheses {
2993 command,
2994 }))
2995 }
2996 ExprTask::ValuePredicateInParentheses { command } => {
2997 let op = self.parse_row_condition_operator()?;
2998 frames.push(ExprCont::ValuePredicateEnd { op, command });
2999 Ok(ExprStep::Enter(ExprTask::RepositoryExpression))
3000 }
3001 ExprTask::SortCommand => {
3002 if self.at(&TokenKind::LParen)? {
3003 frames.push(ExprCont::SortArgument { check_bare: false });
3004 return Ok(ExprStep::Enter(ExprTask::SingleCallArgument {
3005 command: "sort",
3006 }));
3007 }
3008 if self.at_bare_operand_start()? {
3009 frames.push(ExprCont::SortArgument { check_bare: true });
3010 return Ok(ExprStep::Enter(ExprTask::BareOperand));
3011 }
3012 let descending = self.parse_sort_direction()?;
3013 Ok(ExprStep::Yield(ExprVal::Command(ListCommand::Sort {
3014 descending,
3015 argument: None,
3016 })))
3017 }
3018 ExprTask::ListWithCommand => {
3019 if !self.at(&TokenKind::LParen)? {
3020 return Ok(ExprStep::Enter(ExprTask::ListWithRows));
3021 }
3022 self.next()?;
3023 let saved = self.save_flags();
3024 self.call_argument_depth += 1;
3025 frames.push(ExprCont::ListWithEnd);
3026 frames.push(ExprCont::Restore(saved));
3027 Ok(ExprStep::Enter(ExprTask::ListWithRows))
3028 }
3029 ExprTask::ListWithRows => {
3030 if self.at_path_then_colon()? {
3031 return self.enter_pair_field(Vec::new(), frames);
3032 }
3033 frames.push(ExprCont::ValueItem { values: Vec::new() });
3034 Ok(ExprStep::Enter(ExprTask::BareArgument { command: "with" }))
3035 }
3036 }
3037 }
3038
3039 fn resume_expression(
3040 &mut self,
3041 cont: ExprCont,
3042 value: ExprVal,
3043 frames: &mut Vec<ExprCont>,
3044 ) -> Result<ExprStep, Error> {
3045 match cont {
3046 ExprCont::Restore(flags) => {
3047 self.bare_operand = flags.bare_operand;
3048 self.call_argument_depth = flags.call_argument_depth;
3049 Ok(ExprStep::Yield(value))
3050 }
3051 ExprCont::PopDepth => {
3052 self.depth_tracker.pop_depth();
3053 Ok(ExprStep::Yield(value))
3054 }
3055 ExprCont::AndFirst { start_span } => {
3056 self.and_chain(expr_of(value), Vec::new(), start_span, frames)
3057 }
3058 ExprCont::AndOperand {
3059 first,
3060 mut steps,
3061 start_span,
3062 } => {
3063 let operand = expr_of(value);
3064 let end_span = self
3065 .expr_span(operand)
3066 .unwrap_or_else(|| start_span.clone());
3067 let span = self.span_covering(&start_span, &end_span);
3068 steps.push(ChainStep {
3069 op: (),
3070 operand,
3071 source_location: self.make_source(span),
3072 });
3073 self.and_chain(first, steps, start_span, frames)
3074 }
3075 ExprCont::VetoStatus {
3076 operator_is_not,
3077 keyword_was_negated,
3078 start_span,
3079 } => expr_step(self.wrap_result_is_veto_expression(
3080 expr_of(value),
3081 operator_is_not,
3082 keyword_was_negated,
3083 start_span,
3084 )),
3085 ExprCont::Negation { start_span } => {
3086 let operand = expr_of(value);
3087 let end_span = self
3088 .expr_span(operand)
3089 .unwrap_or_else(|| start_span.clone());
3090 let span = self.span_covering(&start_span, &end_span);
3091 expr_step(self.new_expression(
3092 ExpressionKind::LogicalNegation(operand, NegationType::Not),
3093 self.make_source(span),
3094 ))
3095 }
3096 ExprCont::RepositorySuffix { start_span } => {
3097 self.continue_repository(expr_of(value), start_span, frames)
3098 }
3099 ExprCont::ContinueRepository { start_span } => {
3100 self.continue_repository(expr_of(value), start_span, frames)
3101 }
3102 ExprCont::ComparisonRight {
3103 left,
3104 operator,
3105 start_span,
3106 } => {
3107 let right = expr_of(value);
3108 let end_span = self.expr_span(right).unwrap_or_else(|| start_span.clone());
3109 let span = self.span_covering(&start_span, &end_span);
3110 expr_step(self.new_expression(
3111 ExpressionKind::Comparison(left, operator, right),
3112 self.make_source(span),
3113 ))
3114 }
3115 ExprCont::InOffset {
3116 direction,
3117 rel_kind,
3118 repository,
3119 start_span,
3120 } => {
3121 let offset = expr_of(value);
3122 let offset_end_span = self.expr_span(offset).unwrap_or_else(|| start_span.clone());
3123 let range = self.new_expression(
3124 ExpressionKind::PastFutureRange(rel_kind, offset),
3125 self.make_source(self.span_covering(&direction, &offset_end_span)),
3126 )?;
3127 let span = self.span_covering(&start_span, &offset_end_span);
3128 expr_step(self.new_expression(
3129 ExpressionKind::RangeContainment(repository, range),
3130 self.make_source(span),
3131 ))
3132 }
3133 ExprCont::InRange {
3134 repository,
3135 start_span,
3136 } => {
3137 let range = expr_of(value);
3138 let end_span = self.expr_span(range).unwrap_or_else(|| start_span.clone());
3139 let span = self.span_covering(&start_span, &end_span);
3140 expr_step(self.new_expression(
3141 ExpressionKind::RangeContainment(repository, range),
3142 self.make_source(span),
3143 ))
3144 }
3145 ExprCont::RepositoryFirst { start_span } => {
3146 self.repository_chain(expr_of(value), Vec::new(), start_span, frames)
3147 }
3148 ExprCont::RepositoryOperand {
3149 first,
3150 mut steps,
3151 start_span,
3152 operation,
3153 } => {
3154 let operand = expr_of(value);
3155 if steps.is_empty()
3156 && self.is_plain_number_literal(first)
3157 && self.is_unit_conversion(operand)
3158 {
3159 let source = self
3160 .expr_source(operand)
3161 .unwrap_or_else(|| self.make_source(start_span.clone()));
3162 return Err(Error::parsing(
3163 "Cannot add a plain number to a converted value; convert each operand before \
3164 '+' (e.g. '5 as usd + c as usd')",
3165 source,
3166 None::<String>,
3167 ));
3168 }
3169 let end_span = self
3170 .expr_span(operand)
3171 .unwrap_or_else(|| start_span.clone());
3172 let span = self.span_covering(&start_span, &end_span);
3173 steps.push(ChainStep {
3174 op: operation,
3175 operand,
3176 source_location: self.make_source(span),
3177 });
3178 self.repository_chain(first, steps, start_span, frames)
3179 }
3180 ExprCont::TermFirst {
3181 allow_as,
3182 start_span,
3183 } => {
3184 let mut first = expr_of(value);
3185 if allow_as {
3186 first = self.parse_as_chain(first, start_span.clone())?;
3187 }
3188 self.term_chain(first, Vec::new(), allow_as, start_span, frames)
3189 }
3190 ExprCont::TermOperand {
3191 first,
3192 mut steps,
3193 allow_as,
3194 start_span,
3195 operation,
3196 right_start_span,
3197 } => {
3198 let mut operand = expr_of(value);
3199 if allow_as {
3200 operand = self.parse_as_chain(operand, right_start_span)?;
3201 }
3202 let end_span = self
3203 .expr_span(operand)
3204 .unwrap_or_else(|| start_span.clone());
3205 let span = self.span_covering(&start_span, &end_span);
3206 steps.push(ChainStep {
3207 op: operation,
3208 operand,
3209 source_location: self.make_source(span),
3210 });
3211 self.term_chain(first, steps, allow_as, start_span, frames)
3212 }
3213 ExprCont::PowerLeft {
3214 start_span,
3215 range_bound,
3216 } => self.power_tail(expr_of(value), start_span, range_bound, frames),
3217 ExprCont::PowerRight { left, start_span } => {
3218 let right = expr_of(value);
3219 let end_span = self.expr_span(right).unwrap_or_else(|| start_span.clone());
3220 let span = self.span_covering(&start_span, &end_span);
3221 let step = ChainStep {
3222 op: ArithmeticComputation::Power,
3223 operand: right,
3224 source_location: self.make_source(span),
3225 };
3226 expr_step(self.arithmetic_chain(left, vec![step]))
3227 }
3228 ExprCont::RangeFactor { start_span, flags } => {
3229 let factor = expr_of(value);
3230 if self.at(&TokenKind::Ellipsis)? {
3231 self.next()?;
3232 frames.push(ExprCont::RangeRight {
3233 left: factor,
3234 start_span,
3235 });
3236 return Ok(ExprStep::Enter(ExprTask::RangeEllipsisBound));
3237 }
3238 if !self.at_any(&[TokenKind::Caret, TokenKind::Plus, TokenKind::Minus])? {
3239 return Ok(ExprStep::Yield(ExprVal::Expr(factor)));
3240 }
3241 frames.push(ExprCont::RangeLeft {
3242 factor,
3243 start_span: start_span.clone(),
3244 checkpoint: Box::new(self.checkpoint()),
3245 flags,
3246 });
3247 frames.push(ExprCont::EllipsisFirst {
3248 start_span: start_span.clone(),
3249 });
3250 self.power_tail(factor, start_span, true, frames)
3251 }
3252 ExprCont::RangeLeft {
3253 factor,
3254 start_span,
3255 checkpoint,
3256 flags,
3257 } => {
3258 let left = expr_of(value);
3259 let starts = std::mem::take(&mut self.bound_chain_starts);
3260 if !self.at(&TokenKind::Ellipsis)? {
3261 for start in starts {
3262 self.no_range_at.insert(start, flags);
3263 }
3264 self.restore(*checkpoint);
3265 return Ok(ExprStep::Yield(ExprVal::Expr(factor)));
3266 }
3267 self.next()?;
3268 frames.push(ExprCont::RangeRight { left, start_span });
3269 Ok(ExprStep::Enter(ExprTask::RangeEllipsisBound))
3270 }
3271 ExprCont::RangeRight { left, start_span } => {
3272 let right = expr_of(value);
3273 let end_span = self.expr_span(right).unwrap_or_else(|| start_span.clone());
3274 let span = self.span_covering(&start_span, &end_span);
3275 expr_step(self.new_expression(
3276 ExpressionKind::RangeLiteral(left, right),
3277 self.make_source(span),
3278 ))
3279 }
3280 ExprCont::EllipsisFirst { start_span } => {
3281 let starts = vec![start_span.start];
3282 self.ellipsis_chain(expr_of(value), Vec::new(), start_span, starts, frames)
3283 }
3284 ExprCont::EllipsisOperand {
3285 first,
3286 mut steps,
3287 start_span,
3288 operation,
3289 starts,
3290 } => {
3291 let operand = expr_of(value);
3292 let end_span = self
3293 .expr_span(operand)
3294 .unwrap_or_else(|| start_span.clone());
3295 let span = self.span_covering(&start_span, &end_span);
3296 steps.push(ChainStep {
3297 op: operation,
3298 operand,
3299 source_location: self.make_source(span),
3300 });
3301 self.ellipsis_chain(first, steps, start_span, starts, frames)
3302 }
3303 ExprCont::FactorNegate { start_span } => {
3304 let operand = expr_of(value);
3305 let end_span = self
3306 .expr_span(operand)
3307 .unwrap_or_else(|| start_span.clone());
3308 let span = self.span_covering(&start_span, &end_span);
3309 if let ExpressionKind::Literal(literal) = self.table.kind(operand) {
3310 if let Ok(negated) = try_negate_numeric_literal(literal.clone()) {
3311 return expr_step(self.new_expression(
3312 ExpressionKind::Literal(negated),
3313 self.make_source(span),
3314 ));
3315 }
3316 }
3317 let zero = self.new_expression(
3318 ExpressionKind::Literal(Value::Number(Decimal::ZERO)),
3319 self.make_source(start_span),
3320 )?;
3321 let step = ChainStep {
3322 op: ArithmeticComputation::Subtract,
3323 operand,
3324 source_location: self.make_source(span),
3325 };
3326 expr_step(self.arithmetic_chain(zero, vec![step]))
3327 }
3328 ExprCont::PrimaryOrMathSuffix { start_span } => {
3329 let expr = expr_of(value);
3330 if !self.bare_operand && self.at(&TokenKind::Arrow)? {
3331 frames.push(ExprCont::PrimaryOrMathSuffix {
3332 start_span: start_span.clone(),
3333 });
3334 return Ok(ExprStep::Enter(ExprTask::ListCommandSuffix {
3335 list: expr,
3336 start_span,
3337 }));
3338 }
3339 Ok(ExprStep::Yield(ExprVal::Expr(expr)))
3340 }
3341 ExprCont::ListCommandDone { list, start_span } => {
3342 let command = command_of(value);
3343 let span = self.span_covering(&start_span, &self.last_span);
3344 expr_step(self.new_expression(
3345 ExpressionKind::ListCommand { list, command },
3346 self.make_source(span),
3347 ))
3348 }
3349 ExprCont::Command(builder) => Ok(ExprStep::Yield(ExprVal::Command(build_command(
3350 builder, value,
3351 )))),
3352 ExprCont::FindKey { mut keys } => {
3353 keys.push(expr_of(value));
3354 self.find_key_next(keys, frames)
3355 }
3356 ExprCont::CallArgumentsEnd { command } => {
3357 self.expect(&TokenKind::RParen)?;
3358 self.reject_comma_after_call(command)?;
3359 Ok(ExprStep::Yield(value))
3360 }
3361 ExprCont::CallArgumentItems { mut arguments } => {
3362 arguments.push(expr_of(value));
3363 self.call_argument_items(arguments, frames)
3364 }
3365 ExprCont::SingleCallArgumentCheck { command } => {
3366 let mut arguments = exprs_of(value);
3367 if arguments.len() != 1 {
3368 let tok = self.peek()?.clone();
3369 return Err(self.error_at_token(
3370 &tok,
3371 format!("`{command}` takes one argument, got {}", arguments.len()),
3372 ));
3373 }
3374 Ok(ExprStep::Yield(ExprVal::Expr(arguments.remove(0))))
3375 }
3376 ExprCont::WrapSome => Ok(ExprStep::Yield(ExprVal::Optional(Some(expr_of(value))))),
3377 ExprCont::BareArgumentEnd { command } => {
3378 let argument = expr_of(value);
3379 if !self.at_bare_argument_end()? {
3380 return Err(self.bare_argument_error(command));
3381 }
3382 Ok(ExprStep::Yield(ExprVal::Expr(argument)))
3383 }
3384 ExprCont::ParenEnd { start_span } => {
3385 let mut inner = expr_of(value);
3386 self.expect(&TokenKind::RParen)?;
3387 if self.at(&TokenKind::Dot)? {
3388 self.next()?;
3389 let path = self.parse_reference()?;
3390 let span = self.span_covering(&start_span, &self.last_span);
3391 inner = self.new_expression(
3392 ExpressionKind::Member { base: inner, path },
3393 self.make_source(span),
3394 )?;
3395 }
3396 Ok(ExprStep::Yield(ExprVal::Expr(inner)))
3397 }
3398 ExprCont::PastFuture { kind, start_span } => {
3399 let offset = expr_of(value);
3400 let offset_span = self.expr_span(offset).unwrap_or_else(|| start_span.clone());
3401 let span = self.span_covering(&start_span, &offset_span);
3402 expr_step(self.new_expression(
3403 ExpressionKind::PastFutureRange(kind, offset),
3404 self.make_source(span),
3405 ))
3406 }
3407 ExprCont::Math {
3408 operator,
3409 start_span,
3410 } => {
3411 let operand = expr_of(value);
3412 let end_span = self
3413 .expr_span(operand)
3414 .unwrap_or_else(|| start_span.clone());
3415 let span = self.span_covering(&start_span, &end_span);
3416 expr_step(self.new_expression(
3417 ExpressionKind::MathematicalComputation(operator, operand),
3418 self.make_source(span),
3419 ))
3420 }
3421 ExprCont::LowerUpperEnd { bound, start_span } => {
3422 let operand = expr_of(value);
3423 let end_span = self
3424 .expr_span(operand)
3425 .unwrap_or_else(|| start_span.clone());
3426 let span = self.span_covering(&start_span, &end_span);
3427 expr_step(self.new_expression(
3428 ExpressionKind::RangeBound(bound, operand),
3429 self.make_source(span),
3430 ))
3431 }
3432 ExprCont::PrefixArgumentEnd { keyword } => {
3433 let argument = expr_of(value);
3434 if !self.at_bare_argument_end()? {
3435 let tok = self.peek()?.clone();
3436 return Err(self.error_at_token(
3437 &tok,
3438 format!(
3439 "`{keyword}` without parentheses takes one operand, found '{op}' after it; \
3440 write `{keyword}(a {op} b)` or `{keyword}(a) {op} b`",
3441 op = tok.text
3442 ),
3443 ));
3444 }
3445 Ok(ExprStep::Yield(ExprVal::Expr(argument)))
3446 }
3447 ExprCont::PredicateValueRight { op, command } => {
3448 let right = expr_of(value);
3449 if !self.at_bare_argument_end()? {
3450 return Err(self.condition_error(command));
3451 }
3452 Ok(ExprStep::Yield(ExprVal::Predicate(ListPredicate::Value {
3453 op,
3454 right,
3455 })))
3456 }
3457 ExprCont::PredicateLeft {
3458 start_span,
3459 command,
3460 } => {
3461 let left = expr_of(value);
3462 if self.at_row_condition_operator()? {
3463 let op = self.parse_row_condition_operator()?;
3464 frames.push(ExprCont::PredicateRight {
3465 left,
3466 op,
3467 start_span,
3468 command,
3469 });
3470 return Ok(ExprStep::Enter(ExprTask::BareOperand));
3471 }
3472 self.predicate_instance_end(left, command)
3473 }
3474 ExprCont::PredicateRight {
3475 left,
3476 op,
3477 start_span,
3478 command,
3479 } => {
3480 let right = expr_of(value);
3481 let span = self.span_covering(&start_span, &self.last_span);
3482 let kind = match op {
3483 RowCondition::Compare(op) => ExpressionKind::Comparison(left, op, right),
3484 RowCondition::In => ExpressionKind::RangeContainment(left, right),
3485 };
3486 let expr = self.new_expression(kind, self.make_source(span))?;
3487 self.predicate_instance_end(expr, command)
3488 }
3489 ExprCont::WrapInstance => Ok(ExprStep::Yield(ExprVal::Predicate(
3490 ListPredicate::Instance {
3491 expr: expr_of(value),
3492 },
3493 ))),
3494 ExprCont::ValuePredicateEnd { op, command } => {
3495 let right = expr_of(value);
3496 if !self.at(&TokenKind::RParen)? {
3497 let tok = self.peek()?.clone();
3498 return Err(self.error_at_token(
3499 &tok,
3500 format!(
3501 "a value-list `{command}` condition is one comparison, found '{}'; chain \
3502 `where` or use `in` with a range",
3503 tok.text
3504 ),
3505 ));
3506 }
3507 Ok(ExprStep::Yield(ExprVal::Predicate(ListPredicate::Value {
3508 op,
3509 right,
3510 })))
3511 }
3512 ExprCont::CallPredicateEnd { command } => {
3513 self.expect(&TokenKind::RParen)?;
3514 self.reject_comma_after_call(command)?;
3515 Ok(ExprStep::Yield(value))
3516 }
3517 ExprCont::SortArgument { check_bare } => {
3518 let argument = expr_of(value);
3519 if check_bare
3520 && !self.at_any(&[TokenKind::Asc, TokenKind::Desc])?
3521 && !self.at_bare_argument_end()?
3522 {
3523 return Err(self.bare_argument_error("sort"));
3524 }
3525 let descending = self.parse_sort_direction()?;
3526 Ok(ExprStep::Yield(ExprVal::Command(ListCommand::Sort {
3527 descending,
3528 argument: Some(argument),
3529 })))
3530 }
3531 ExprCont::ListWithEnd => {
3532 let rows = rows_of(value);
3533 self.expect(&TokenKind::RParen)?;
3534 self.reject_comma_after_call("with")?;
3535 Ok(ExprStep::Yield(ExprVal::Rows(rows)))
3536 }
3537 ExprCont::PairValue { path, mut pairs } => {
3538 pairs.push((path, expr_of(value)));
3539 self.pair_value_next(pairs, frames)
3540 }
3541 ExprCont::ValueItem { mut values } => {
3542 values.push(expr_of(value));
3543 self.value_item_next(values, frames)
3544 }
3545 }
3546 }
3547
3548 fn and_chain(
3549 &mut self,
3550 first: ExprId,
3551 steps: Vec<ChainStep<()>>,
3552 start_span: Span,
3553 frames: &mut Vec<ExprCont>,
3554 ) -> Result<ExprStep, Error> {
3555 if !self.at(&TokenKind::And)? {
3556 return match steps.last() {
3557 None => Ok(ExprStep::Yield(ExprVal::Expr(first))),
3558 Some(last) => {
3559 let source = last.source_location.clone();
3560 expr_step(
3561 self.new_expression(ExpressionKind::LogicalAnd { first, steps }, source),
3562 )
3563 }
3564 };
3565 }
3566 self.next()?;
3567 frames.push(ExprCont::AndOperand {
3568 first,
3569 steps,
3570 start_span,
3571 });
3572 Ok(ExprStep::Enter(ExprTask::AndOperand))
3573 }
3574
3575 fn continue_repository(
3576 &mut self,
3577 mut expr: ExprId,
3578 start_span: Span,
3579 frames: &mut Vec<ExprCont>,
3580 ) -> Result<ExprStep, Error> {
3581 loop {
3582 let kind = self.peek()?.kind.clone();
3583 if is_comparison_operator(&kind) {
3584 return Ok(ExprStep::Enter(ExprTask::ComparisonSuffix {
3585 left: expr,
3586 start_span,
3587 }));
3588 }
3589 if kind == TokenKind::Not {
3590 expr = self.parse_not_in_calendar_suffix(expr, start_span.clone())?;
3591 continue;
3592 }
3593 if kind == TokenKind::In {
3594 frames.push(ExprCont::ContinueRepository {
3595 start_span: start_span.clone(),
3596 });
3597 return Ok(ExprStep::Enter(ExprTask::InSuffix {
3598 repository: expr,
3599 start_span,
3600 }));
3601 }
3602 if kind == TokenKind::As {
3603 expr = self.parse_as_chain(expr, start_span.clone())?;
3604 continue;
3605 }
3606 break;
3607 }
3608
3609 if self.at_expression_suffix_end()? {
3610 return expr_step(Ok(expr));
3611 }
3612
3613 let tok = self.peek()?.clone();
3614 Err(self.error_at_token(
3615 &tok,
3616 format!("Unexpected token '{}' after expression", tok.text),
3617 ))
3618 }
3619
3620 fn enter_comparison_suffix(
3621 &mut self,
3622 left: ExprId,
3623 start_span: Span,
3624 frames: &mut Vec<ExprCont>,
3625 ) -> Result<ExprStep, Error> {
3626 let operator = self.parse_comparison_operator()?;
3627 let operator_is_not = matches!(operator, ComparisonComputation::IsNot);
3628
3629 if matches!(
3630 operator,
3631 ComparisonComputation::Is | ComparisonComputation::IsNot
3632 ) && self.at_bare_veto_token()?
3633 {
3634 self.expect(&TokenKind::Veto)?;
3635 if self.at(&TokenKind::StringLit)? {
3636 let tok = self.peek()?.clone();
3637 return Err(self.error_at_token(
3638 &tok,
3639 "veto with a message is only valid as a rule or unless result, not in `is veto` comparisons",
3640 ));
3641 }
3642 return expr_step(self.wrap_result_is_veto_expression(
3643 left,
3644 operator_is_not,
3645 false,
3646 start_span,
3647 ));
3648 }
3649
3650 let right = if self.at(&TokenKind::Not)? {
3651 ExprTask::NotExpression
3652 } else {
3653 ExprTask::RepositoryExpression
3654 };
3655 frames.push(ExprCont::ComparisonRight {
3656 left,
3657 operator,
3658 start_span,
3659 });
3660 Ok(ExprStep::Enter(right))
3661 }
3662
3663 fn enter_in_suffix(
3664 &mut self,
3665 repository: ExprId,
3666 start_span: Span,
3667 frames: &mut Vec<ExprCont>,
3668 ) -> Result<ExprStep, Error> {
3669 self.expect(&TokenKind::In)?;
3670
3671 let peeked = self.peek()?.clone();
3672 if peeked.kind == TokenKind::Past || peeked.kind == TokenKind::Future {
3673 let direction = self.next()?;
3674 let rel_kind = if direction.kind == TokenKind::Past {
3675 DateRelativeKind::InPast
3676 } else {
3677 DateRelativeKind::InFuture
3678 };
3679
3680 if self.at_calendar_period_marker()? {
3681 self.next_calendar_period_marker()?;
3682 let cal_kind = if direction.kind == TokenKind::Past {
3683 DateCalendarKind::Past
3684 } else {
3685 DateCalendarKind::Future
3686 };
3687 let unit = self.parse_calendar_unit()?;
3688 let end = self.peek()?.span.clone();
3689 let span = self.span_covering(&start_span, &end);
3690 return expr_step(self.new_expression(
3691 ExpressionKind::DateCalendar(cal_kind, unit, repository),
3692 self.make_source(span),
3693 ));
3694 }
3695
3696 if self.at(&TokenKind::And)?
3697 || self.at(&TokenKind::Unless)?
3698 || self.at(&TokenKind::Then)?
3699 || self.at(&TokenKind::RParen)?
3700 || self.at(&TokenKind::Eof)?
3701 || self.at(&TokenKind::Spec)?
3702 || is_spec_body_keyword(&self.peek()?.kind)
3703 || is_comparison_operator(&self.peek()?.kind)
3704 {
3705 let end = self.peek()?.span.clone();
3706 let span = self.span_covering(&start_span, &end);
3707 return expr_step(self.new_expression(
3708 ExpressionKind::DateRelative(rel_kind, repository),
3709 self.make_source(span),
3710 ));
3711 }
3712
3713 frames.push(ExprCont::InOffset {
3714 direction: direction.span,
3715 rel_kind,
3716 repository,
3717 start_span,
3718 });
3719 return Ok(ExprStep::Enter(ExprTask::RepositoryExpression));
3720 }
3721
3722 if token_is_calendar_period_marker(&peeked) {
3723 self.next_calendar_period_marker()?;
3724 let unit = self.parse_calendar_unit()?;
3725 let end = self.peek()?.span.clone();
3726 let span = self.span_covering(&start_span, &end);
3727 return expr_step(self.new_expression(
3728 ExpressionKind::DateCalendar(DateCalendarKind::Current, unit, repository),
3729 self.make_source(span),
3730 ));
3731 }
3732
3733 frames.push(ExprCont::InRange {
3734 repository,
3735 start_span,
3736 });
3737 Ok(ExprStep::Enter(ExprTask::RepositoryExpression))
3738 }
3739
3740 fn enter_prefix_argument(
3741 &mut self,
3742 keyword: String,
3743 frames: &mut Vec<ExprCont>,
3744 ) -> Result<ExprStep, Error> {
3745 if self.at(&TokenKind::LParen)? {
3746 return Ok(ExprStep::Enter(ExprTask::Primary));
3747 }
3748 if !self.at_bare_operand_start()? {
3749 let tok = self.peek()?.clone();
3750 return Err(self.error_at_token(
3751 &tok,
3752 format!(
3753 "`{keyword}` takes one operand or `{keyword}(...)`, found '{}'",
3754 tok.text
3755 ),
3756 ));
3757 }
3758 self.check_depth()?;
3759 frames.push(ExprCont::PrefixArgumentEnd { keyword });
3760 frames.push(ExprCont::PopDepth);
3761 Ok(ExprStep::Enter(ExprTask::RangeOperand))
3762 }
3763
3764 fn enter_primary(&mut self, frames: &mut Vec<ExprCont>) -> Result<ExprStep, Error> {
3765 let start_span = self.peek()?.span.clone();
3766 let kind = self.peek()?.kind.clone();
3767 match &kind {
3768 TokenKind::LParen => {
3769 self.next()?;
3770 let saved = self.save_flags();
3771 self.bare_operand = false;
3772 self.call_argument_depth = 0;
3773 frames.push(ExprCont::ParenEnd { start_span });
3774 frames.push(ExprCont::Restore(saved));
3775 Ok(ExprStep::Enter(ExprTask::Expression))
3776 }
3777 TokenKind::Now => {
3778 let tok = self.next()?;
3779 expr_step(self.new_expression(ExpressionKind::Now, self.make_source(tok.span)))
3780 }
3781 TokenKind::Past | TokenKind::Future => {
3782 let tok = self.next()?;
3783 let rel_kind = if tok.kind == TokenKind::Past {
3784 DateRelativeKind::InPast
3785 } else {
3786 DateRelativeKind::InFuture
3787 };
3788 frames.push(ExprCont::PastFuture {
3789 kind: rel_kind,
3790 start_span,
3791 });
3792 Ok(ExprStep::Enter(ExprTask::RepositoryExpression))
3793 }
3794 TokenKind::StringLit => {
3795 let tok = self.next()?;
3796 expr_step(self.new_expression(
3797 ExpressionKind::Literal(Value::Text(tok.text)),
3798 self.make_source(tok.span),
3799 ))
3800 }
3801 k if is_boolean_keyword(k) => {
3802 let tok = self.next()?;
3803 expr_step(self.new_expression(
3804 ExpressionKind::Literal(Value::Boolean(token_kind_to_boolean_value(&tok.kind))),
3805 self.make_source(tok.span),
3806 ))
3807 }
3808 TokenKind::NumberLit => expr_step(self.parse_number_expression()),
3809 k if can_be_label(k) => {
3810 let reference = self.parse_expression_reference()?;
3811 let span = self.span_covering(&start_span, &self.last_span);
3812 let expr = self
3813 .new_expression(ExpressionKind::Reference(reference), self.make_source(span))?;
3814 expr_step(self.wrap_list_type_suffix(expr, start_span))
3815 }
3816 k if token_kind_to_primitive(k).is_some() => {
3817 if !self.next_is_list_type_suffix()? {
3818 let tok = self.next()?;
3819 return Err(self.error_at_token(
3820 &tok,
3821 format!("Expected an expression, found '{}'", tok.text),
3822 ));
3823 }
3824 let parent = self.parse_expression_parent_type()?;
3825 let span = self.span_covering(&start_span, &self.last_span);
3826 expr_step(self.new_expression(
3827 ExpressionKind::ListType { element: parent },
3828 self.make_source(span),
3829 ))
3830 }
3831 _ => {
3832 let tok = self.next()?;
3833 Err(self.error_at_token(
3834 &tok,
3835 format!("Expected an expression, found '{}'", tok.text),
3836 ))
3837 }
3838 }
3839 }
3840
3841 fn enter_list_command_body(
3842 &mut self,
3843 name: Token,
3844 frames: &mut Vec<ExprCont>,
3845 ) -> Result<ExprStep, Error> {
3846 match name.kind {
3847 TokenKind::Find => {
3848 frames.push(ExprCont::Command(CommandBuild::Find));
3849 Ok(ExprStep::Enter(ExprTask::FindKeys))
3850 }
3851 TokenKind::First => {
3852 self.reject_command_argument("first")?;
3853 Ok(ExprStep::Yield(ExprVal::Command(ListCommand::First)))
3854 }
3855 TokenKind::Last => {
3856 self.reject_command_argument("last")?;
3857 Ok(ExprStep::Yield(ExprVal::Command(ListCommand::Last)))
3858 }
3859 TokenKind::Count => {
3860 self.reject_command_argument("count")?;
3861 Ok(ExprStep::Yield(ExprVal::Command(ListCommand::Count)))
3862 }
3863 TokenKind::Sum => {
3864 frames.push(ExprCont::Command(CommandBuild::Sum));
3865 Ok(ExprStep::Enter(ExprTask::OptionalArgument {
3866 command: "sum",
3867 }))
3868 }
3869 TokenKind::Avg => {
3870 frames.push(ExprCont::Command(CommandBuild::Avg));
3871 Ok(ExprStep::Enter(ExprTask::OptionalArgument {
3872 command: "avg",
3873 }))
3874 }
3875 TokenKind::Product => {
3876 frames.push(ExprCont::Command(CommandBuild::Product));
3877 Ok(ExprStep::Enter(ExprTask::OptionalArgument {
3878 command: "product",
3879 }))
3880 }
3881 TokenKind::Min => {
3882 frames.push(ExprCont::Command(CommandBuild::Min));
3883 Ok(ExprStep::Enter(ExprTask::OptionalArgument {
3884 command: "min",
3885 }))
3886 }
3887 TokenKind::Max => {
3888 frames.push(ExprCont::Command(CommandBuild::Max));
3889 Ok(ExprStep::Enter(ExprTask::OptionalArgument {
3890 command: "max",
3891 }))
3892 }
3893 TokenKind::Any => {
3894 frames.push(ExprCont::Command(CommandBuild::Any));
3895 Ok(ExprStep::Enter(ExprTask::ListPredicate { command: "any" }))
3896 }
3897 TokenKind::All => {
3898 frames.push(ExprCont::Command(CommandBuild::All));
3899 Ok(ExprStep::Enter(ExprTask::ListPredicate { command: "all" }))
3900 }
3901 TokenKind::Where => {
3902 frames.push(ExprCont::Command(CommandBuild::Where));
3903 Ok(ExprStep::Enter(ExprTask::ListPredicate {
3904 command: "where",
3905 }))
3906 }
3907 TokenKind::Sort => Ok(ExprStep::Enter(ExprTask::SortCommand)),
3908 TokenKind::Top => {
3909 frames.push(ExprCont::Command(CommandBuild::Top));
3910 Ok(ExprStep::Enter(ExprTask::RequiredArgument {
3911 command: "top",
3912 }))
3913 }
3914 TokenKind::With => {
3915 frames.push(ExprCont::Command(CommandBuild::With));
3916 Ok(ExprStep::Enter(ExprTask::ListWithCommand))
3917 }
3918 _ => Err(self.error_at_token(&name, format!("Unknown list command '{}'", name.text))),
3919 }
3920 }
3921
3922 fn enter_list_predicate(
3923 &mut self,
3924 command: &'static str,
3925 frames: &mut Vec<ExprCont>,
3926 ) -> Result<ExprStep, Error> {
3927 if self.at(&TokenKind::LParen)? {
3928 return Ok(ExprStep::Enter(ExprTask::CallListPredicate { command }));
3929 }
3930 if self.at_row_condition_operator()? {
3931 let op = self.parse_row_condition_operator()?;
3932 frames.push(ExprCont::PredicateValueRight { op, command });
3933 return Ok(ExprStep::Enter(ExprTask::BareOperand));
3934 }
3935 if !self.at_bare_operand_start()? {
3936 let tok = self.peek()?.clone();
3937 return Err(self.error_at_token(
3938 &tok,
3939 format!("`{command}` needs a condition; write `{command}(...)`"),
3940 ));
3941 }
3942 let start_span = self.peek()?.span.clone();
3943 frames.push(ExprCont::PredicateLeft {
3944 start_span,
3945 command,
3946 });
3947 Ok(ExprStep::Enter(ExprTask::BareOperand))
3948 }
3949
3950 fn predicate_instance_end(
3951 &mut self,
3952 expr: ExprId,
3953 command: &'static str,
3954 ) -> Result<ExprStep, Error> {
3955 if !self.at_bare_argument_end()? {
3956 return Err(self.condition_error(command));
3957 }
3958 Ok(ExprStep::Yield(ExprVal::Predicate(
3959 ListPredicate::Instance { expr },
3960 )))
3961 }
3962
3963 fn enter_pair_field(
3964 &mut self,
3965 pairs: Vec<(Reference, ExprId)>,
3966 frames: &mut Vec<ExprCont>,
3967 ) -> Result<ExprStep, Error> {
3968 let path = self.parse_reference()?;
3969 self.expect(&TokenKind::Colon)?;
3970 frames.push(ExprCont::PairValue { path, pairs });
3971 Ok(ExprStep::Enter(ExprTask::BareArgument { command: "with" }))
3972 }
3973
3974 fn pair_value_next(
3975 &mut self,
3976 pairs: Vec<(Reference, ExprId)>,
3977 frames: &mut Vec<ExprCont>,
3978 ) -> Result<ExprStep, Error> {
3979 if !self.at(&TokenKind::Comma)? {
3980 return Ok(ExprStep::Yield(ExprVal::Rows(ListWithRows::FieldPairs(
3981 pairs,
3982 ))));
3983 }
3984 self.next()?;
3985 if !self.at_path_then_colon()? {
3986 let tok = self.peek()?.clone();
3987 return Err(self.error_at_token_with_suggestion(
3988 &tok,
3989 "Expected a field pair after comma".to_string(),
3990 "Remove the extra comma, or add `field: value`",
3991 ));
3992 }
3993 self.enter_pair_field(pairs, frames)
3994 }
3995
3996 fn value_item_next(
3997 &mut self,
3998 values: Vec<ExprId>,
3999 frames: &mut Vec<ExprCont>,
4000 ) -> Result<ExprStep, Error> {
4001 if !self.at(&TokenKind::Comma)? {
4002 return Ok(ExprStep::Yield(ExprVal::Rows(ListWithRows::Values(values))));
4003 }
4004 self.next()?;
4005 if self.at_expression_suffix_end()? || self.at(&TokenKind::Comma)? {
4006 let tok = self.peek()?.clone();
4007 return Err(self.error_at_token_with_suggestion(
4008 &tok,
4009 "Trailing or empty comma in list".to_string(),
4010 "Remove the extra comma, or add the missing value",
4011 ));
4012 }
4013 frames.push(ExprCont::ValueItem { values });
4014 Ok(ExprStep::Enter(ExprTask::BareArgument { command: "with" }))
4015 }
4016
4017 fn find_key_next(
4018 &mut self,
4019 keys: Vec<ExprId>,
4020 frames: &mut Vec<ExprCont>,
4021 ) -> Result<ExprStep, Error> {
4022 if self.at(&TokenKind::Comma)? && self.call_argument_depth == 0 {
4023 self.next()?;
4024 frames.push(ExprCont::FindKey { keys });
4025 return Ok(ExprStep::Enter(ExprTask::BareArgument { command: "find" }));
4026 }
4027 Ok(ExprStep::Yield(ExprVal::Exprs(keys)))
4028 }
4029
4030 fn call_argument_items(
4031 &mut self,
4032 arguments: Vec<ExprId>,
4033 frames: &mut Vec<ExprCont>,
4034 ) -> Result<ExprStep, Error> {
4035 if self.at(&TokenKind::Comma)? {
4036 self.next()?;
4037 frames.push(ExprCont::CallArgumentItems { arguments });
4038 return Ok(ExprStep::Enter(ExprTask::Expression));
4039 }
4040 Ok(ExprStep::Yield(ExprVal::Exprs(arguments)))
4041 }
4042
4043 fn repository_chain(
4044 &mut self,
4045 first: ExprId,
4046 steps: Vec<ChainStep<ArithmeticComputation>>,
4047 start_span: Span,
4048 frames: &mut Vec<ExprCont>,
4049 ) -> Result<ExprStep, Error> {
4050 if !self.at_any(&[TokenKind::Plus, TokenKind::Minus])? {
4051 return expr_step(self.arithmetic_chain(first, steps));
4052 }
4053 let op_tok = self.next()?;
4054 let operation = match op_tok.kind {
4055 TokenKind::Plus => ArithmeticComputation::Add,
4056 TokenKind::Minus => ArithmeticComputation::Subtract,
4057 _ => unreachable!("BUG: only + and - should reach here"),
4058 };
4059 frames.push(ExprCont::RepositoryOperand {
4060 first,
4061 steps,
4062 start_span,
4063 operation,
4064 });
4065 Ok(ExprStep::Enter(ExprTask::Term { allow_as: true }))
4066 }
4067
4068 fn term_chain(
4069 &mut self,
4070 first: ExprId,
4071 steps: Vec<ChainStep<ArithmeticComputation>>,
4072 allow_as: bool,
4073 start_span: Span,
4074 frames: &mut Vec<ExprCont>,
4075 ) -> Result<ExprStep, Error> {
4076 if self.at(&TokenKind::Percent)? {
4077 let pct_tok = self.next()?;
4078 return Err(self.error_at_token(
4079 &pct_tok,
4080 "'%' is percent only; use 'mod' for remainder (e.g. 'value mod 7')",
4081 ));
4082 }
4083 if !self.at_any(&[TokenKind::Star, TokenKind::Slash, TokenKind::Mod])? {
4084 return expr_step(self.arithmetic_chain(first, steps));
4085 }
4086 let op_tok = self.next()?;
4087 let operation = match op_tok.kind {
4088 TokenKind::Star => ArithmeticComputation::Multiply,
4089 TokenKind::Slash => ArithmeticComputation::Divide,
4090 TokenKind::Mod => ArithmeticComputation::Modulo,
4091 _ => unreachable!("BUG: only *, /, mod should reach here"),
4092 };
4093 let right_start_span = self.peek()?.span.clone();
4094 frames.push(ExprCont::TermOperand {
4095 first,
4096 steps,
4097 allow_as,
4098 start_span,
4099 operation,
4100 right_start_span,
4101 });
4102 Ok(ExprStep::Enter(ExprTask::Power))
4103 }
4104
4105 fn power_tail(
4106 &mut self,
4107 left: ExprId,
4108 start_span: Span,
4109 range_bound: bool,
4110 frames: &mut Vec<ExprCont>,
4111 ) -> Result<ExprStep, Error> {
4112 if !self.at(&TokenKind::Caret)? {
4113 return Ok(ExprStep::Yield(ExprVal::Expr(left)));
4114 }
4115 self.next()?;
4116 self.check_depth()?;
4117 frames.push(ExprCont::PowerRight { left, start_span });
4118 frames.push(ExprCont::PopDepth);
4119 Ok(ExprStep::Enter(if range_bound {
4120 ExprTask::PowerForRangeBound
4121 } else {
4122 ExprTask::Power
4123 }))
4124 }
4125
4126 fn ellipsis_chain(
4127 &mut self,
4128 first: ExprId,
4129 steps: Vec<ChainStep<ArithmeticComputation>>,
4130 start_span: Span,
4131 mut starts: Vec<usize>,
4132 frames: &mut Vec<ExprCont>,
4133 ) -> Result<ExprStep, Error> {
4134 if !self.at_any(&[TokenKind::Plus, TokenKind::Minus])? {
4135 self.bound_chain_starts = starts;
4136 return expr_step(self.arithmetic_chain(first, steps));
4137 }
4138 let op_tok = self.next()?;
4139 let operation = match op_tok.kind {
4140 TokenKind::Plus => ArithmeticComputation::Add,
4141 TokenKind::Minus => ArithmeticComputation::Subtract,
4142 _ => unreachable!("BUG: only + and - should reach here"),
4143 };
4144 starts.push(self.peek()?.span.start);
4145 frames.push(ExprCont::EllipsisOperand {
4146 first,
4147 steps,
4148 start_span,
4149 operation,
4150 starts,
4151 });
4152 Ok(ExprStep::Enter(ExprTask::PowerForRangeBound))
4153 }
4154}
4155
4156#[derive(Clone, Copy, PartialEq, Eq)]
4158struct ExprFlags {
4159 bare_operand: bool,
4160 call_argument_depth: usize,
4161}
4162
4163enum ExprTask {
4165 Expression,
4166 AndExpression,
4167 AndOperand,
4168 VetoStatus,
4169 NotExpression,
4170 RepositoryWithSuffix,
4171 ComparisonSuffix {
4172 left: ExprId,
4173 start_span: Span,
4174 },
4175 InSuffix {
4176 repository: ExprId,
4177 start_span: Span,
4178 },
4179 RepositoryExpression,
4180 Term {
4181 allow_as: bool,
4182 },
4183 Power,
4184 RangeOperand,
4185 RangeEllipsisBound,
4186 PowerForRangeBound,
4187 Factor,
4188 PrimaryOrMath,
4189 MathFunction,
4190 LowerUpper,
4191 PrefixArgument {
4192 keyword: String,
4193 },
4194 Primary,
4195 ListCommandSuffix {
4196 list: ExprId,
4197 start_span: Span,
4198 },
4199 ListCommandBody {
4200 name: Token,
4201 },
4202 FindKeys,
4203 CallArguments {
4204 command: &'static str,
4205 },
4206 SingleCallArgument {
4207 command: &'static str,
4208 },
4209 OptionalArgument {
4210 command: &'static str,
4211 },
4212 RequiredArgument {
4213 command: &'static str,
4214 },
4215 BareArgument {
4216 command: &'static str,
4217 },
4218 BareOperand,
4219 ListPredicate {
4220 command: &'static str,
4221 },
4222 CallListPredicate {
4223 command: &'static str,
4224 },
4225 ValuePredicateInParentheses {
4226 command: &'static str,
4227 },
4228 SortCommand,
4229 ListWithCommand,
4230 ListWithRows,
4231}
4232
4233#[derive(Clone, Copy)]
4235enum CommandBuild {
4236 Find,
4237 Sum,
4238 Avg,
4239 Product,
4240 Min,
4241 Max,
4242 Any,
4243 All,
4244 Where,
4245 Top,
4246 With,
4247}
4248
4249enum ExprCont {
4251 Restore(ExprFlags),
4252 PopDepth,
4253 AndFirst {
4254 start_span: Span,
4255 },
4256 AndOperand {
4257 first: ExprId,
4258 steps: Vec<ChainStep<()>>,
4259 start_span: Span,
4260 },
4261 VetoStatus {
4262 operator_is_not: bool,
4263 keyword_was_negated: bool,
4264 start_span: Span,
4265 },
4266 Negation {
4267 start_span: Span,
4268 },
4269 RepositorySuffix {
4270 start_span: Span,
4271 },
4272 ContinueRepository {
4273 start_span: Span,
4274 },
4275 ComparisonRight {
4276 left: ExprId,
4277 operator: ComparisonComputation,
4278 start_span: Span,
4279 },
4280 InOffset {
4281 direction: Span,
4282 rel_kind: DateRelativeKind,
4283 repository: ExprId,
4284 start_span: Span,
4285 },
4286 InRange {
4287 repository: ExprId,
4288 start_span: Span,
4289 },
4290 RepositoryFirst {
4291 start_span: Span,
4292 },
4293 RepositoryOperand {
4294 first: ExprId,
4295 steps: Vec<ChainStep<ArithmeticComputation>>,
4296 start_span: Span,
4297 operation: ArithmeticComputation,
4298 },
4299 TermFirst {
4300 allow_as: bool,
4301 start_span: Span,
4302 },
4303 TermOperand {
4304 first: ExprId,
4305 steps: Vec<ChainStep<ArithmeticComputation>>,
4306 allow_as: bool,
4307 start_span: Span,
4308 operation: ArithmeticComputation,
4309 right_start_span: Span,
4310 },
4311 PowerLeft {
4312 start_span: Span,
4313 range_bound: bool,
4314 },
4315 PowerRight {
4316 left: ExprId,
4317 start_span: Span,
4318 },
4319 RangeFactor {
4321 start_span: Span,
4322 flags: ExprFlags,
4323 },
4324 RangeLeft {
4327 factor: ExprId,
4328 start_span: Span,
4329 checkpoint: Box<ParserCheckpoint>,
4330 flags: ExprFlags,
4331 },
4332 RangeRight {
4333 left: ExprId,
4334 start_span: Span,
4335 },
4336 EllipsisFirst {
4337 start_span: Span,
4338 },
4339 EllipsisOperand {
4340 first: ExprId,
4341 steps: Vec<ChainStep<ArithmeticComputation>>,
4342 start_span: Span,
4343 operation: ArithmeticComputation,
4344 starts: Vec<usize>,
4345 },
4346 FactorNegate {
4347 start_span: Span,
4348 },
4349 PrimaryOrMathSuffix {
4350 start_span: Span,
4351 },
4352 ListCommandDone {
4353 list: ExprId,
4354 start_span: Span,
4355 },
4356 Command(CommandBuild),
4357 FindKey {
4358 keys: Vec<ExprId>,
4359 },
4360 CallArgumentsEnd {
4361 command: &'static str,
4362 },
4363 CallArgumentItems {
4364 arguments: Vec<ExprId>,
4365 },
4366 SingleCallArgumentCheck {
4367 command: &'static str,
4368 },
4369 WrapSome,
4370 BareArgumentEnd {
4371 command: &'static str,
4372 },
4373 ParenEnd {
4374 start_span: Span,
4375 },
4376 PastFuture {
4377 kind: DateRelativeKind,
4378 start_span: Span,
4379 },
4380 Math {
4381 operator: MathematicalComputation,
4382 start_span: Span,
4383 },
4384 LowerUpperEnd {
4385 bound: RangeBound,
4386 start_span: Span,
4387 },
4388 PrefixArgumentEnd {
4389 keyword: String,
4390 },
4391 PredicateValueRight {
4392 op: RowCondition,
4393 command: &'static str,
4394 },
4395 PredicateLeft {
4396 start_span: Span,
4397 command: &'static str,
4398 },
4399 PredicateRight {
4400 left: ExprId,
4401 op: RowCondition,
4402 start_span: Span,
4403 command: &'static str,
4404 },
4405 WrapInstance,
4406 ValuePredicateEnd {
4407 op: RowCondition,
4408 command: &'static str,
4409 },
4410 CallPredicateEnd {
4411 command: &'static str,
4412 },
4413 SortArgument {
4414 check_bare: bool,
4415 },
4416 ListWithEnd,
4417 PairValue {
4418 path: Reference,
4419 pairs: Vec<(Reference, ExprId)>,
4420 },
4421 ValueItem {
4422 values: Vec<ExprId>,
4423 },
4424}
4425
4426enum ExprVal {
4428 Expr(ExprId),
4429 Optional(Option<ExprId>),
4430 Exprs(Vec<ExprId>),
4431 Command(ListCommand),
4432 Predicate(ListPredicate),
4433 Rows(ListWithRows),
4434}
4435
4436enum ExprStep {
4437 Enter(ExprTask),
4438 Yield(ExprVal),
4439}
4440
4441fn expr_of(value: ExprVal) -> ExprId {
4442 match value {
4443 ExprVal::Expr(expr) => expr,
4444 _ => panic!("BUG: expression machine expected an expression value"),
4445 }
4446}
4447
4448fn optional_of(value: ExprVal) -> Option<ExprId> {
4449 match value {
4450 ExprVal::Optional(argument) => argument,
4451 _ => panic!("BUG: expression machine expected an optional argument"),
4452 }
4453}
4454
4455fn exprs_of(value: ExprVal) -> Vec<ExprId> {
4456 match value {
4457 ExprVal::Exprs(exprs) => exprs,
4458 _ => panic!("BUG: expression machine expected an argument list"),
4459 }
4460}
4461
4462fn predicate_of(value: ExprVal) -> ListPredicate {
4463 match value {
4464 ExprVal::Predicate(predicate) => predicate,
4465 _ => panic!("BUG: expression machine expected a list predicate"),
4466 }
4467}
4468
4469fn rows_of(value: ExprVal) -> ListWithRows {
4470 match value {
4471 ExprVal::Rows(rows) => rows,
4472 _ => panic!("BUG: expression machine expected list rows"),
4473 }
4474}
4475
4476fn command_of(value: ExprVal) -> ListCommand {
4477 match value {
4478 ExprVal::Command(command) => command,
4479 _ => panic!("BUG: expression machine expected a list command"),
4480 }
4481}
4482
4483fn expr_step(result: Result<ExprId, Error>) -> Result<ExprStep, Error> {
4484 result.map(|expr| ExprStep::Yield(ExprVal::Expr(expr)))
4485}
4486
4487fn build_command(builder: CommandBuild, value: ExprVal) -> ListCommand {
4488 match builder {
4489 CommandBuild::Find => ListCommand::Find {
4490 keys: exprs_of(value),
4491 },
4492 CommandBuild::Sum => ListCommand::Sum {
4493 argument: optional_of(value),
4494 },
4495 CommandBuild::Avg => ListCommand::Avg {
4496 argument: optional_of(value),
4497 },
4498 CommandBuild::Product => ListCommand::Product {
4499 argument: optional_of(value),
4500 },
4501 CommandBuild::Min => ListCommand::Min {
4502 argument: optional_of(value),
4503 },
4504 CommandBuild::Max => ListCommand::Max {
4505 argument: optional_of(value),
4506 },
4507 CommandBuild::Any => ListCommand::Any {
4508 form: predicate_of(value),
4509 },
4510 CommandBuild::All => ListCommand::All {
4511 form: predicate_of(value),
4512 },
4513 CommandBuild::Where => ListCommand::Where {
4514 form: predicate_of(value),
4515 },
4516 CommandBuild::Top => ListCommand::Top { n: expr_of(value) },
4517 CommandBuild::With => ListCommand::With {
4518 rows: rows_of(value),
4519 },
4520 }
4521}
4522
4523fn parent_type_from_reference(reference: &Reference) -> ParentType {
4524 if reference.segments.is_empty() {
4525 return ParentType::Custom {
4526 name: reference.name.clone(),
4527 };
4528 }
4529 if reference.segments.len() == 1 {
4530 return ParentType::Qualified {
4531 spec_alias: reference.segments[0].clone(),
4532 inner: Box::new(ParentType::Custom {
4533 name: reference.name.clone(),
4534 }),
4535 };
4536 }
4537 ParentType::Qualified {
4538 spec_alias: reference.segments[0].clone(),
4539 inner: Box::new(ParentType::Custom {
4540 name: reference.name.clone(),
4541 }),
4542 }
4543}
4544
4545fn parse_decimal_string(text: &str, span: &Span, parser: &Parser) -> Result<Decimal, Error> {
4550 text.parse::<crate::literals::NumberLiteral>()
4551 .map(|parsed| parsed.0)
4552 .map_err(|message| {
4553 Error::parsing(message, parser.make_source(span.clone()), None::<String>)
4554 })
4555}
4556
4557fn try_negate_numeric_literal(value: Value) -> Result<Value, Value> {
4559 match value {
4560 Value::Number(d) => Ok(Value::Number(-d)),
4561 Value::NumberWithUnit(d, unit) => Ok(Value::NumberWithUnit(-d, unit)),
4562 other => Err(other),
4563 }
4564}
4565
4566fn is_comparison_operator(kind: &TokenKind) -> bool {
4567 matches!(
4568 kind,
4569 TokenKind::Gt | TokenKind::Lt | TokenKind::Gte | TokenKind::Lte | TokenKind::Is
4570 )
4571}