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 fn_list_sym(arena: &Arena) -> ast::FunctionIndex {
59 arena.function_sym("fn:list", None)
60}
61
62fn fn_map_sym(arena: &Arena) -> ast::FunctionIndex {
63 arena.function_sym("fn:map", None)
64}
65
66fn fn_struct_sym(arena: &Arena) -> ast::FunctionIndex {
67 arena.function_sym("fn:struct", None)
68}
69
70fn fn_list_type_sym(arena: &Arena) -> ast::FunctionIndex {
71 arena.function_sym("fn:List", None)
72}
73
74fn fn_option_type_sym(arena: &Arena) -> ast::FunctionIndex {
75 arena.function_sym("fn:Option", None)
76}
77
78fn empty_package_decl(arena: &Arena) -> ast::Decl<'_> {
79 ast::Decl {
80 atom: arena.alloc(ast::Atom {
81 sym: package_sym(arena),
82 args: &[],
83 }),
84 descr: arena.alloc_slice_copy(&[arena.alloc(ast::Atom {
85 sym: name_sym(arena),
86 args: arena
87 .alloc_slice_copy(&[arena.alloc(ast::BaseTerm::Const(ast::Const::String("")))]),
88 })]),
89 bounds: None,
90 constraints: None,
91 }
92}
93
94macro_rules! alloc {
95 ($self:expr, $e:expr) => {
96 &*$self.arena.alloc($e)
97 };
98}
99
100macro_rules! alloc_str {
101 ($self:expr, $e:expr) => {
102 &*$self.arena.alloc_str($e)
103 };
104}
105
106macro_rules! alloc_slice {
107 ($self:expr, $e:expr) => {
108 &*$self.arena.alloc_slice_copy($e)
109 };
110}
111
112impl<'arena, R> Parser<'arena, R>
113where
114 R: io::Read,
115{
116 pub fn new<P: ToString>(arena: &'arena Arena, reader: R, path: P) -> Self
117 where
118 R: io::Read,
119 {
120 Self {
121 sc: scan::Scanner::new(reader, path),
122 token: token::Token::Illegal,
123 arena,
124 anon_counter: 0,
125 }
126 }
127
128 pub fn next_token(&mut self) -> Result<()> {
129 self.token = self.sc.next_token()?;
130 Ok(())
131 }
132
133 fn expect(&mut self, expected: Token) -> Result<()> {
135 if expected != self.token {
136 let error = ParseError::Unexpected(
137 self.sc.get_error_context(),
138 expected.clone(),
139 self.token.clone(),
140 );
141 return Err(anyhow!(error));
142 }
143 self.next_token()
144 }
145
146 pub fn parse_unit(&mut self) -> Result<&'arena ast::Unit<'arena>> {
147 let package = if matches!(self.token.clone(), Token::Package) {
148 self.parse_package_decl()?
149 } else {
150 self.arena.alloc(empty_package_decl(self.arena))
151 };
152 let mut decls = vec![package];
153 while let Token::Use = self.token {
154 decls.push(self.parse_use_decl()?);
155 }
156 let mut clauses = vec![];
157 loop {
158 match self.token {
159 Token::Eof => break,
160 Token::Decl => decls.push(self.parse_decl()?),
161 _ => clauses.push(self.parse_clause()?),
162 }
163 }
164 let decls: &'arena [&'arena ast::Decl<'arena>] = self.arena.alloc_slice_copy(&decls);
165 let clauses: &'arena [&'arena ast::Clause<'arena>] = self.arena.alloc_slice_copy(&clauses);
166 let unit: &'arena ast::Unit<'arena> = &*self.arena.alloc(ast::Unit { clauses, decls });
167 Ok(unit)
168 }
169
170 pub fn parse_package_decl(&mut self) -> Result<&'arena ast::Decl<'arena>> {
172 self.expect(Token::Package)?;
173 let package_name: &'arena str = if let Token::Ident { name } = &self.token {
174 self.arena.alloc_str(name.as_str())
175 } else {
176 bail!("expected identifer got {}", self.token);
177 };
178
179 let name_atom: &'arena ast::Atom<'arena> = self.arena.alloc(ast::Atom {
180 sym: name_sym(self.arena),
181 args: self.arena.alloc_slice_copy(&[self
182 .arena
183 .alloc(ast::BaseTerm::Const(ast::Const::String(package_name)))]),
184 });
185 let mut descr_atoms: Vec<&'arena ast::Atom<'arena>> = vec![name_atom];
186 self.next_token()?;
187 if Token::LBracket == self.token {
188 self.parse_bracket_atoms(&mut descr_atoms)?;
189 }
190 let descr = alloc_slice!(self, &descr_atoms);
191
192 self.expect(Token::Bang)?;
193
194 let package_atom = alloc!(
195 self,
196 ast::Atom {
197 sym: package_sym(self.arena),
198 args: &[]
199 }
200 );
201
202 let decl: &'arena ast::Decl = alloc!(
204 self,
205 ast::Decl {
206 atom: package_atom,
207 bounds: None,
208 descr,
209 constraints: None
210 }
211 );
212 Ok(decl)
213 }
214
215 fn parse_use_decl(&mut self) -> Result<&'arena ast::Decl<'arena>> {
216 self.expect(Token::Use)?;
217 let use_atom = alloc!(
218 self,
219 ast::Atom {
220 sym: use_sym(self.arena),
221 args: &[]
222 }
223 );
224
225 let name = match &self.token {
226 Token::Ident { name } => name.as_str(),
227 _ => bail!("parse_use_decl: expected identifer got {}", self.token),
228 };
229
230 let name: &'arena str = alloc_str!(self, name);
231 let name = alloc!(self, ast::BaseTerm::Const(ast::Const::String(name)));
232 let args = alloc_slice!(self, &[name]);
233
234 let mut descr_atoms: Vec<&ast::Atom> = vec![self.arena.alloc(ast::Atom {
235 sym: name_sym(self.arena),
236 args,
237 })];
238 self.next_token()?;
239 if Token::LBracket == self.token {
240 self.parse_bracket_atoms(&mut descr_atoms)?;
241 }
242 self.expect(Token::Bang)?;
243
244 let descr_atoms = alloc_slice!(self, &descr_atoms);
245 Ok(alloc!(
246 self,
247 ast::Decl {
248 atom: use_atom,
249 descr: descr_atoms,
250 bounds: None,
251 constraints: None
252 }
253 ))
254 }
255
256 fn parse_decl(&mut self) -> Result<&'arena ast::Decl<'arena>> {
257 self.expect(Token::Decl)?;
258 let atom = self.parse_atom()?;
259 let mut descr_atoms = vec![];
260 if Token::Descr == self.token {
261 self.next_token()?;
262 self.parse_bracket_atoms(&mut descr_atoms)?;
263 }
264 let mut bound_decls = vec![];
265 loop {
266 if Token::Bound != self.token {
267 break;
268 }
269 bound_decls.push(self.parse_bounds_decl()?);
270 }
271 let bounds = if bound_decls.is_empty() {
272 None
273 } else {
274 Some(alloc_slice!(self, &bound_decls))
275 };
276 let constraints = if Token::Inclusion == self.token {
277 Some(self.parse_inclusion_constraint()?)
278 } else {
279 None
280 };
281 self.expect(Token::Dot)?;
282 Ok(alloc!(
283 self,
284 ast::Decl {
285 atom,
286 descr: alloc_slice!(self, &descr_atoms),
287 bounds,
288 constraints
289 }
290 ))
291 }
292
293 fn parse_bounds_decl(&mut self) -> Result<&'arena ast::BoundDecl<'arena>> {
295 self.expect(Token::Bound)?;
296 self.expect(Token::LBracket)?;
297 let mut base_terms = vec![];
298 self.parse_base_terms(&mut base_terms)?;
299 self.expect(Token::RBracket)?;
300 let base_terms = alloc_slice!(self, &base_terms);
301 let bound_decl = alloc!(self, ast::BoundDecl { base_terms });
302 Ok(bound_decl)
303 }
304
305 fn parse_inclusion_constraint(&mut self) -> Result<&'arena ast::Constraints<'arena>> {
306 self.expect(Token::Inclusion)?;
307 let mut consequences = vec![];
308 self.parse_bracket_atoms(&mut consequences)?;
309 let consequences = alloc_slice!(self, &consequences);
310 Ok(alloc!(
311 self,
312 Constraints {
313 consequences,
314 alternatives: &[]
315 }
316 ))
317 }
318
319 pub fn parse_clause(&mut self) -> Result<&'arena ast::Clause<'arena>> {
320 let head = self.parse_atom()?;
321 let mut premises = vec![];
322 let mut transform = vec![];
323 match self.token {
324 Token::ColonDash | Token::LongLeftDoubleArrow => {
325 self.next_token()?;
326 self.parse_terms(&mut premises)?;
327 if let Token::PipeGt = self.token {
328 self.next_token()?;
329 self.parse_transforms(&mut transform)?;
330 }
331 }
332 _ => {}
333 }
334 self.expect(Token::Dot)?;
335 let premises = alloc_slice!(self, &premises);
336 let transform = alloc_slice!(self, &transform);
337 Ok(alloc!(
338 self,
339 ast::Clause {
340 head,
341 premises,
342 transform
343 }
344 ))
345 }
346
347 fn parse_terms(&mut self, terms: &mut Vec<&'arena ast::Term<'arena>>) -> Result<()> {
349 terms.push(self.parse_term()?);
350 loop {
351 if Token::Comma != self.token {
352 return Ok(());
353 }
354 self.next_token()?;
355 terms.push(self.parse_term()?);
356 }
357 }
358
359 pub fn parse_term(&mut self) -> Result<&'arena ast::Term<'arena>> {
360 match &self.token {
361 Token::Bang => {
362 self.next_token()?;
363 let atom = self.parse_atom()?;
364 Ok(alloc!(self, ast::Term::NegAtom(atom)))
365 }
366 t if base_term_start(t) => {
367 let left_base_term = self.parse_base_term()?;
368 let op = self.token.clone();
369 match op {
370 Token::Eq | Token::BangEq | Token::Lt | Token::Le => self.next_token()?,
371 _ => bail!("parse_terms: expected `=` or `!=` got {}", self.token),
372 };
373 let right_base_term = self.parse_base_term()?;
374 let term = match op {
375 Token::Eq => ast::Term::Eq(left_base_term, right_base_term),
376 Token::BangEq => ast::Term::Ineq(left_base_term, right_base_term),
377 Token::Lt => ast::Term::Atom(alloc!(
378 self,
379 ast::Atom {
380 sym: lt_sym(self.arena),
381 args: alloc_slice!(self, &[left_base_term, right_base_term]),
382 }
383 )),
384 Token::Le => ast::Term::Atom(self.arena.alloc(ast::Atom {
385 sym: le_sym(self.arena),
386 args: alloc_slice!(self, &[left_base_term, right_base_term]),
387 })),
388 _ => unreachable!(),
389 };
390 Ok(alloc!(self, term))
391 }
392 Token::Ident { .. } => {
393 let atom = self.parse_atom()?;
394 Ok(alloc!(self, ast::Term::Atom(atom)))
395 }
396 _ => bail!("parse_term: unexpected token {:?}", self.token),
397 }
398 }
399
400 fn parse_bracket_atoms(&mut self, atoms: &mut Vec<&'arena ast::Atom<'arena>>) -> Result<()> {
402 self.expect(Token::LBracket)?;
403 self.parse_atoms(atoms)?;
404 self.expect(Token::RBracket)?;
405 Ok(())
406 }
407
408 fn parse_atoms(&mut self, atoms: &mut Vec<&'arena ast::Atom<'arena>>) -> Result<()> {
410 if let Token::Ident { .. } = self.token {
411 atoms.push(self.parse_atom()?);
412 loop {
413 if Token::Comma != self.token {
414 break;
415 }
416 self.next_token()?;
417 let atom = self.parse_atom()?;
418 atoms.push(atom);
419 }
420 }
421 Ok(())
422 }
423
424 pub fn parse_atom(&mut self) -> Result<&'arena ast::Atom<'arena>> {
427 let mut name_buf = match &self.token {
428 Token::Ident { name } => name.clone(),
429 _ => bail!("parse_atom: expected identifer got {}", self.token),
430 };
431
432 self.next_token()?;
433
434 while self.token == Token::Dot {
436 self.next_token()?;
440 match &self.token {
441 Token::Ident { name: next_name } => {
442 name_buf.push('.');
443 name_buf.push_str(next_name);
444 self.next_token()?;
445 }
446 _ => {
447 bail!(
453 "parse_atom: expected identifier after `.` in qualified name, got {}",
454 self.token
455 );
456 }
457 }
458 }
459
460 let name = self.arena.alloc_str(&name_buf);
461
462 self.expect(Token::LParen)?;
463 let mut args = vec![];
464 if Token::RParen != self.token {
465 self.parse_base_terms(&mut args)?;
466 }
467 self.expect(Token::RParen)?;
468 let args = alloc_slice!(self, &args);
469 Ok(alloc!(
470 self,
471 ast::Atom {
472 sym: self.arena.predicate_sym(name, None),
473 args
474 }
475 ))
476 }
477
478 fn parse_transforms(
479 &mut self,
480 transforms: &mut Vec<&'arena ast::TransformStmt<'arena>>,
481 ) -> Result<()> {
482 if Token::Do == self.token {
483 self.next_token()?;
484 let expr = self.parse_base_term()?;
485 transforms.push(alloc!(
486 self,
487 ast::TransformStmt {
488 var: None,
489 app: expr
490 }
491 ));
492 self.expect(Token::Semi)?;
493 }
494 loop {
495 if Token::Let != self.token {
496 break;
497 }
498 self.next_token()?;
499 if let Token::Ident { name } = &self.token {
500 let name = alloc_str!(self, name.as_str());
501 self.next_token()?;
502 self.expect(Token::Eq)?;
503 let expr = self.parse_base_term()?;
504 transforms.push(alloc!(
505 self,
506 ast::TransformStmt {
507 var: Some(name),
508 app: expr
509 }
510 ))
511 }
512 if let Token::Dot = self.token {
513 break;
514 }
515 self.expect(Token::Semi)?;
516 }
517 Ok(())
518 }
519
520 pub fn parse_base_term(&mut self) -> Result<&'arena ast::BaseTerm<'arena>> {
528 match &self.token {
529 Token::LBracket => return self.parse_list_or_map(),
530 Token::LBrace => return self.parse_struct(),
531 _ => {}
532 }
533
534 let mut is_type = false;
535 let mut base_term = match &self.token {
536 Token::Ident { name } if name == "_" => {
537 let unique = format!("_Anon{}", self.anon_counter);
538 self.anon_counter += 1;
539 ast::BaseTerm::Variable(self.arena.variable_sym(&unique))
540 }
541 Token::Ident { name } if is_variable(name) => {
542 ast::BaseTerm::Variable(self.arena.variable_sym(name))
543 }
544 Token::Ident { name } if is_fn(name) => {
545 let name = self.arena.alloc_str(name);
546 ast::BaseTerm::ApplyFn(self.arena.function_sym(name, None), &[])
548 }
549 Token::DotIdent { name } => {
550 let name = self.arena.alloc_str(name);
551 is_type = true;
552 ast::BaseTerm::ApplyFn(self.arena.function_sym(name, None), &[])
554 }
555 Token::String { decoded } => {
556 let value = self.arena.alloc_str(decoded.as_str());
557 ast::BaseTerm::Const(ast::Const::String(value))
558 }
559 Token::Bytes { decoded } => {
560 let value = self.arena.alloc_slice_copy(decoded);
561 ast::BaseTerm::Const(ast::Const::Bytes(value))
562 }
563 Token::Int { decoded } => ast::BaseTerm::Const(ast::Const::Number(*decoded)),
564 Token::Float { decoded } => ast::BaseTerm::Const(ast::Const::Float(*decoded)),
565 Token::Name { name } => {
566 let name = self.arena.intern(name);
567 ast::BaseTerm::Const(ast::Const::Name(name))
568 }
569 _ => bail!("parse_base_term: unexpected token {:?}", self.token),
570 };
571 self.next_token()?;
572 if let ast::BaseTerm::ApplyFn(fn_sym, _) = base_term {
573 let mut fn_args = vec![];
574 if is_type {
575 self.parse_langle_base_terms(&mut fn_args)?;
576 } else {
577 self.parse_paren_base_terms(&mut fn_args)?;
578 }
579 let fn_args = self.arena.alloc_slice_copy(&fn_args);
580 base_term = ast::BaseTerm::ApplyFn(fn_sym, fn_args);
581 }
582 let base_term = alloc!(self, base_term);
583 Ok(base_term)
584 }
585
586 fn parse_list_or_map(&mut self) -> Result<&'arena ast::BaseTerm<'arena>> {
587 self.expect(Token::LBracket)?;
588 if Token::RBracket == self.token {
589 self.next_token()?;
590 return Ok(alloc!(
591 self,
592 ast::BaseTerm::ApplyFn(fn_list_sym(self.arena), &[])
593 ));
594 }
595 let first = self.parse_base_term()?;
596 let expr = if Token::Colon != self.token {
597 self.expect(Token::Comma)?;
598 let mut items = vec![first];
599 self.parse_base_terms(&mut items)?;
600 ast::BaseTerm::ApplyFn(fn_list_sym(self.arena), alloc_slice!(self, &items))
601 } else {
602 self.expect(Token::Colon)?; let first_val = self.parse_base_term()?;
604 let mut items = vec![first, first_val];
605 loop {
606 if Token::Comma != self.token {
607 break;
608 }
609 self.next_token()?;
610 items.push(self.parse_base_term()?);
611 self.expect(Token::Colon)?;
612 items.push(self.parse_base_term()?);
613 }
614 ast::BaseTerm::ApplyFn(fn_map_sym(self.arena), alloc_slice!(self, &items))
615 };
616 self.expect(Token::RBracket)?;
617 Ok(alloc!(self, expr))
618 }
619
620 fn parse_struct(&mut self) -> Result<&'arena ast::BaseTerm<'arena>> {
621 self.expect(Token::LBrace)?;
622 if Token::RBrace == self.token {
623 self.next_token()?;
624 return Ok(alloc!(
625 self,
626 ast::BaseTerm::ApplyFn(fn_struct_sym(self.arena), &[])
627 ));
628 }
629 let mut items = vec![];
630 let name = self.parse_base_term()?;
631 if let ast::BaseTerm::Const(ast::Const::Name { .. }) = name {
632 items.push(name)
633 } else {
634 bail!("parse_base_term: expected name in struct expression {{ ... }} got {name:?}",);
635 }
636 self.expect(Token::Colon)?;
637 items.push(self.parse_base_term()?);
638 loop {
639 if Token::Comma != self.token {
640 break;
641 }
642 let name = self.parse_base_term()?;
643 if let ast::BaseTerm::Const(ast::Const::Name { .. }) = name {
644 items.push(name)
645 } else {
646 bail!("parse_base_term: expected name in struct expression {{ ... }} got {name:?}");
647 }
648 self.expect(Token::Colon)?;
649 items.push(self.parse_base_term()?);
650 }
651 self.expect(Token::RBrace)?;
652 Ok(alloc!(
653 self,
654 ast::BaseTerm::ApplyFn(fn_struct_sym(self.arena), alloc_slice!(self, &items))
655 ))
656 }
657
658 fn parse_langle_base_terms(
660 &mut self,
661 base_terms: &mut Vec<&'arena ast::BaseTerm<'arena>>,
662 ) -> Result<()> {
663 self.expect(Token::Lt)?;
664 if Token::Gt != self.token {
665 self.parse_base_terms(base_terms)?;
666 }
667 self.expect(Token::Gt)?;
668 Ok(())
669 }
670
671 fn parse_paren_base_terms(
673 &mut self,
674 base_terms: &mut Vec<&'arena ast::BaseTerm<'arena>>,
675 ) -> Result<()> {
676 self.expect(Token::LParen)?;
677 if Token::RParen != self.token {
678 self.parse_base_terms(base_terms)?;
679 }
680 self.expect(Token::RParen)?;
681 Ok(())
682 }
683
684 fn parse_base_terms(
686 &mut self,
687 base_terms: &mut Vec<&'arena ast::BaseTerm<'arena>>,
688 ) -> Result<()> {
689 base_terms.push(self.parse_base_term()?);
690 while let Token::Comma = self.token {
691 self.next_token()?;
692 base_terms.push(self.parse_base_term()?);
693 }
694
695 Ok(())
696 }
697}
698
699fn is_variable(name: &str) -> bool {
700 name.chars().next().unwrap().is_ascii_uppercase()
701}
702
703fn is_fn(name: &str) -> bool {
704 name.starts_with("fn:")
705}
706
707fn base_term_start(t: &Token) -> bool {
708 match t {
709 Token::Name { .. }
710 | Token::Int { .. }
711 | Token::Float { .. }
712 | Token::String { .. }
713 | Token::Bytes { .. }
714 | Token::LBracket
715 | Token::LBrace
716 | Token::DotIdent { .. } => true,
717 Token::Ident { name } => is_variable(name) || is_fn(name),
718 _ => false,
719 }
720}
721
722#[cfg(test)]
723mod test {
724
725 use super::*;
726 use googletest::prelude::{eq, gtest, verify_that};
727
728 fn make_parser<'arena>(
729 arena: &'arena Arena,
730 input: &'arena str,
731 ) -> Parser<'arena, &'arena [u8]> {
732 let mut p = Parser::new(arena, input.as_bytes(), "test");
733 p.next_token().unwrap();
734 p
735 }
736
737 #[test]
738 fn test_empty_unit() -> Result<()> {
739 let arena = Arena::new_with_global_interner();
740 let mut p = make_parser(&arena, "");
741 match p.parse_unit()? {
742 &ast::Unit { decls: &[pkg], .. } => {
743 assert_eq!(pkg, &empty_package_decl(&arena));
744 }
745 z => panic!("unexpected: {:?}", z),
746 }
747 Ok(())
748 }
749
750 #[test]
751 fn test_package_use() -> Result<()> {
752 let arena = Arena::new_with_global_interner();
753 let input = "Package foo[bar()]! Use baz[bar()]!";
754
755 let mut p = make_parser(&arena, input);
756 let unit = p.parse_unit()?;
757 match unit.decls {
758 &[
759 &ast::Decl {
760 atom:
761 &ast::Atom {
762 sym: got_package_sym,
763 ..
764 },
765 descr:
766 &[
767 &ast::Atom {
768 sym: got_name_sym1,
769 args: &[ast::BaseTerm::Const(ast::Const::String("foo"))],
770 },
771 &ast::Atom {
772 sym: got_bar_sym1,
773 args: &[],
774 },
775 ],
776 ..
777 },
778 &ast::Decl {
779 atom:
780 &ast::Atom {
781 sym: got_use_sym, ..
782 },
783 descr:
784 &[
785 &ast::Atom {
786 sym: got_name_sym2,
787 args: &[ast::BaseTerm::Const(ast::Const::String("baz"))],
788 },
789 &ast::Atom {
790 sym: got_bar_sym2,
791 args: &[],
792 },
793 ],
794 ..
795 },
796 ] => {
797 assert_eq!(got_use_sym, use_sym(&arena));
798 assert_eq!(got_package_sym, package_sym(&arena));
799 assert_eq!(got_name_sym1, name_sym(&arena));
800 assert_eq!(got_name_sym2, name_sym(&arena));
801 assert_eq!(got_bar_sym1, arena.predicate_sym("bar", None));
802 assert_eq!(got_bar_sym2, arena.predicate_sym("bar", None));
803 }
804 z => panic!("unexpected {z:?}"),
805 }
806 Ok(())
807 }
808
809 #[test]
810 fn test_decl() -> Result<()> {
811 let arena = Arena::new_with_global_interner();
812 let input = "Decl foo(X, Y).";
813 let mut p = make_parser(&arena, input);
814 match p.parse_decl()? {
815 &ast::Decl {
816 atom:
817 &ast::Atom {
818 sym: got_foo_sym,
819 args:
820 &[
821 &ast::BaseTerm::Variable(x_sym),
822 &ast::BaseTerm::Variable(y_sym),
823 ],
824 },
825 ..
826 } => {
827 assert_eq!(got_foo_sym, arena.predicate_sym("foo", None));
828 assert_eq!(x_sym, arena.variable_sym("X"));
829 assert_eq!(y_sym, arena.variable_sym("Y"))
830 }
831 decl => panic!("got {:?}", decl),
832 };
833 Ok(())
834 }
835
836 #[test]
837 fn test_base_term() -> googletest::Result<()> {
838 let arena = Arena::new_with_global_interner();
839 let input = "X 3 1.5 'foo' /foo fn:list() fn:list(/a) fn:list(/a, 3)"; let mut p = make_parser(&arena, input);
841 let mut got_base_terms = vec![];
842 loop {
843 if Token::Eof == p.token {
844 break;
845 }
846 let base_term = p.parse_base_term().unwrap();
848 got_base_terms.push(base_term);
849 }
850 let expected = vec![
851 arena.variable("X"),
852 arena.const_(ast::Const::Number(3)),
853 arena.const_(ast::Const::Float(1.5)),
854 arena.const_(ast::Const::String("foo")),
855 arena.const_(arena.name("/foo")),
856 arena.apply_fn(fn_list_sym(&arena), &[]),
857 arena.apply_fn(fn_list_sym(&arena), &[arena.const_(arena.name("/a"))]),
858 arena.apply_fn(
859 fn_list_sym(&arena),
860 &[
861 arena.const_(arena.name("/a")),
862 arena.const_(ast::Const::Number(3)),
863 ],
864 ),
865 ];
866 verify_that!(got_base_terms, eq(&expected))
867 }
868
869 #[test]
870 fn test_term() -> googletest::Result<()> {
871 let arena = Arena::new_with_global_interner();
872 let input = "foo(/bar) !bar() X = Z X != 3 3 < 1 3 <= 1";
873 let mut p = make_parser(&arena, input);
874 let mut got_terms = vec![];
875 loop {
876 if Token::Eof == p.token {
877 break;
878 }
879 got_terms.push(p.parse_term().unwrap());
881 }
882 let expected = [
883 &ast::Term::Atom(arena.atom(
884 arena.predicate_sym("foo", None),
885 &[arena.const_(arena.name("/bar"))],
886 )),
887 &ast::Term::NegAtom(arena.atom(arena.predicate_sym("bar", None), &[])),
888 &ast::Term::Eq(arena.variable("X"), arena.variable("Z")),
889 &ast::Term::Ineq(
890 arena.variable("X"),
891 arena.alloc(ast::BaseTerm::Const(ast::Const::Number(3))),
892 ),
893 &ast::Term::Atom(arena.atom(
894 arena.predicate_sym(":lt", Some(2)),
895 &[
896 arena.const_(ast::Const::Number(3)),
897 arena.const_(ast::Const::Number(1)),
898 ],
899 )),
900 &ast::Term::Atom(arena.atom(
901 arena.predicate_sym(":le", Some(2)),
902 &[
903 arena.const_(ast::Const::Number(3)),
904 arena.const_(ast::Const::Number(1)),
905 ],
906 )),
907 ];
908 verify_that!(got_terms, eq(&expected))
909 }
910
911 #[gtest]
912 fn test_structured_data_and_types() -> googletest::Result<()> {
913 let arena = Arena::new_with_global_interner();
914 let input =
915 "[] [1,2,3] [1: 'one', 2: 'two'] {} {/foo: /bar} .List<.Option</name>, /string>";
916 let mut p = make_parser(&arena, input);
917 let mut got_base_terms = vec![];
918 loop {
919 if Token::Eof == p.token {
920 break;
921 }
922 let base_term = p.parse_base_term().unwrap();
924 got_base_terms.push(base_term);
925 }
926 let expected = vec![
927 arena.apply_fn(fn_list_sym(&arena), &[]),
928 arena.apply_fn(
929 fn_list_sym(&arena),
930 &[
931 arena.const_(ast::Const::Number(1)),
932 arena.const_(ast::Const::Number(2)),
933 arena.const_(ast::Const::Number(3)),
934 ],
935 ),
936 arena.apply_fn(
937 fn_map_sym(&arena),
938 &[
939 arena.const_(ast::Const::Number(1)),
940 arena.const_(ast::Const::String("one")),
941 arena.const_(ast::Const::Number(2)),
942 arena.const_(ast::Const::String("two")),
943 ],
944 ),
945 arena.apply_fn(fn_struct_sym(&arena), &[]),
946 arena.apply_fn(
947 fn_struct_sym(&arena),
948 &[
949 arena.const_(arena.name("/foo")),
950 arena.const_(arena.name("/bar")),
951 ],
952 ),
953 arena.apply_fn(
954 fn_list_type_sym(&arena),
955 &[
956 arena.apply_fn(
957 fn_option_type_sym(&arena),
958 &[arena.const_(arena.name("/name"))],
959 ),
960 arena.const_(arena.name("/string")),
961 ],
962 ),
963 ];
964 verify_that!(got_base_terms, eq(&expected))
965 }
966
967 #[test]
968 fn test_clause() -> Result<()> {
969 let arena = Arena::new_with_global_interner();
970 let mut p = make_parser(&arena, "foo(X).");
971 let clause = p.parse_clause()?;
972 match clause {
973 &ast::Clause {
974 head:
975 &ast::Atom {
976 args: &[ast::BaseTerm::Variable(x_sym)],
977 ..
978 },
979 premises: &[],
980 transform: &[],
981 } => {
982 assert_eq!(*x_sym, arena.variable_sym("X"));
983 assert_eq!(clause.head.sym, arena.predicate_sym("foo", None));
984 }
985 _ => panic!("unexpected: {:?}", clause),
986 }
987 let mut p = make_parser(&arena, "foo(X) :- !bar(X).");
988 let clause = p.parse_clause()?;
989 match clause {
990 &ast::Clause {
991 head:
992 &ast::Atom {
993 sym: foo_sym,
994 args: _,
995 },
996 premises:
997 &[
998 &ast::Term::NegAtom(&ast::Atom {
999 sym: bar_sym,
1000 args: _,
1001 }),
1002 ],
1003 transform: &[],
1004 } => {
1005 assert_eq!(foo_sym, arena.predicate_sym("foo", None));
1006 assert_eq!(bar_sym, arena.predicate_sym("bar", None));
1007 }
1008 _ => panic!("unexpected: {:?}", clause),
1009 };
1010 let mut p = make_parser(
1011 &arena,
1012 "foo(Z) ⟸ bar(Y) |> do fn:group_by(); let X = fn:count(Y).",
1013 );
1014
1015 let clause = p.parse_clause()?;
1016 match clause {
1017 &ast::Clause {
1018 head: &ast::Atom { .. },
1019 premises: &[&ast::Term::Atom(ast::Atom { .. })],
1020 transform:
1021 &[
1022 &ast::TransformStmt {
1023 var: None,
1024 app: ast::BaseTerm::ApplyFn(first_sym, _),
1025 },
1026 &ast::TransformStmt {
1027 var: Some("X"),
1028 app: ast::BaseTerm::ApplyFn(second_sym, _),
1029 },
1030 ],
1031 } => {
1032 assert_eq!(clause.head.sym, arena.predicate_sym("foo", None));
1033 assert_eq!(clause.transform.len(), 2);
1034 assert_eq!(*first_sym, arena.function_sym("fn:group_by", None));
1035 assert_eq!(*second_sym, arena.function_sym("fn:count", None));
1036 }
1037 _ => panic!("unexpected: {:?}", clause),
1038 }
1039
1040 Ok(())
1041 }
1042
1043 #[test]
1044 fn test_anonymous_variable_single() -> Result<()> {
1045 let arena = Arena::new_with_global_interner();
1046 let mut p = make_parser(&arena, "foo(_, X).");
1047 let clause = p.parse_clause()?;
1048 match clause.head.args {
1050 &[&ast::BaseTerm::Variable(anon), &ast::BaseTerm::Variable(x)] => {
1051 assert_eq!(anon, arena.variable_sym("_Anon0"));
1052 assert_eq!(x, arena.variable_sym("X"));
1053 }
1054 _ => panic!("unexpected args: {:?}", clause.head.args),
1055 }
1056 Ok(())
1057 }
1058
1059 #[test]
1060 fn test_anonymous_variable_multiple_distinct() -> Result<()> {
1061 let arena = Arena::new_with_global_interner();
1062 let mut p = make_parser(&arena, "foo(_, _, _).");
1063 let clause = p.parse_clause()?;
1064 match clause.head.args {
1066 &[
1067 &ast::BaseTerm::Variable(a0),
1068 &ast::BaseTerm::Variable(a1),
1069 &ast::BaseTerm::Variable(a2),
1070 ] => {
1071 assert_eq!(a0, arena.variable_sym("_Anon0"));
1072 assert_eq!(a1, arena.variable_sym("_Anon1"));
1073 assert_eq!(a2, arena.variable_sym("_Anon2"));
1074 assert_ne!(a0, a1);
1076 assert_ne!(a1, a2);
1077 }
1078 _ => panic!("unexpected args: {:?}", clause.head.args),
1079 }
1080 Ok(())
1081 }
1082
1083 #[test]
1084 fn test_anonymous_variable_in_rule_body() -> Result<()> {
1085 let arena = Arena::new_with_global_interner();
1086 let mut p = make_parser(&arena, "result(X) :- foo(X, _).");
1087 let clause = p.parse_clause()?;
1088 assert_eq!(clause.head.sym, arena.predicate_sym("result", None));
1089 match clause.premises {
1090 &[&ast::Term::Atom(&ast::Atom { args, .. })] => match args {
1091 &[&ast::BaseTerm::Variable(x), &ast::BaseTerm::Variable(anon)] => {
1092 assert_eq!(x, arena.variable_sym("X"));
1093 assert_eq!(anon, arena.variable_sym("_Anon0"));
1094 }
1095 _ => panic!("unexpected args: {:?}", args),
1096 },
1097 _ => panic!("unexpected premises: {:?}", clause.premises),
1098 }
1099 Ok(())
1100 }
1101
1102 #[test]
1103 fn test_anonymous_variable_with_negation() -> Result<()> {
1104 let arena = Arena::new_with_global_interner();
1105 let mut p = make_parser(&arena, "orphan(X) :- node(X, _), !has_parent(X).");
1106 let clause = p.parse_clause()?;
1107 assert_eq!(clause.head.sym, arena.predicate_sym("orphan", None));
1108 assert_eq!(clause.premises.len(), 2);
1109 match clause.premises[0] {
1111 &ast::Term::Atom(&ast::Atom { args, .. }) => match args {
1112 &[&ast::BaseTerm::Variable(_), &ast::BaseTerm::Variable(anon)] => {
1113 assert_eq!(anon, arena.variable_sym("_Anon0"));
1114 }
1115 _ => panic!("unexpected args: {:?}", args),
1116 },
1117 _ => panic!("expected Atom, got {:?}", clause.premises[0]),
1118 }
1119 match clause.premises[1] {
1121 &ast::Term::NegAtom(&ast::Atom { sym, .. }) => {
1122 assert_eq!(sym, arena.predicate_sym("has_parent", None));
1123 }
1124 _ => panic!("expected NegAtom, got {:?}", clause.premises[1]),
1125 }
1126 Ok(())
1127 }
1128}