1use anyhow::{Result, anyhow, bail};
16use ast::{Arena, Constraints};
17use mangle_ast as ast;
18use std::io;
19
20mod error;
21mod quote;
22mod scan;
23mod token;
24
25pub use error::{ErrorContext, ParseError};
26use token::Token;
27
28pub struct Parser<'arena, R>
29where
30 R: io::Read,
31{
32 sc: scan::Scanner<R>,
33 token: crate::token::Token,
34 arena: &'arena Arena,
35 anon_counter: usize,
36}
37
38fn package_sym(arena: &Arena) -> ast::PredicateIndex {
39 arena.predicate_sym("Package", Some(0))
40}
41
42fn name_sym(arena: &Arena) -> ast::PredicateIndex {
43 arena.predicate_sym("name", Some(1))
44}
45
46fn use_sym(arena: &Arena) -> ast::PredicateIndex {
47 arena.predicate_sym("Use", Some(0))
48}
49
50fn lt_sym(arena: &Arena) -> ast::PredicateIndex {
51 arena.predicate_sym(":lt", Some(2))
52}
53
54fn le_sym(arena: &Arena) -> ast::PredicateIndex {
55 arena.predicate_sym(":le", Some(2))
56}
57
58fn gt_sym(arena: &Arena) -> ast::PredicateIndex {
59 arena.predicate_sym(":gt", Some(2))
60}
61
62fn ge_sym(arena: &Arena) -> ast::PredicateIndex {
63 arena.predicate_sym(":ge", Some(2))
64}
65
66fn fn_list_sym(arena: &Arena) -> ast::FunctionIndex {
67 arena.function_sym("fn:list", None)
68}
69
70fn fn_map_sym(arena: &Arena) -> ast::FunctionIndex {
71 arena.function_sym("fn:map", None)
72}
73
74fn fn_struct_sym(arena: &Arena) -> ast::FunctionIndex {
75 arena.function_sym("fn:struct", None)
76}
77
78fn fn_list_type_sym(arena: &Arena) -> ast::FunctionIndex {
79 arena.function_sym("fn:List", None)
80}
81
82fn fn_option_type_sym(arena: &Arena) -> ast::FunctionIndex {
83 arena.function_sym("fn:Option", None)
84}
85
86fn empty_package_decl(arena: &Arena) -> ast::Decl<'_> {
87 ast::Decl {
88 atom: arena.alloc(ast::Atom {
89 sym: package_sym(arena),
90 args: &[],
91 }),
92 is_temporal: false,
93 descr: arena.alloc_slice_copy(&[arena.alloc(ast::Atom {
94 sym: name_sym(arena),
95 args: arena
96 .alloc_slice_copy(&[arena.alloc(ast::BaseTerm::Const(ast::Const::String("")))]),
97 })]),
98 bounds: None,
99 constraints: None,
100 }
101}
102
103macro_rules! alloc {
104 ($self:expr, $e:expr) => {
105 &*$self.arena.alloc($e)
106 };
107}
108
109macro_rules! alloc_str {
110 ($self:expr, $e:expr) => {
111 &*$self.arena.alloc_str($e)
112 };
113}
114
115macro_rules! alloc_slice {
116 ($self:expr, $e:expr) => {
117 &*$self.arena.alloc_slice_copy($e)
118 };
119}
120
121impl<'arena, R> Parser<'arena, R>
122where
123 R: io::Read,
124{
125 pub fn new<P: ToString>(arena: &'arena Arena, reader: R, path: P) -> Self
126 where
127 R: io::Read,
128 {
129 Self {
130 sc: scan::Scanner::new(reader, path),
131 token: token::Token::Illegal,
132 arena,
133 anon_counter: 0,
134 }
135 }
136
137 pub fn next_token(&mut self) -> Result<()> {
138 self.token = self.sc.next_token()?;
139 Ok(())
140 }
141
142 fn expect(&mut self, expected: Token) -> Result<()> {
144 if expected != self.token {
145 let error = ParseError::Unexpected(
146 self.sc.get_error_context(),
147 expected.clone(),
148 self.token.clone(),
149 );
150 return Err(anyhow!(error));
151 }
152 self.next_token()
153 }
154
155 pub fn parse_unit(&mut self) -> Result<&'arena ast::Unit<'arena>> {
156 let package = if matches!(self.token.clone(), Token::Package) {
157 self.parse_package_decl()?
158 } else {
159 self.arena.alloc(empty_package_decl(self.arena))
160 };
161 let mut decls = vec![package];
162 while let Token::Use = self.token {
163 decls.push(self.parse_use_decl()?);
164 }
165 let mut clauses = vec![];
166 loop {
167 match self.token {
168 Token::Eof => break,
169 Token::Decl => decls.push(self.parse_decl()?),
170 _ => clauses.push(self.parse_clause()?),
171 }
172 }
173 let decls: &'arena [&'arena ast::Decl<'arena>] = self.arena.alloc_slice_copy(&decls);
174 let clauses: &'arena [&'arena ast::Clause<'arena>] = self.arena.alloc_slice_copy(&clauses);
175 let unit: &'arena ast::Unit<'arena> = &*self.arena.alloc(ast::Unit { clauses, decls });
176 Ok(unit)
177 }
178
179 pub fn parse_package_decl(&mut self) -> Result<&'arena ast::Decl<'arena>> {
181 self.expect(Token::Package)?;
182 let package_name: &'arena str = if let Token::Ident { name } = &self.token {
183 self.arena.alloc_str(name.as_str())
184 } else {
185 bail!("expected identifer got {}", self.token);
186 };
187
188 let name_atom: &'arena ast::Atom<'arena> = self.arena.alloc(ast::Atom {
189 sym: name_sym(self.arena),
190 args: self.arena.alloc_slice_copy(&[self
191 .arena
192 .alloc(ast::BaseTerm::Const(ast::Const::String(package_name)))]),
193 });
194 let mut descr_atoms: Vec<&'arena ast::Atom<'arena>> = vec![name_atom];
195 self.next_token()?;
196 if Token::LBracket == self.token {
197 self.parse_bracket_atoms(&mut descr_atoms)?;
198 }
199 let descr = alloc_slice!(self, &descr_atoms);
200
201 self.expect(Token::Bang)?;
202
203 let package_atom = alloc!(
204 self,
205 ast::Atom {
206 sym: package_sym(self.arena),
207 args: &[]
208 }
209 );
210
211 let decl: &'arena ast::Decl = alloc!(
213 self,
214 ast::Decl {
215 atom: package_atom,
216 bounds: None,
217 descr,
218 constraints: None,
219 is_temporal: false,
220 }
221 );
222 Ok(decl)
223 }
224
225 fn parse_use_decl(&mut self) -> Result<&'arena ast::Decl<'arena>> {
226 self.expect(Token::Use)?;
227 let use_atom = alloc!(
228 self,
229 ast::Atom {
230 sym: use_sym(self.arena),
231 args: &[]
232 }
233 );
234
235 let name = match &self.token {
236 Token::Ident { name } => name.as_str(),
237 _ => bail!("parse_use_decl: expected identifer got {}", self.token),
238 };
239
240 let name: &'arena str = alloc_str!(self, name);
241 let name = alloc!(self, ast::BaseTerm::Const(ast::Const::String(name)));
242 let args = alloc_slice!(self, &[name]);
243
244 let mut descr_atoms: Vec<&ast::Atom> = vec![self.arena.alloc(ast::Atom {
245 sym: name_sym(self.arena),
246 args,
247 })];
248 self.next_token()?;
249 if Token::LBracket == self.token {
250 self.parse_bracket_atoms(&mut descr_atoms)?;
251 }
252 self.expect(Token::Bang)?;
253
254 let descr_atoms = alloc_slice!(self, &descr_atoms);
255 Ok(alloc!(
256 self,
257 ast::Decl {
258 atom: use_atom,
259 descr: descr_atoms,
260 bounds: None,
261 constraints: None,
262 is_temporal: false,
263 }
264 ))
265 }
266
267 fn parse_decl(&mut self) -> Result<&'arena ast::Decl<'arena>> {
268 self.expect(Token::Decl)?;
269 let atom = self.parse_atom()?;
270 let is_temporal = match &self.token {
272 Token::Ident { name } if name == "temporal" => {
273 self.next_token()?;
274 true
275 }
276 _ => false,
277 };
278 let mut descr_atoms = vec![];
279 if Token::Descr == self.token {
280 self.next_token()?;
281 self.parse_bracket_atoms(&mut descr_atoms)?;
282 }
283 let mut bound_decls = vec![];
284 loop {
285 if Token::Bound != self.token {
286 break;
287 }
288 bound_decls.push(self.parse_bounds_decl()?);
289 }
290 let bounds = if bound_decls.is_empty() {
291 None
292 } else {
293 Some(alloc_slice!(self, &bound_decls))
294 };
295 let constraints = if Token::Inclusion == self.token {
296 Some(self.parse_inclusion_constraint()?)
297 } else {
298 None
299 };
300 self.expect(Token::Dot)?;
301 Ok(alloc!(
302 self,
303 ast::Decl {
304 atom,
305 descr: alloc_slice!(self, &descr_atoms),
306 bounds,
307 constraints,
308 is_temporal,
309 }
310 ))
311 }
312
313 fn parse_bounds_decl(&mut self) -> Result<&'arena ast::BoundDecl<'arena>> {
315 self.expect(Token::Bound)?;
316 self.expect(Token::LBracket)?;
317 let mut base_terms = vec![];
318 self.parse_base_terms(&mut base_terms)?;
319 self.expect(Token::RBracket)?;
320 let base_terms = alloc_slice!(self, &base_terms);
321 let bound_decl = alloc!(self, ast::BoundDecl { base_terms });
322 Ok(bound_decl)
323 }
324
325 fn parse_inclusion_constraint(&mut self) -> Result<&'arena ast::Constraints<'arena>> {
326 self.expect(Token::Inclusion)?;
327 let mut consequences = vec![];
328 self.parse_bracket_atoms(&mut consequences)?;
329 let consequences = alloc_slice!(self, &consequences);
330 Ok(alloc!(
331 self,
332 Constraints {
333 consequences,
334 alternatives: &[]
335 }
336 ))
337 }
338
339 pub fn parse_clause(&mut self) -> Result<&'arena ast::Clause<'arena>> {
340 let head = self.parse_atom()?;
341 let head_time = self.try_parse_interval()?;
342 let mut premises = vec![];
343 let mut transform = vec![];
344 match self.token {
345 Token::ColonDash | Token::LongLeftDoubleArrow => {
346 self.next_token()?;
347 self.parse_terms(&mut premises)?;
348 if let Token::PipeGt = self.token {
349 self.next_token()?;
350 self.parse_transforms(&mut transform)?;
351 }
352 }
353 _ => {}
354 }
355 self.expect(Token::Dot)?;
356 let premises = alloc_slice!(self, &premises);
357 let transform = alloc_slice!(self, &transform);
358 Ok(alloc!(
359 self,
360 ast::Clause {
361 head,
362 head_time,
363 premises,
364 transform,
365 }
366 ))
367 }
368
369 fn parse_terms(&mut self, terms: &mut Vec<&'arena ast::Term<'arena>>) -> Result<()> {
371 terms.push(self.parse_term()?);
372 loop {
373 if Token::Comma != self.token {
374 return Ok(());
375 }
376 self.next_token()?;
377 terms.push(self.parse_term()?);
378 }
379 }
380
381 pub fn parse_term(&mut self) -> Result<&'arena ast::Term<'arena>> {
382 match &self.token {
383 Token::Bang => {
384 self.next_token()?;
385 let atom = self.parse_atom()?;
386 Ok(alloc!(self, ast::Term::NegAtom(atom)))
387 }
388 t if base_term_start(t) => {
389 let left_base_term = self.parse_base_term()?;
390 let op = self.token.clone();
391 match op {
392 Token::Eq | Token::BangEq | Token::Lt | Token::Le | Token::Gt | Token::Ge => self.next_token()?,
393 _ => bail!("parse_terms: expected comparison operator, got {}", self.token),
394 };
395 let right_base_term = self.parse_base_term()?;
396 let term = match op {
397 Token::Eq => ast::Term::Eq(left_base_term, right_base_term),
398 Token::BangEq => ast::Term::Ineq(left_base_term, right_base_term),
399 Token::Lt => ast::Term::Atom(alloc!(
400 self,
401 ast::Atom {
402 sym: lt_sym(self.arena),
403 args: alloc_slice!(self, &[left_base_term, right_base_term]),
404 }
405 )),
406 Token::Le => ast::Term::Atom(self.arena.alloc(ast::Atom {
407 sym: le_sym(self.arena),
408 args: alloc_slice!(self, &[left_base_term, right_base_term]),
409 })),
410 Token::Gt => ast::Term::Atom(alloc!(
411 self,
412 ast::Atom {
413 sym: gt_sym(self.arena),
414 args: alloc_slice!(self, &[left_base_term, right_base_term]),
415 }
416 )),
417 Token::Ge => ast::Term::Atom(self.arena.alloc(ast::Atom {
418 sym: ge_sym(self.arena),
419 args: alloc_slice!(self, &[left_base_term, right_base_term]),
420 })),
421 _ => unreachable!(),
422 };
423 Ok(alloc!(self, term))
424 }
425 Token::Ident { .. } => {
426 let atom = self.parse_atom()?;
427 if let Some(interval) = self.try_parse_interval()? {
428 Ok(alloc!(self, ast::Term::TemporalAtom(atom, interval)))
429 } else {
430 Ok(alloc!(self, ast::Term::Atom(atom)))
431 }
432 }
433 _ => bail!("parse_term: unexpected token {:?}", self.token),
434 }
435 }
436
437 fn parse_bracket_atoms(&mut self, atoms: &mut Vec<&'arena ast::Atom<'arena>>) -> Result<()> {
439 self.expect(Token::LBracket)?;
440 self.parse_atoms(atoms)?;
441 self.expect(Token::RBracket)?;
442 Ok(())
443 }
444
445 fn parse_atoms(&mut self, atoms: &mut Vec<&'arena ast::Atom<'arena>>) -> Result<()> {
447 if let Token::Ident { .. } = self.token {
448 atoms.push(self.parse_atom()?);
449 loop {
450 if Token::Comma != self.token {
451 break;
452 }
453 self.next_token()?;
454 let atom = self.parse_atom()?;
455 atoms.push(atom);
456 }
457 }
458 Ok(())
459 }
460
461 pub fn parse_atom(&mut self) -> Result<&'arena ast::Atom<'arena>> {
464 let mut name_buf = match &self.token {
465 Token::Ident { name } => name.clone(),
466 _ => bail!("parse_atom: expected identifer got {}", self.token),
467 };
468
469 self.next_token()?;
470
471 while self.token == Token::Dot {
473 self.next_token()?;
477 match &self.token {
478 Token::Ident { name: next_name } => {
479 name_buf.push('.');
480 name_buf.push_str(next_name);
481 self.next_token()?;
482 }
483 _ => {
484 bail!(
490 "parse_atom: expected identifier after `.` in qualified name, got {}",
491 self.token
492 );
493 }
494 }
495 }
496
497 let name = self.arena.alloc_str(&name_buf);
498
499 self.expect(Token::LParen)?;
500 let mut args = vec![];
501 if Token::RParen != self.token {
502 self.parse_base_terms(&mut args)?;
503 }
504 self.expect(Token::RParen)?;
505 let args = alloc_slice!(self, &args);
506 Ok(alloc!(
507 self,
508 ast::Atom {
509 sym: self.arena.predicate_sym(name, None),
510 args
511 }
512 ))
513 }
514
515 fn parse_transforms(
516 &mut self,
517 transforms: &mut Vec<&'arena ast::TransformStmt<'arena>>,
518 ) -> Result<()> {
519 if Token::Do == self.token {
520 self.next_token()?;
521 let expr = self.parse_base_term()?;
522 transforms.push(alloc!(
523 self,
524 ast::TransformStmt {
525 var: None,
526 app: expr
527 }
528 ));
529 self.expect(Token::Semi)?;
530 }
531 loop {
532 if Token::Let != self.token {
533 break;
534 }
535 self.next_token()?;
536 if let Token::Ident { name } = &self.token {
537 let name = alloc_str!(self, name.as_str());
538 self.next_token()?;
539 self.expect(Token::Eq)?;
540 let expr = self.parse_base_term()?;
541 transforms.push(alloc!(
542 self,
543 ast::TransformStmt {
544 var: Some(name),
545 app: expr
546 }
547 ))
548 }
549 if let Token::Dot = self.token {
550 break;
551 }
552 self.expect(Token::Semi)?;
553 }
554 Ok(())
555 }
556
557 fn try_parse_interval(&mut self) -> Result<Option<ast::Interval>> {
563 if self.token != Token::At {
564 return Ok(None);
565 }
566 self.next_token()?; self.expect(Token::LBracket)?;
568 let start = self.parse_temporal_bound(true)?;
569 let end = if self.token == Token::Comma {
570 self.next_token()?;
571 self.parse_temporal_bound(false)?
572 } else {
573 start
575 };
576 self.expect(Token::RBracket)?;
577 Ok(Some(ast::Interval { start, end }))
578 }
579
580 fn parse_temporal_bound(&mut self, is_start: bool) -> Result<ast::TemporalBound> {
582 match &self.token {
583 Token::Timestamp { nanos } => {
584 let nanos = *nanos;
585 self.next_token()?;
586 Ok(ast::TemporalBound::Timestamp(nanos))
587 }
588 Token::Ident { name } if name == "_" => {
589 self.next_token()?;
590 if is_start {
591 Ok(ast::TemporalBound::NegInf)
592 } else {
593 Ok(ast::TemporalBound::PosInf)
594 }
595 }
596 Token::Ident { name } if is_variable(name) => {
597 let var_idx = self.arena.variable_sym(name);
598 self.next_token()?;
599 Ok(ast::TemporalBound::Variable(var_idx))
600 }
601 _ => bail!("parse_temporal_bound: expected timestamp, variable, or '_', got {:?}", self.token),
602 }
603 }
604
605 pub fn parse_base_term(&mut self) -> Result<&'arena ast::BaseTerm<'arena>> {
615 match &self.token {
616 Token::LBracket => return self.parse_list_or_map(),
617 Token::LBrace => return self.parse_struct(),
618 _ => {}
619 }
620
621 let mut is_type = false;
622 let mut base_term = match &self.token {
623 Token::Ident { name } if name == "_" => {
624 let unique = format!("_Anon{}", self.anon_counter);
625 self.anon_counter += 1;
626 ast::BaseTerm::Variable(self.arena.variable_sym(&unique))
627 }
628 Token::Ident { name } if is_variable(name) => {
629 ast::BaseTerm::Variable(self.arena.variable_sym(name))
630 }
631 Token::Ident { name } if is_fn(name) => {
632 let name = self.arena.alloc_str(name);
633 ast::BaseTerm::ApplyFn(self.arena.function_sym(name, None), &[])
635 }
636 Token::DotIdent { name } => {
637 let name = self.arena.alloc_str(name);
638 is_type = true;
639 ast::BaseTerm::ApplyFn(self.arena.function_sym(name, None), &[])
641 }
642 Token::String { decoded } => {
643 let value = self.arena.alloc_str(decoded.as_str());
644 ast::BaseTerm::Const(ast::Const::String(value))
645 }
646 Token::Bytes { decoded } => {
647 let value = self.arena.alloc_slice_copy(decoded);
648 ast::BaseTerm::Const(ast::Const::Bytes(value))
649 }
650 Token::Int { decoded } => ast::BaseTerm::Const(ast::Const::Number(*decoded)),
651 Token::Float { decoded } => ast::BaseTerm::Const(ast::Const::Float(*decoded)),
652 Token::Timestamp { nanos } => ast::BaseTerm::Const(ast::Const::Time(*nanos)),
653 Token::Duration { nanos } => ast::BaseTerm::Const(ast::Const::Duration(*nanos)),
654 Token::Name { name } => {
655 let name = self.arena.intern(name);
656 ast::BaseTerm::Const(ast::Const::Name(name))
657 }
658 _ => bail!("parse_base_term: unexpected token {:?}", self.token),
659 };
660 self.next_token()?;
661 if let ast::BaseTerm::ApplyFn(fn_sym, _) = base_term {
662 let mut fn_args = vec![];
663 if is_type {
664 self.parse_langle_base_terms(&mut fn_args)?;
665 } else {
666 self.parse_paren_base_terms(&mut fn_args)?;
667 }
668 let fn_args = self.arena.alloc_slice_copy(&fn_args);
669 base_term = ast::BaseTerm::ApplyFn(fn_sym, fn_args);
670 }
671 let base_term = alloc!(self, base_term);
672 Ok(base_term)
673 }
674
675 fn parse_list_or_map(&mut self) -> Result<&'arena ast::BaseTerm<'arena>> {
676 self.expect(Token::LBracket)?;
677 if Token::RBracket == self.token {
678 self.next_token()?;
679 return Ok(alloc!(
680 self,
681 ast::BaseTerm::ApplyFn(fn_list_sym(self.arena), &[])
682 ));
683 }
684 let first = self.parse_base_term()?;
685 let expr = if Token::Colon != self.token {
686 self.expect(Token::Comma)?;
687 let mut items = vec![first];
688 self.parse_base_terms(&mut items)?;
689 ast::BaseTerm::ApplyFn(fn_list_sym(self.arena), alloc_slice!(self, &items))
690 } else {
691 self.expect(Token::Colon)?; let first_val = self.parse_base_term()?;
693 let mut items = vec![first, first_val];
694 loop {
695 if Token::Comma != self.token {
696 break;
697 }
698 self.next_token()?;
699 if Token::RBracket == self.token {
700 break; }
702 items.push(self.parse_base_term()?);
703 self.expect(Token::Colon)?;
704 items.push(self.parse_base_term()?);
705 }
706 ast::BaseTerm::ApplyFn(fn_map_sym(self.arena), alloc_slice!(self, &items))
707 };
708 self.expect(Token::RBracket)?;
709 Ok(alloc!(self, expr))
710 }
711
712 fn parse_struct(&mut self) -> Result<&'arena ast::BaseTerm<'arena>> {
713 self.expect(Token::LBrace)?;
714 if Token::RBrace == self.token {
715 self.next_token()?;
716 return Ok(alloc!(
717 self,
718 ast::BaseTerm::ApplyFn(fn_struct_sym(self.arena), &[])
719 ));
720 }
721 let mut items = vec![];
722 let name = self.parse_base_term()?;
723 if let ast::BaseTerm::Const(ast::Const::Name { .. }) = name {
724 items.push(name)
725 } else {
726 bail!("parse_base_term: expected name in struct expression {{ ... }} got {name:?}",);
727 }
728 self.expect(Token::Colon)?;
729 items.push(self.parse_base_term()?);
730 loop {
731 if Token::Comma != self.token {
732 break;
733 }
734 self.next_token()?;
735 if Token::RBrace == self.token {
736 break; }
738 let name = self.parse_base_term()?;
739 if let ast::BaseTerm::Const(ast::Const::Name { .. }) = name {
740 items.push(name)
741 } else {
742 bail!("parse_base_term: expected name in struct expression {{ ... }} got {name:?}");
743 }
744 self.expect(Token::Colon)?;
745 items.push(self.parse_base_term()?);
746 }
747 self.expect(Token::RBrace)?;
748 Ok(alloc!(
749 self,
750 ast::BaseTerm::ApplyFn(fn_struct_sym(self.arena), alloc_slice!(self, &items))
751 ))
752 }
753
754 fn parse_langle_base_terms(
756 &mut self,
757 base_terms: &mut Vec<&'arena ast::BaseTerm<'arena>>,
758 ) -> Result<()> {
759 self.expect(Token::Lt)?;
760 if Token::Gt != self.token {
761 self.parse_base_terms(base_terms)?;
762 }
763 self.expect(Token::Gt)?;
764 Ok(())
765 }
766
767 fn parse_paren_base_terms(
769 &mut self,
770 base_terms: &mut Vec<&'arena ast::BaseTerm<'arena>>,
771 ) -> Result<()> {
772 self.expect(Token::LParen)?;
773 if Token::RParen != self.token {
774 self.parse_base_terms(base_terms)?;
775 }
776 self.expect(Token::RParen)?;
777 Ok(())
778 }
779
780 fn parse_base_terms(
782 &mut self,
783 base_terms: &mut Vec<&'arena ast::BaseTerm<'arena>>,
784 ) -> Result<()> {
785 base_terms.push(self.parse_base_term()?);
786 while let Token::Comma = self.token {
787 self.next_token()?;
788 if !base_term_start(&self.token) {
789 break; }
791 base_terms.push(self.parse_base_term()?);
792 }
793
794 Ok(())
795 }
796}
797
798fn is_variable(name: &str) -> bool {
799 name.chars().next().unwrap().is_ascii_uppercase()
800}
801
802fn is_fn(name: &str) -> bool {
803 name.starts_with("fn:")
804}
805
806fn base_term_start(t: &Token) -> bool {
807 match t {
808 Token::Name { .. }
809 | Token::Int { .. }
810 | Token::Float { .. }
811 | Token::String { .. }
812 | Token::Bytes { .. }
813 | Token::Timestamp { .. }
814 | Token::Duration { .. }
815 | Token::LBracket
816 | Token::LBrace
817 | Token::DotIdent { .. } => true,
818 Token::Ident { name } => is_variable(name) || is_fn(name) || name == "_",
819 _ => false,
820 }
821}
822
823#[cfg(test)]
824mod test {
825
826 use super::*;
827 use googletest::prelude::{eq, gtest, verify_that};
828
829 fn make_parser<'arena>(
830 arena: &'arena Arena,
831 input: &'arena str,
832 ) -> Parser<'arena, &'arena [u8]> {
833 let mut p = Parser::new(arena, input.as_bytes(), "test");
834 p.next_token().unwrap();
835 p
836 }
837
838 #[test]
839 fn test_empty_unit() -> Result<()> {
840 let arena = Arena::new_with_global_interner();
841 let mut p = make_parser(&arena, "");
842 match p.parse_unit()? {
843 &ast::Unit { decls: &[pkg], .. } => {
844 assert_eq!(pkg, &empty_package_decl(&arena));
845 }
846 z => panic!("unexpected: {:?}", z),
847 }
848 Ok(())
849 }
850
851 #[test]
852 fn test_package_use() -> Result<()> {
853 let arena = Arena::new_with_global_interner();
854 let input = "Package foo[bar()]! Use baz[bar()]!";
855
856 let mut p = make_parser(&arena, input);
857 let unit = p.parse_unit()?;
858 match unit.decls {
859 &[
860 &ast::Decl {
861 atom:
862 &ast::Atom {
863 sym: got_package_sym,
864 ..
865 },
866 descr:
867 &[
868 &ast::Atom {
869 sym: got_name_sym1,
870 args: &[ast::BaseTerm::Const(ast::Const::String("foo"))],
871 },
872 &ast::Atom {
873 sym: got_bar_sym1,
874 args: &[],
875 },
876 ],
877 ..
878 },
879 &ast::Decl {
880 atom:
881 &ast::Atom {
882 sym: got_use_sym, ..
883 },
884 descr:
885 &[
886 &ast::Atom {
887 sym: got_name_sym2,
888 args: &[ast::BaseTerm::Const(ast::Const::String("baz"))],
889 },
890 &ast::Atom {
891 sym: got_bar_sym2,
892 args: &[],
893 },
894 ],
895 ..
896 },
897 ] => {
898 assert_eq!(got_use_sym, use_sym(&arena));
899 assert_eq!(got_package_sym, package_sym(&arena));
900 assert_eq!(got_name_sym1, name_sym(&arena));
901 assert_eq!(got_name_sym2, name_sym(&arena));
902 assert_eq!(got_bar_sym1, arena.predicate_sym("bar", None));
903 assert_eq!(got_bar_sym2, arena.predicate_sym("bar", None));
904 }
905 z => panic!("unexpected {z:?}"),
906 }
907 Ok(())
908 }
909
910 #[test]
911 fn test_decl() -> Result<()> {
912 let arena = Arena::new_with_global_interner();
913 let input = "Decl foo(X, Y).";
914 let mut p = make_parser(&arena, input);
915 match p.parse_decl()? {
916 &ast::Decl {
917 atom:
918 &ast::Atom {
919 sym: got_foo_sym,
920 args:
921 &[
922 &ast::BaseTerm::Variable(x_sym),
923 &ast::BaseTerm::Variable(y_sym),
924 ],
925 },
926 ..
927 } => {
928 assert_eq!(got_foo_sym, arena.predicate_sym("foo", None));
929 assert_eq!(x_sym, arena.variable_sym("X"));
930 assert_eq!(y_sym, arena.variable_sym("Y"))
931 }
932 decl => panic!("got {:?}", decl),
933 };
934 Ok(())
935 }
936
937 #[test]
938 fn test_base_term() -> googletest::Result<()> {
939 let arena = Arena::new_with_global_interner();
940 let input = "X 3 1.5 'foo' /foo fn:list() fn:list(/a) fn:list(/a, 3)"; let mut p = make_parser(&arena, input);
942 let mut got_base_terms = vec![];
943 loop {
944 if Token::Eof == p.token {
945 break;
946 }
947 let base_term = p.parse_base_term().unwrap();
949 got_base_terms.push(base_term);
950 }
951 let expected = vec![
952 arena.variable("X"),
953 arena.const_(ast::Const::Number(3)),
954 arena.const_(ast::Const::Float(1.5)),
955 arena.const_(ast::Const::String("foo")),
956 arena.const_(arena.name("/foo")),
957 arena.apply_fn(fn_list_sym(&arena), &[]),
958 arena.apply_fn(fn_list_sym(&arena), &[arena.const_(arena.name("/a"))]),
959 arena.apply_fn(
960 fn_list_sym(&arena),
961 &[
962 arena.const_(arena.name("/a")),
963 arena.const_(ast::Const::Number(3)),
964 ],
965 ),
966 ];
967 verify_that!(got_base_terms, eq(&expected))
968 }
969
970 #[test]
971 fn test_term() -> googletest::Result<()> {
972 let arena = Arena::new_with_global_interner();
973 let input = "foo(/bar) !bar() X = Z X != 3 3 < 1 3 <= 1";
974 let mut p = make_parser(&arena, input);
975 let mut got_terms = vec![];
976 loop {
977 if Token::Eof == p.token {
978 break;
979 }
980 got_terms.push(p.parse_term().unwrap());
982 }
983 let expected = [
984 &ast::Term::Atom(arena.atom(
985 arena.predicate_sym("foo", None),
986 &[arena.const_(arena.name("/bar"))],
987 )),
988 &ast::Term::NegAtom(arena.atom(arena.predicate_sym("bar", None), &[])),
989 &ast::Term::Eq(arena.variable("X"), arena.variable("Z")),
990 &ast::Term::Ineq(
991 arena.variable("X"),
992 arena.alloc(ast::BaseTerm::Const(ast::Const::Number(3))),
993 ),
994 &ast::Term::Atom(arena.atom(
995 arena.predicate_sym(":lt", Some(2)),
996 &[
997 arena.const_(ast::Const::Number(3)),
998 arena.const_(ast::Const::Number(1)),
999 ],
1000 )),
1001 &ast::Term::Atom(arena.atom(
1002 arena.predicate_sym(":le", Some(2)),
1003 &[
1004 arena.const_(ast::Const::Number(3)),
1005 arena.const_(ast::Const::Number(1)),
1006 ],
1007 )),
1008 ];
1009 verify_that!(got_terms, eq(&expected))
1010 }
1011
1012 #[gtest]
1013 fn test_structured_data_and_types() -> googletest::Result<()> {
1014 let arena = Arena::new_with_global_interner();
1015 let input =
1016 "[] [1,2,3] [1: 'one', 2: 'two'] {} {/foo: /bar} {/name: \"alice\", /age: 30} .List<.Option</name>, /string>";
1017 let mut p = make_parser(&arena, input);
1018 let mut got_base_terms = vec![];
1019 loop {
1020 if Token::Eof == p.token {
1021 break;
1022 }
1023 let base_term = p.parse_base_term().unwrap();
1025 got_base_terms.push(base_term);
1026 }
1027 let expected = vec![
1028 arena.apply_fn(fn_list_sym(&arena), &[]),
1029 arena.apply_fn(
1030 fn_list_sym(&arena),
1031 &[
1032 arena.const_(ast::Const::Number(1)),
1033 arena.const_(ast::Const::Number(2)),
1034 arena.const_(ast::Const::Number(3)),
1035 ],
1036 ),
1037 arena.apply_fn(
1038 fn_map_sym(&arena),
1039 &[
1040 arena.const_(ast::Const::Number(1)),
1041 arena.const_(ast::Const::String("one")),
1042 arena.const_(ast::Const::Number(2)),
1043 arena.const_(ast::Const::String("two")),
1044 ],
1045 ),
1046 arena.apply_fn(fn_struct_sym(&arena), &[]),
1047 arena.apply_fn(
1048 fn_struct_sym(&arena),
1049 &[
1050 arena.const_(arena.name("/foo")),
1051 arena.const_(arena.name("/bar")),
1052 ],
1053 ),
1054 arena.apply_fn(
1055 fn_struct_sym(&arena),
1056 &[
1057 arena.const_(arena.name("/name")),
1058 arena.const_(ast::Const::String("alice")),
1059 arena.const_(arena.name("/age")),
1060 arena.const_(ast::Const::Number(30)),
1061 ],
1062 ),
1063 arena.apply_fn(
1064 fn_list_type_sym(&arena),
1065 &[
1066 arena.apply_fn(
1067 fn_option_type_sym(&arena),
1068 &[arena.const_(arena.name("/name"))],
1069 ),
1070 arena.const_(arena.name("/string")),
1071 ],
1072 ),
1073 ];
1074 verify_that!(got_base_terms, eq(&expected))
1075 }
1076
1077 #[gtest]
1078 fn test_trailing_commas() -> googletest::Result<()> {
1079 let arena = Arena::new_with_global_interner();
1080 let input = "[1, 2, 3,] [1: 'one', 2: 'two',] {/a: 1, /b: 2,}";
1081 let mut p = make_parser(&arena, input);
1082 let mut got_base_terms = vec![];
1083 loop {
1084 if Token::Eof == p.token {
1085 break;
1086 }
1087 let base_term = p.parse_base_term().unwrap();
1088 got_base_terms.push(base_term);
1089 }
1090 let expected = vec![
1091 arena.apply_fn(
1092 fn_list_sym(&arena),
1093 &[
1094 arena.const_(ast::Const::Number(1)),
1095 arena.const_(ast::Const::Number(2)),
1096 arena.const_(ast::Const::Number(3)),
1097 ],
1098 ),
1099 arena.apply_fn(
1100 fn_map_sym(&arena),
1101 &[
1102 arena.const_(ast::Const::Number(1)),
1103 arena.const_(ast::Const::String("one")),
1104 arena.const_(ast::Const::Number(2)),
1105 arena.const_(ast::Const::String("two")),
1106 ],
1107 ),
1108 arena.apply_fn(
1109 fn_struct_sym(&arena),
1110 &[
1111 arena.const_(arena.name("/a")),
1112 arena.const_(ast::Const::Number(1)),
1113 arena.const_(arena.name("/b")),
1114 arena.const_(ast::Const::Number(2)),
1115 ],
1116 ),
1117 ];
1118 verify_that!(got_base_terms, eq(&expected))
1119 }
1120
1121 #[test]
1122 fn test_clause() -> Result<()> {
1123 let arena = Arena::new_with_global_interner();
1124 let mut p = make_parser(&arena, "foo(X).");
1125 let clause = p.parse_clause()?;
1126 match clause {
1127 &ast::Clause {
1128 head:
1129 &ast::Atom {
1130 args: &[ast::BaseTerm::Variable(x_sym)],
1131 ..
1132 },
1133 premises: &[],
1134 transform: &[],
1135 ..
1136 } => {
1137 assert_eq!(*x_sym, arena.variable_sym("X"));
1138 assert_eq!(clause.head.sym, arena.predicate_sym("foo", None));
1139 }
1140 _ => panic!("unexpected: {:?}", clause),
1141 }
1142 let mut p = make_parser(&arena, "foo(X) :- !bar(X).");
1143 let clause = p.parse_clause()?;
1144 match clause {
1145 &ast::Clause {
1146 head:
1147 &ast::Atom {
1148 sym: foo_sym,
1149 args: _,
1150 },
1151 premises:
1152 &[
1153 &ast::Term::NegAtom(&ast::Atom {
1154 sym: bar_sym,
1155 args: _,
1156 }),
1157 ],
1158 transform: &[],
1159 ..
1160 } => {
1161 assert_eq!(foo_sym, arena.predicate_sym("foo", None));
1162 assert_eq!(bar_sym, arena.predicate_sym("bar", None));
1163 }
1164 _ => panic!("unexpected: {:?}", clause),
1165 };
1166 let mut p = make_parser(
1167 &arena,
1168 "foo(Z) ⟸ bar(Y) |> do fn:group_by(); let X = fn:count(Y).",
1169 );
1170
1171 let clause = p.parse_clause()?;
1172 match clause {
1173 &ast::Clause {
1174 head: &ast::Atom { .. },
1175 premises: &[&ast::Term::Atom(ast::Atom { .. })],
1176 transform:
1177 &[
1178 &ast::TransformStmt {
1179 var: None,
1180 app: ast::BaseTerm::ApplyFn(first_sym, _),
1181 },
1182 &ast::TransformStmt {
1183 var: Some("X"),
1184 app: ast::BaseTerm::ApplyFn(second_sym, _),
1185 },
1186 ],
1187 ..
1188 } => {
1189 assert_eq!(clause.head.sym, arena.predicate_sym("foo", None));
1190 assert_eq!(clause.transform.len(), 2);
1191 assert_eq!(*first_sym, arena.function_sym("fn:group_by", None));
1192 assert_eq!(*second_sym, arena.function_sym("fn:count", None));
1193 }
1194 _ => panic!("unexpected: {:?}", clause),
1195 }
1196
1197 Ok(())
1198 }
1199
1200 #[test]
1201 fn test_anonymous_variable_single() -> Result<()> {
1202 let arena = Arena::new_with_global_interner();
1203 let mut p = make_parser(&arena, "foo(_, X).");
1204 let clause = p.parse_clause()?;
1205 match clause.head.args {
1207 &[&ast::BaseTerm::Variable(anon), &ast::BaseTerm::Variable(x)] => {
1208 assert_eq!(anon, arena.variable_sym("_Anon0"));
1209 assert_eq!(x, arena.variable_sym("X"));
1210 }
1211 _ => panic!("unexpected args: {:?}", clause.head.args),
1212 }
1213 Ok(())
1214 }
1215
1216 #[test]
1217 fn test_anonymous_variable_multiple_distinct() -> Result<()> {
1218 let arena = Arena::new_with_global_interner();
1219 let mut p = make_parser(&arena, "foo(_, _, _).");
1220 let clause = p.parse_clause()?;
1221 match clause.head.args {
1223 &[
1224 &ast::BaseTerm::Variable(a0),
1225 &ast::BaseTerm::Variable(a1),
1226 &ast::BaseTerm::Variable(a2),
1227 ] => {
1228 assert_eq!(a0, arena.variable_sym("_Anon0"));
1229 assert_eq!(a1, arena.variable_sym("_Anon1"));
1230 assert_eq!(a2, arena.variable_sym("_Anon2"));
1231 assert_ne!(a0, a1);
1233 assert_ne!(a1, a2);
1234 }
1235 _ => panic!("unexpected args: {:?}", clause.head.args),
1236 }
1237 Ok(())
1238 }
1239
1240 #[test]
1241 fn test_anonymous_variable_in_rule_body() -> Result<()> {
1242 let arena = Arena::new_with_global_interner();
1243 let mut p = make_parser(&arena, "result(X) :- foo(X, _).");
1244 let clause = p.parse_clause()?;
1245 assert_eq!(clause.head.sym, arena.predicate_sym("result", None));
1246 match clause.premises {
1247 &[&ast::Term::Atom(&ast::Atom { args, .. })] => match args {
1248 &[&ast::BaseTerm::Variable(x), &ast::BaseTerm::Variable(anon)] => {
1249 assert_eq!(x, arena.variable_sym("X"));
1250 assert_eq!(anon, arena.variable_sym("_Anon0"));
1251 }
1252 _ => panic!("unexpected args: {:?}", args),
1253 },
1254 _ => panic!("unexpected premises: {:?}", clause.premises),
1255 }
1256 Ok(())
1257 }
1258
1259 #[test]
1260 fn test_anonymous_variable_with_negation() -> Result<()> {
1261 let arena = Arena::new_with_global_interner();
1262 let mut p = make_parser(&arena, "orphan(X) :- node(X, _), !has_parent(X).");
1263 let clause = p.parse_clause()?;
1264 assert_eq!(clause.head.sym, arena.predicate_sym("orphan", None));
1265 assert_eq!(clause.premises.len(), 2);
1266 match clause.premises[0] {
1268 &ast::Term::Atom(&ast::Atom { args, .. }) => match args {
1269 &[&ast::BaseTerm::Variable(_), &ast::BaseTerm::Variable(anon)] => {
1270 assert_eq!(anon, arena.variable_sym("_Anon0"));
1271 }
1272 _ => panic!("unexpected args: {:?}", args),
1273 },
1274 _ => panic!("expected Atom, got {:?}", clause.premises[0]),
1275 }
1276 match clause.premises[1] {
1278 &ast::Term::NegAtom(&ast::Atom { sym, .. }) => {
1279 assert_eq!(sym, arena.predicate_sym("has_parent", None));
1280 }
1281 _ => panic!("expected NegAtom, got {:?}", clause.premises[1]),
1282 }
1283 Ok(())
1284 }
1285
1286 #[test]
1292 fn test_temporal_fact_with_interval() -> Result<()> {
1293 let arena = Arena::new_with_global_interner();
1294 let mut p = make_parser(&arena, "foo(/bar)@[2024-01-15, 2024-06-30].");
1295 let clause = p.parse_clause()?;
1296 assert!(clause.head_time.is_some(), "expected temporal annotation");
1297 let interval = clause.head_time.unwrap();
1298 match interval.start {
1299 ast::TemporalBound::Timestamp(_) => {}
1300 _ => panic!("expected Timestamp start, got {:?}", interval.start),
1301 }
1302 match interval.end {
1303 ast::TemporalBound::Timestamp(_) => {}
1304 _ => panic!("expected Timestamp end, got {:?}", interval.end),
1305 }
1306 Ok(())
1307 }
1308
1309 #[test]
1311 fn test_temporal_fact_point_interval() -> Result<()> {
1312 let arena = Arena::new_with_global_interner();
1313 let mut p = make_parser(&arena, "event(/login)@[2024-03-15].");
1314 let clause = p.parse_clause()?;
1315 assert!(clause.head_time.is_some(), "expected temporal annotation");
1316 let interval = clause.head_time.unwrap();
1317 assert_eq!(interval.start, interval.end);
1319 Ok(())
1320 }
1321
1322 #[test]
1324 fn test_non_temporal_fact() -> Result<()> {
1325 let arena = Arena::new_with_global_interner();
1326 let mut p = make_parser(&arena, "regular(/fact).");
1327 let clause = p.parse_clause()?;
1328 assert!(clause.head_time.is_none(), "non-temporal fact should have no annotation");
1329 Ok(())
1330 }
1331
1332 #[test]
1334 fn test_temporal_declaration() -> Result<()> {
1335 let arena = Arena::new_with_global_interner();
1336 let mut p = make_parser(&arena, "Decl employee(X) temporal bound [/name].");
1337 let unit = p.parse_unit()?;
1338 assert_eq!(unit.decls.len(), 2);
1340 assert!(unit.decls[1].is_temporal, "expected temporal declaration");
1341 Ok(())
1342 }
1343
1344 #[test]
1346 fn test_non_temporal_declaration() -> Result<()> {
1347 let arena = Arena::new_with_global_interner();
1348 let mut p = make_parser(&arena, "Decl config(X) bound [/string].");
1349 let unit = p.parse_unit()?;
1350 assert_eq!(unit.decls.len(), 2);
1351 assert!(!unit.decls[1].is_temporal, "expected non-temporal declaration");
1352 Ok(())
1353 }
1354
1355 #[test]
1357 fn test_temporal_declaration_with_descr() -> Result<()> {
1358 let arena = Arena::new_with_global_interner();
1359 let input = r#"Decl status(X, Y) temporal
1360 descr [doc("Employee status over time")]
1361 bound [/name, /string]."#;
1362 let mut p = make_parser(&arena, input);
1363 let unit = p.parse_unit()?;
1364 assert_eq!(unit.decls.len(), 2);
1365 assert!(unit.decls[1].is_temporal, "expected temporal declaration");
1366 Ok(())
1367 }
1368
1369 #[test]
1371 fn test_backward_compat_no_temporal() -> Result<()> {
1372 let programs = [
1374 "edge(/a, /b). path(X, Y) :- edge(X, Y).",
1375 "all(/a). excluded(/a). included(X) :- all(X), !excluded(X).",
1376 "age(/alice, 30). adult(Name) :- age(Name, Age), Age >= 18 .",
1377 ];
1378 for prog in &programs {
1379 let arena = Arena::new_with_global_interner();
1380 let mut p = make_parser(&arena, prog);
1381 let unit = p.parse_unit()?;
1382 for clause in unit.clauses {
1383 assert!(clause.head_time.is_none(), "clause should not have temporal annotation in: {prog}");
1384 }
1385 }
1386 Ok(())
1387 }
1388
1389 #[test]
1391 fn test_temporal_rule_with_variable_interval() -> Result<()> {
1392 let arena = Arena::new_with_global_interner();
1393 let mut p = make_parser(&arena, "reachable(X, Y)@[T] :- link(X, Y)@[T].");
1394 let clause = p.parse_clause()?;
1395 assert!(clause.head_time.is_some());
1397 let interval = clause.head_time.unwrap();
1398 match interval.start {
1399 ast::TemporalBound::Variable(_) => {}
1400 _ => panic!("expected Variable start, got {:?}", interval.start),
1401 }
1402 assert_eq!(interval.start, interval.end);
1404 assert_eq!(clause.premises.len(), 1);
1406 match clause.premises[0] {
1407 ast::Term::TemporalAtom(_, _) => {}
1408 _ => panic!("expected TemporalAtom, got {:?}", clause.premises[0]),
1409 }
1410 Ok(())
1411 }
1412
1413 #[test]
1415 fn test_temporal_rule_with_interval_range() -> Result<()> {
1416 let arena = Arena::new_with_global_interner();
1417 let mut p = make_parser(&arena, "reachable(X, Y)@[S, E] :- link(X, Y)@[S, E].");
1418 let clause = p.parse_clause()?;
1419 let interval = clause.head_time.unwrap();
1420 match interval.start {
1421 ast::TemporalBound::Variable(v) => {
1422 assert_eq!(arena.lookup_name(v.0).unwrap(), "S");
1423 }
1424 _ => panic!("expected Variable start"),
1425 }
1426 match interval.end {
1427 ast::TemporalBound::Variable(v) => {
1428 assert_eq!(arena.lookup_name(v.0).unwrap(), "E");
1429 }
1430 _ => panic!("expected Variable end"),
1431 }
1432 Ok(())
1433 }
1434
1435 #[test]
1437 fn test_temporal_wildcard_bounds() -> Result<()> {
1438 let arena = Arena::new_with_global_interner();
1439 let mut p = make_parser(&arena, "always(/true)@[_, _].");
1440 let clause = p.parse_clause()?;
1441 let interval = clause.head_time.unwrap();
1442 assert_eq!(interval.start, ast::TemporalBound::NegInf);
1443 assert_eq!(interval.end, ast::TemporalBound::PosInf);
1444 Ok(())
1445 }
1446}