Skip to main content

razor_fol/
parser.rs

1//! Implements a parser for first-order formulae and theories in Razor's syntax.
2//!
3//! The module provides a parser for first-order formulae by implementing [`FromStr`] for
4//! [`Formula`] and [`Theory`]. The parser is often used implicitly through [`str::parse`] method.
5//!
6//! **Example**:
7//! The following example parses a string into a [`Formula`]:
8//! ```rust
9//! use razor_fol::syntax::Formula;
10//!
11//! // parse a string into `Formula`:
12//! let formula: Formula = "exists x. P(x) & Q(x)".parse().unwrap();
13//!
14//! assert_eq!("∃ x. (P(x) ∧ Q(x))", formula.to_string());
15//! ```
16//!
17//! Similarly, a [`Theory`] can be parsed from a string:
18//! ```rust
19//! use razor_fol::syntax::Theory;
20//!
21//! // parse a string into `Theory` (formulae are separated by `;`)
22//! let theory: Theory = r#"
23//!    // mathematical notation:
24//!    ∀ x. Eq(x, x);
25//!    // verbose notation:
26//!    forall x, y. (Eq(x, y) implies Eq(y, x));
27//!    // compact notation:
28//!    ? x, y, z. (Eq(x, y) & Eq(y, z) -> Eq(x, z));
29//! "#.parse().unwrap();
30//!
31//! assert_eq!("∀ x. Eq(x, x)\n\
32//! ∀ x, y. (Eq(x, y) → Eq(y, x))\n\
33//! ∃ x, y, z. ((Eq(x, y) ∧ Eq(y, z)) → Eq(x, z))", theory.to_string());
34//! ```
35//!
36//! [`Formula`]: ../syntax/enum.formula.html
37//! [`Theory`]: ../syntax/struct.theory.html
38//! [`FromStr`]: https://doc.rust-lang.org/stable/core/str/trait.FromStr.html
39//! [`str::parse`]: https://doc.rust-lang.org/stable/std/primitive.str.html#method.parse
40use super::syntax::{*, Formula::*};
41use nom::{*, types::CompleteStr};
42use nom_locate::LocatedSpan;
43use std::fmt as fmt;
44use failure::{Fail, Error};
45use std::str::FromStr;
46
47const LOWER: &str = "abcdefghijklmnopqrstuvwxyz_";
48const UPPER: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
49const ALPHA_NUMERIC: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
50const COMMA: &str = ",";
51const APOSTROPHE: &str = "'";
52const L_PAREN: &str = "(";
53const R_PAREN: &str = ")";
54const TRUE: &str = "true";
55const CHAR_TOP: &str = "'|'";
56const TOP: &str = "⊤";
57const FALSE: &str = "false";
58const CHAR_BOTTOM: &str = "_|_";
59const BOTTOM: &str = "⟘";
60const EQUALS: &str = "=";
61const AND: &str = "and";
62const AMPERSAND: &str = "&";
63const WEDGE: &str = "∧";
64const OR: &str = "or";
65const BAR: &str = "|";
66const VEE: &str = "∨";
67const NOT: &str = "not";
68const TILDE: &str = "~";
69const NEG: &str = "¬";
70const IMPLIES: &str = "implies";
71const CHAR_RIGHT_ARROW: &str = "->";
72const RIGHT_ARROW: &str = "→";
73const IFF: &str = "iff";
74const CHAR_DOUBLE_ARROW: &str = "<=>";
75const DOUBLE_ARROW: &str = "⇔";
76const EXISTS: &str = "exists";
77const QUESTION: &str = "?";
78const CHAR_EXISTS: &str = "∃";
79const FORALL: &str = "forall";
80const EXCLAMATION: &str = "!";
81const CHAR_FORALL: &str = "∀";
82const DOT: &str = ".";
83const SEMI_COLON: &str = ";";
84const LINE_COMMENT: &str = "//";
85const L_BLOCK_COMMENT: &str = "/*";
86const R_BLOCK_COMMENT: &str = "*/";
87
88// Custom parsing errors:
89const ERR_DOT: u32 = 1;
90const ERR_SEMI_COLON: u32 = 2;
91const ERR_L_PAREN: u32 = 3;
92const ERR_R_PAREN: u32 = 4;
93
94const ERR_LOWER: u32 = 21;
95
96const ERR_VARS: u32 = 31;
97const ERR_TERM: u32 = 32;
98
99const ERR_EQUALS: u32 = 41;
100const ERR_FORMULA: u32 = 42;
101
102fn error_code_to_string(code: u32) -> &'static str {
103    match code {
104        ERR_DOT => ".",
105        ERR_SEMI_COLON => ";",
106        ERR_L_PAREN => "(",
107        ERR_R_PAREN => ")",
108        ERR_LOWER => "lowercase identifier",
109        ERR_VARS => "variables",
110        ERR_TERM => "term",
111        ERR_EQUALS => "=",
112        ERR_FORMULA => "formula",
113        _ => "unknown",
114    }
115}
116
117#[derive(Debug, Fail)]
118enum ParserError {
119    Missing {
120        line: u32,
121        column: u32,
122        code: u32,
123    },
124    Expecting {
125        line: u32,
126        column: u32,
127        code: u32,
128        found: Option<String>,
129    },
130    Failed {
131        line: u32,
132        column: u32,
133    },
134    Unknown,
135}
136
137impl fmt::Display for ParserError {
138    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
139        match self {
140            ParserError::Missing { line, column, code } => {
141                write!(f, "missing '{}' at line {}, column {}", error_code_to_string(*code), line, column)
142            }
143            ParserError::Expecting { line, column, code, found } => {
144                write!(f, "expecting '{}' on line {}, column {}", error_code_to_string(*code), line, column)
145                    .and_then(|result| {
146                        if let Some(found) = found {
147                            write!(f, "; found \"{}\"", found)
148                        } else {
149                            Ok(result)
150                        }
151                    })
152            }
153            ParserError::Failed { line, column } => {
154                write!(f, "failed to parse the input at line {}, column {}", line, column)
155            }
156            ParserError::Unknown => {
157                write!(f, "an error occurred while parsing the input")
158            }
159        }
160    }
161}
162
163type Span<'a> = LocatedSpan<CompleteStr<'a>>;
164
165named!(pub p_line_comment<Span, ()>,
166  map!(
167    many1!(
168      tuple!(
169        nom::space0,
170        preceded!(tag!(LINE_COMMENT), many0!(nom::not_line_ending)),
171        alt!(nom::line_ending | eof!())
172      )
173    ),
174    |_| ()
175  )
176);
177
178named!(pub p_block_comment<Span, ()>,
179  map!(
180    many1!(
181      tuple!(
182        nom::space0,
183        delimited!(
184            tag!(L_BLOCK_COMMENT),
185            many0!(is_not!(R_BLOCK_COMMENT)),
186            tag!(R_BLOCK_COMMENT)
187        )
188      )
189    ),
190    |_| ()
191  )
192);
193
194named!(pub spaces<Span, ()>,
195    map!(many0!(alt!(one_of!(&b" \t\n\r"[..]) => { |_|() } | p_line_comment | p_block_comment)), |_| ())
196);
197
198#[doc(hidden)]
199macro_rules! sp (
200  ($i:expr, $($args:tt)*) => (
201    {
202      use nom::Convert;
203      use nom::Err;
204
205      match sep!($i, spaces, $($args)*) {
206        Err(e) => Err(e),
207        Ok((i1,o))    => {
208          match spaces(i1) {
209            Err(e) => Err(Err::convert(e)),
210            Ok((i2,_))    => Ok((i2, o))
211          }
212        }
213      }
214    }
215  )
216);
217
218named!(p_lower_ident<Span, String>,
219    map!(pair!(one_of!(LOWER), opt!(is_a!(ALPHA_NUMERIC))),
220        |(first, rest): (char, Option<Span>)| {
221            let mut first = first.to_string();
222            if rest.is_some() {
223                first.push_str(rest.unwrap().fragment.0);
224            }
225            first
226        }
227    )
228);
229
230named!(p_upper_ident<Span, String>,
231    map!(pair!(one_of!(UPPER), opt!(is_a!(ALPHA_NUMERIC))),
232        |(first, rest): (char, Option<Span>)| {
233            let mut first = first.to_string();
234            if rest.is_some() {
235                first.push_str(rest.unwrap().fragment.0);
236            }
237            first
238        }
239    )
240);
241
242named!(p_var<Span, V>,
243    map!(p_lower_ident, |v| V::from(&v))
244);
245
246named!(p_vars<Span, Vec<V>>,
247    terminated!(
248        separated_nonempty_list!(
249            tag!(COMMA),
250            sp!(p_var)
251        ),
252        opt!(sp!(tag!(COMMA)))
253    )
254);
255
256named!(p_const<Span, C>,
257    map!(
258        preceded!(
259            tag!(APOSTROPHE),
260            return_error!(ErrorKind::Custom(ERR_LOWER), p_lower_ident)
261        ),
262        |c| C::from(&c)
263    )
264);
265
266named!(p_func<Span, F>,
267    map!(p_lower_ident,
268        |f| F::from(&f)
269    )
270);
271
272named!(p_nonempty_terms<Span, Vec<Term>>,
273    terminated!(
274        separated_nonempty_list!(
275            tag!(COMMA),
276            return_error!(ErrorKind::Custom(ERR_TERM), p_term)
277        ),
278        opt!(sp!(tag!(COMMA)))
279    )
280);
281
282named!(p_term_args<Span, Vec<Term>>,
283    alt!(
284        value!(vec![], delimited!(tag!(L_PAREN), opt!(space),tag!(R_PAREN))) |
285        delimited!(
286            tag!(L_PAREN),
287            p_nonempty_terms,
288            return_error!(ErrorKind::Custom(ERR_R_PAREN), tag!(R_PAREN))
289        )
290    )
291);
292
293named!(p_term<Span, Term>,
294    alt!(
295        map!(
296            terminated!(
297                sp!(p_var),
298                // The term is a composite term if followed by '(':
299                not!(tag!(L_PAREN))
300            ),
301            |v| v.into()
302        ) |
303        map!(sp!(p_const), |c| c.into()) |
304        map!( // composite term
305            pair!(sp!(p_func), sp!(p_term_args)),
306            |(f, ts): (F, Vec<Term>)| f.app(ts)
307        )
308    )
309);
310
311named!(p_equals<Span, Formula>,
312    do_parse!(left: p_term >>
313        tag!(EQUALS) >>
314        right: add_return_error!(ErrorKind::Custom(ERR_TERM), p_term) >>
315        (left.equals(right))
316    )
317);
318
319named!(p_pred<Span, Pred>,
320    map!(p_upper_ident,
321        |f| Pred::from(&f)
322    )
323);
324
325named!(p_atom<Span, Formula>,
326    alt!(
327        value!(Top, alt!(tag!(TRUE) |  tag!(TOP) | tag!(CHAR_TOP))) |
328        value!(Bottom, alt!(tag!(FALSE) |  tag!(BOTTOM) | tag!(CHAR_BOTTOM))) |
329        add_return_error!(ErrorKind::Custom(ERR_EQUALS), p_equals) |
330        // composite term:
331        map!(
332            pair!(p_pred, sp!(p_term_args)),
333            |(p, ts): (Pred, Vec<Term>)| p.app(ts)
334        ) |
335        delimited!(sp!(tag!(L_PAREN)),
336            return_error!(ErrorKind::Custom(ERR_FORMULA), p_formula),
337            return_error!(ErrorKind::Custom(ERR_R_PAREN), tag!(R_PAREN))
338        )
339    )
340);
341
342named!(p_not<Span, Formula>,
343    alt!(
344        preceded!(
345            sp!(alt!(tag!(NOT) | tag!(TILDE) | tag!(NEG))),
346            map!(alt!(p_not | p_quantified), not)
347        ) |
348        sp!(p_atom)
349    )
350);
351
352named!(p_and<Span, Formula>,
353    map!(
354        pair!(
355            p_not,
356            opt!(
357                preceded!(
358                    sp!(alt!(tag!(AND) | tag!(AMPERSAND) | tag!(WEDGE))),
359                    alt!(
360                        p_and |
361                        return_error!(ErrorKind::Custom(ERR_FORMULA), p_quantified)
362                    )
363                )
364            )
365        ),
366        |(l, r)| if let Some(r) = r { l.and(r) } else { l }
367    )
368);
369
370named!(p_or<Span, Formula>,
371    map!(
372        pair!(
373            p_and,
374            opt!(
375                preceded!(
376                    sp!(alt!(tag!(OR) | tag!(BAR) | tag!(VEE))),
377                    return_error!(ErrorKind::Custom(ERR_FORMULA), p_quantified)
378                )
379            )
380        ),
381        |(l, r)| if let Some(r) = r { l.or(r) } else { l }
382    )
383);
384
385named!(p_quantified<Span, Formula>,
386    alt!(
387        do_parse!(
388            q: sp!(
389                alt!(
390                    value!(
391                        FORALL,
392                        alt!(tag!(FORALL) | tag!(EXCLAMATION) | tag!(CHAR_FORALL))
393                    ) |
394                    value!(
395                        EXISTS,
396                        alt!(tag!(EXISTS) | tag!(QUESTION) | tag!(CHAR_EXISTS))
397                    )
398                )
399            ) >>
400            vs: return_error!(ErrorKind::Custom(ERR_VARS), p_vars) >>
401            return_error!(ErrorKind::Custom(ERR_DOT), sp!(tag!(DOT))) >>
402            f: return_error!(ErrorKind::Custom(ERR_FORMULA), p_quantified) >>
403            ( if q == FORALL { forall(vs, f) } else { exists(vs, f) } )
404        ) |
405        p_or
406    )
407);
408
409named!(p_formula<Span, Formula>,
410    do_parse!(
411        first: p_quantified >>
412        second: fold_many0!(
413            pair!(
414                sp!(
415                    alt!(
416                        value!(
417                            IMPLIES,
418                            alt!(tag!(IMPLIES) | tag!(RIGHT_ARROW) | tag!(CHAR_RIGHT_ARROW))
419                        ) |
420                        value!(
421                            IFF,
422                            alt!(tag!(IFF) | tag!(DOUBLE_ARROW) | tag!(CHAR_DOUBLE_ARROW))
423                        )
424                    )
425                ),
426                return_error!(ErrorKind::Custom(ERR_FORMULA), p_quantified)
427            ),
428            first,
429            |acc: Formula, (q, f)| if q == IMPLIES { acc.implies(f) } else { acc.iff(f) }
430        ) >>
431        (second)
432    )
433);
434
435named!(pub theory<Span, Theory>,
436    map!(
437        many_till!(
438            map!(
439                terminated!(
440                    sp!(p_formula),
441                    return_error!(ErrorKind::Custom(ERR_SEMI_COLON),
442                        sp!(tag!(SEMI_COLON))
443                    )
444                ),
445                |f| Option::Some(f)
446            ),
447            value!((), sp!(eof!()))
448        ),
449        |(fs, _)| {
450            let formulae: Vec<Formula> = fs.into_iter()
451                .filter_map(|f| f)
452                .collect();
453            Theory::from(formulae)
454        }
455    )
456);
457
458fn make_parser_error(error: &Err<Span, u32>) -> ParserError {
459    match error {
460        Err::Error(Context::Code(pos, ErrorKind::Custom(code))) | Err::Failure(Context::Code(pos, ErrorKind::Custom(code))) => {
461            let found = if pos.fragment.len() != 0 {
462                Some(pos.fragment.0.to_owned())
463            } else {
464                None
465            };
466            let code = *code;
467            match code {
468                ERR_SEMI_COLON | ERR_DOT | ERR_L_PAREN | ERR_R_PAREN
469                    => ParserError::Missing { line: pos.line, column: pos.get_column() as u32, code },
470                ERR_FORMULA | ERR_TERM | ERR_VARS | ERR_LOWER
471                    => ParserError::Expecting { line: pos.line, column: pos.get_column() as u32, code, found },
472                _ => ParserError::Failed { line: pos.line, column: pos.get_column() as u32 },
473            }
474        }
475        Err::Error(Context::Code(pos, _)) | Err::Failure(Context::Code(pos, _)) => {
476            ParserError::Failed { line: pos.line, column: pos.get_column() as u32 }
477        }
478        _ => ParserError::Unknown,
479    }
480}
481
482impl FromStr for Formula {
483    type Err = Error;
484
485    fn from_str(s: &str) -> Result<Self, Self::Err> {
486        p_formula(Span::new(CompleteStr(s)))
487            .map(|r| r.1)
488            .map_err(|e| make_parser_error(&e).into())
489    }
490}
491
492impl FromStr for Theory {
493    type Err = Error;
494
495    fn from_str(s: &str) -> Result<Self, Self::Err> {
496        theory(Span::new(CompleteStr(s)))
497            .map(|r| r.1)
498            .map_err(|e| make_parser_error(&e).into())
499    }
500}
501
502#[cfg(test)]
503mod test_parser {
504    use super::*;
505    use std::fmt;
506    use crate::test_prelude::*;
507
508    fn success<R: PartialEq + fmt::Debug>(
509        parser: fn(Span) -> nom::IResult<Span, R, u32>,
510        parse_str: &str,
511        expected: R,
512        remaining: &str) {
513        let parsed = parser(Span::new(CompleteStr(parse_str)));
514        assert!(parsed.is_ok());
515        let (rem, res) = parsed.unwrap();
516        assert_eq!(expected, res);
517        assert_eq!(CompleteStr(remaining), rem.fragment);
518    }
519
520    fn success_to_string<R: ToString>(
521        parser: fn(Span) -> nom::IResult<Span, R, u32>,
522        parse_str: &str,
523        expected: &str,
524        remaining: &str) {
525        let parsed = parser(Span::new(CompleteStr(parse_str)));
526        assert!(parsed.is_ok());
527        let (str, result) = parsed.unwrap();
528        assert_eq!(expected, result.to_string());
529        assert_eq!(remaining, str.fragment.0);
530    }
531
532    fn fail<R: PartialEq + fmt::Debug>(
533        parser: fn(Span) -> nom::IResult<Span, R, u32>,
534        parse_str: &str) {
535        let result = parser(Span::new(CompleteStr(parse_str)));
536        assert!(result.is_err());
537    }
538
539    #[test]
540    fn test_lower_identifier() {
541        success(p_lower_ident, "_", "_".to_owned(), "");
542        success(p_lower_ident, "a", "a".to_owned(), "");
543        success(p_lower_ident, "_ab", "_ab".to_owned(), "");
544        success(p_lower_ident, "aB", "aB".to_owned(), "");
545        success(p_lower_ident, "aB!", "aB".to_owned(), "!");
546        success(p_lower_ident, "johnSn0w", "johnSn0w".to_owned(), "");
547
548        fail(p_lower_ident, "B");
549        fail(p_lower_ident, "Blah");
550        fail(p_lower_ident, "!ABC");
551        fail(p_lower_ident, "123");
552    }
553
554    #[test]
555    fn test_upper_identifier() {
556        success(p_upper_ident, "A", "A".to_owned(), "");
557        success(p_upper_ident, "AB", "AB".to_owned(), "");
558        success(p_upper_ident, "AB!", "AB".to_owned(), "!");
559        success(p_upper_ident, "JohnSn0w", "JohnSn0w".to_owned(), "");
560
561        fail(p_upper_ident, "b");
562        fail(p_upper_ident, "blah");
563        fail(p_upper_ident, "!ABC");
564        fail(p_upper_ident, "123");
565        fail(p_upper_ident, "_");
566        fail(p_upper_ident, "_AB");
567    }
568
569    #[test]
570    fn test_var() {
571        success(p_var, "x", _x(), "");
572
573        fail(p_var, "  x");
574        fail(p_var, "'a");
575        fail(p_var, "B");
576    }
577
578    #[test]
579    fn test_vars() {
580        success(p_vars, "x", vec![_x()], "");
581        success(p_vars, "x,y", vec![_x(), _y()], "");
582        success(p_vars, "  x", vec![_x()], "");
583        success(p_vars, "x, y", vec![_x(), _y()], "");
584        success(p_vars, "x, y\t,\nz", vec![_x(), _y(), _z()], "");
585        success(p_vars, "x,", vec![_x()], "");
586        success(p_vars, "x,y   ,   ", vec![_x(), _y()], "");
587
588        fail(p_vars, ",x");
589        fail(p_vars, "B");
590    }
591
592    #[test]
593    fn test_const() {
594        success(p_const, "'a", _a(), "");
595        fail(p_const, "x");
596        fail(p_const, "   'a");
597        fail(p_const, "'  a");
598        fail(p_const, "''a");
599        fail(p_const, "B");
600    }
601
602    #[test]
603    fn test_func() {
604        success(p_func, "f", f(), "");
605        fail(p_func, "  f");
606        fail(p_func, "'a");
607        fail(p_func, "'B");
608        fail(p_func, "B");
609    }
610
611    #[test]
612    fn test_term() {
613        success(p_term, "x", x(), "");
614        success(p_term, "'a", a(), "");
615        success(p_term, "f()", f().app0(), "");
616        success(p_term, "f( )", f().app0(), "");
617        success_to_string(p_term, "f(x)", "f(x)", "");
618        success_to_string(p_term, "f(x,   y   )", "f(x, y)", "");
619        success_to_string(p_term, "f(x,   y   \n , z)", "f(x, y, z)", "");
620        success_to_string(p_term, "f(f(f(f(f(f(f(x)))))))", "f(f(f(f(f(f(f(x)))))))", "");
621        success_to_string(p_term, "f  (x)", "f(x)", "");
622        success_to_string(p_term, "f  (   x   )   ", "f(x)", "");
623        success_to_string(p_term, "f(w, g (  x, y, z))", "f(w, g(x, y, z))", "");
624        success_to_string(p_term, "f('a, x, g('b, h(x)))", "f('a, x, g('b, h(x)))", "");
625        fail(p_term, "''a");
626        fail(p_term, "P()");
627        fail(p_term, "f(Q())");
628        fail(p_term, "12f(x)");
629        fail(p_term, "f(1, 2)");
630        fail(p_term, "f(x, g(1))");
631    }
632
633    #[test]
634    fn test_equals() {
635        success_to_string(p_equals, "x = y", "x = y", "");
636        success_to_string(p_equals, "'a = 'b", "'a = 'b", "");
637        success_to_string(p_equals, "f(x) = y", "f(x) = y", "");
638        success_to_string(p_equals, "  f  (x  ) = y", "f(x) = y", "");
639
640        fail(p_equals, "A = B");
641        fail(p_equals, "!a = b");
642        fail(p_equals, "a != b");
643    }
644
645    #[test]
646    fn test_pred() {
647        success(p_pred, "P", P(), "");
648        fail(p_pred, "  P");
649        fail(p_pred, "'a");
650        fail(p_pred, "x");
651    }
652
653    #[test]
654    fn test_line_comment() {
655        success(p_line_comment, "//\n", (), "");
656        success(p_line_comment, "  //\n", (), "");
657        success(p_line_comment, "// comment line \n", (), "");
658        success(p_line_comment, "//comment line \n", (), "");
659        success(p_line_comment, "   //   comment line \n", (), "");
660        success(p_line_comment, "//", (), "");
661        fail(p_line_comment, "/");
662    }
663
664    #[test]
665    fn test_block_comment() {
666        success(p_block_comment, "/**/", (), "");
667        success(p_block_comment, "  /**/", (), "");
668        success(p_block_comment, "/* comment line */", (), "");
669        success(p_block_comment, "/* comment line \n*/", (), "");
670        success(p_block_comment, "/*comment line */", (), "");
671        success(p_block_comment, "   /*   comment line \n*/", (), "");
672        fail(p_block_comment, "/*");
673        fail(p_block_comment, "/");
674    }
675
676    #[test]
677    fn test_atom() {
678        success(p_atom, TRUE, Top, "");
679        success(p_atom, CHAR_TOP, Top, "");
680        success(p_atom, TOP, Top, "");
681        success(p_atom, FALSE, Bottom, "");
682        success(p_atom, CHAR_BOTTOM, Bottom, "");
683        success(p_atom, BOTTOM, Bottom, "");
684        success_to_string(p_atom, "x = f('a)", "x = f('a)", "");
685        success_to_string(p_atom, "P()", "P()", "");
686        success_to_string(p_atom, "P( )", "P()", "");
687        success_to_string(p_atom, "P(x)", "P(x)", "");
688        success_to_string(p_atom, "P(x,   y   )", "P(x, y)", "");
689        success_to_string(p_atom, "P(x,   y   \n , z)", "P(x, y, z)", "");
690        success_to_string(p_atom, "P(f(f(f(f(f(f(x)))))))", "P(f(f(f(f(f(f(x)))))))", "");
691        success_to_string(p_atom, "P  (x)", "P(x)", "");
692        success_to_string(p_atom, "P  (   x   )   ", "P(x)", "");
693        success_to_string(p_atom, "P(w, g (  x, y, z))", "P(w, g(x, y, z))", "");
694        success_to_string(p_atom, "P('a, x, g('b, h(x)))", "P('a, x, g('b, h(x)))", "");
695        fail(p_atom, "''a");
696        fail(p_atom, "f()");
697        fail(p_atom, "P(Q())");
698        fail(p_atom, "12P(x)");
699        fail(p_atom, "P(1, 2)");
700        fail(p_atom, "P(x, g(1))");
701    }
702
703    #[test]
704    fn test_formula() {
705        success_to_string(p_formula, "true", "⊤", "");
706        success_to_string(p_formula, "false", "⟘", "");
707        success_to_string(p_formula, "((((true))))", "⊤", "");
708        success_to_string(p_formula, "( true)", "⊤", "");
709        success_to_string(p_formula, "(true )", "⊤", "");
710        success_to_string(p_formula, "P()", "P()", "");
711        success_to_string(p_formula, "  P()", "P()", "");
712        success_to_string(p_formula, "  ~P()", "¬P()", "");
713        success_to_string(p_formula, "P(x)", "P(x)", "");
714        success_to_string(p_formula, "P('a)", "P('a)", "");
715        success_to_string(p_formula, "P(x,y)", "P(x, y)", "");
716        success_to_string(p_formula, "P('a,'b)", "P('a, 'b)", "");
717        success_to_string(p_formula, "P('a,x)", "P('a, x)", "");
718        success_to_string(p_formula, "P(x, y)", "P(x, y)", "");
719        success_to_string(p_formula, "P(x,            y     \n)", "P(x, y)", "");
720        success_to_string(p_formula, "P(f(x))", "P(f(x))", "");
721        success_to_string(
722            p_formula,
723            "P(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(x)))))))))))))))))))))",
724            "P(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(x)))))))))))))))))))))",
725            "",
726        );
727        success_to_string(p_formula, "P(f(x, g(y)), g(f(g(y))))", "P(f(x, g(y)), g(f(g(y))))", "");
728        success_to_string(p_formula, "'a = 'b", "'a = 'b", "");
729        success_to_string(p_formula, "x = x", "x = x", "");
730        success_to_string(p_formula, "f() = x", "f() = x", "");
731        success_to_string(p_formula, "f(x) = x", "f(x) = x", "");
732        success_to_string(p_formula, "f(x) = x", "f(x) = x", "");
733        success_to_string(p_formula, "f(x) = g(h(g(f(x)), y))", "f(x) = g(h(g(f(x)), y))", "");
734        success_to_string(p_formula, "P(x) implies Q(x)", "P(x) → Q(x)", "");
735        success_to_string(p_formula, "P(x) implies Q(x) -> R(x)", "(P(x) → Q(x)) → R(x)", "");
736        success_to_string(p_formula, "P(x) implies (Q(x) -> R(x))", "P(x) → (Q(x) → R(x))", "");
737        success_to_string(p_formula, "P(x) implies (Q(x) -> R(x))", "P(x) → (Q(x) → R(x))", "");
738        success_to_string(p_formula, "P(x) implies (Q(x) -> R(x) -> Q(z))", "P(x) → ((Q(x) → R(x)) → Q(z))", "");
739        success_to_string(p_formula, "P(x) iff Q(x)", "P(x) ⇔ Q(x)", "");
740        success_to_string(p_formula, "P(x) iff Q(x) <=> R(x)", "(P(x) ⇔ Q(x)) ⇔ R(x)", "");
741        success_to_string(p_formula, "P(x) iff (Q(x) <=> R(x))", "P(x) ⇔ (Q(x) ⇔ R(x))", "");
742        success_to_string(p_formula, "P(x) iff (Q(x) <=> R(x) <=> Q(z))", "P(x) ⇔ ((Q(x) ⇔ R(x)) ⇔ Q(z))", "");
743        success_to_string(p_formula, "P(x) iff Q(x) implies R(x)", "(P(x) ⇔ Q(x)) → R(x)", "");
744        success_to_string(p_formula, "P(x) implies Q(x) iff R(x)", "(P(x) → Q(x)) ⇔ R(x)", "");
745        success_to_string(p_formula, "exists x . P(x)", "∃ x. P(x)", "");
746        success_to_string(p_formula, "exists x,y . P(x, y)", "∃ x, y. P(x, y)", "");
747        success_to_string(p_formula, "exists x . exists y, z. P(x, y, z)", "∃ x. (∃ y, z. P(x, y, z))", "");
748        success_to_string(p_formula, "exists x . P(x) implies Q(x)", "(∃ x. P(x)) → Q(x)", "");
749        success_to_string(p_formula, "exists x . (P(x) implies Q(x))", "∃ x. (P(x) → Q(x))", "");
750        success_to_string(p_formula, "forall x . P(x)", "∀ x. P(x)", "");
751        success_to_string(p_formula, "forall x,y . P(x, y)", "∀ x, y. P(x, y)", "");
752        success_to_string(p_formula, "forall x . forall y, z. P(x, y, z)", "∀ x. (∀ y, z. P(x, y, z))", "");
753        success_to_string(p_formula, "forall x . P(x) implies Q(x)", "(∀ x. P(x)) → Q(x)", "");
754        success_to_string(p_formula, "forall x . (P(x) implies Q(x))", "∀ x. (P(x) → Q(x))", "");
755        success_to_string(p_formula, "forall x . exists y . P(x, y)", "∀ x. (∃ y. P(x, y))", "");
756        success_to_string(p_formula, "P(x) or Q(y)", "P(x) ∨ Q(y)", "");
757        success_to_string(p_formula, "P(x) or Q(y) or R(z)", "P(x) ∨ (Q(y) ∨ R(z))", "");
758        success_to_string(p_formula, "(P(x) or Q(y)) or R(z)", "(P(x) ∨ Q(y)) ∨ R(z)", "");
759        success_to_string(p_formula, "P(x) or Q(y) or (R(z) or S(z))", "P(x) ∨ (Q(y) ∨ (R(z) ∨ S(z)))", "");
760        success_to_string(p_formula, "P(x) implies Q(x) or R(x)", "P(x) → (Q(x) ∨ R(x))", "");
761        success_to_string(p_formula, "P(x) or Q(x) implies R(x)", "(P(x) ∨ Q(x)) → R(x)", "");
762        success_to_string(p_formula, "exists x . P(x) or Q(x)", "∃ x. (P(x) ∨ Q(x))", "");
763        success_to_string(p_formula, "P(x) or exists y . Q(y)", "P(x) ∨ (∃ y. Q(y))", "");
764        success_to_string(p_formula, "exists x . P(x) or exists y . Q(y)", "∃ x. (P(x) ∨ (∃ y. Q(y)))", "");
765        success_to_string(p_formula, "P(x) or forall y . Q(y)", "P(x) ∨ (∀ y. Q(y))", "");
766        success_to_string(p_formula, "exists x . P(x) or forall y . Q(y)", "∃ x. (P(x) ∨ (∀ y. Q(y)))", "");
767        success_to_string(p_formula, "P(x) and Q(y) or R(z)", "(P(x) ∧ Q(y)) ∨ R(z)", "");
768        success_to_string(p_formula, "P(x) and (Q(y) or R(z))", "P(x) ∧ (Q(y) ∨ R(z))", "");
769        success_to_string(p_formula, "P(x) or Q(y) and R(z)", "P(x) ∨ (Q(y) ∧ R(z))", "");
770        success_to_string(p_formula, "P(x) and Q(y) and R(z)", "P(x) ∧ (Q(y) ∧ R(z))", "");
771        success_to_string(p_formula, "P(w) and Q(x) and R(y) and S(z)", "P(w) ∧ (Q(x) ∧ (R(y) ∧ S(z)))", "");
772        success_to_string(p_formula, "(P(x) and Q(y)) and R(z)", "(P(x) ∧ Q(y)) ∧ R(z)", "");
773        success_to_string(p_formula, "P(x) and Q(y) implies R(z)", "(P(x) ∧ Q(y)) → R(z)", "");
774        success_to_string(p_formula, "P(x) and exists y . Q(y)", "P(x) ∧ (∃ y. Q(y))", "");
775        success_to_string(p_formula, "exists x . P(x) and exists y . Q(y)", "∃ x. (P(x) ∧ (∃ y. Q(y)))", "");
776        success_to_string(p_formula, "P(x) and forall y . Q(y)", "P(x) ∧ (∀ y. Q(y))", "");
777        success_to_string(p_formula, "exists x . P(x) and forall y . Q(y)", "∃ x. (P(x) ∧ (∀ y. Q(y)))", "");
778        success_to_string(p_formula, "not true", "¬⊤", "");
779        success_to_string(p_formula, "not true -> false", "(¬⊤) → ⟘", "");
780        success_to_string(p_formula, "~x=y", "¬(x = y)", "");
781        success_to_string(p_formula, "true -> not false", "⊤ → (¬⟘)", "");
782        success_to_string(p_formula, "not P(x, y) or Q(z)", "(¬P(x, y)) ∨ Q(z)", "");
783        success_to_string(p_formula, "not P(x, y) and Q(z)", "(¬P(x, y)) ∧ Q(z)", "");
784        success_to_string(p_formula, "not not R(x)", "¬(¬R(x))", "");
785        success_to_string(p_formula, "not not not not not R(x) and S(y)", "(¬(¬(¬(¬(¬R(x)))))) ∧ S(y)", "");
786        success_to_string(p_formula, "not exists y . Q(y)", "¬(∃ y. Q(y))", "");
787        success_to_string(p_formula, "exists x . not exists y . Q(y)", "∃ x. (¬(∃ y. Q(y)))", "");
788        success_to_string(
789            p_formula,
790            "P(x) implies Q(y) and exists z . f(z) = g(f(z)) or (forall y, z . S(y,z) implies false)",
791            "P(x) → (Q(y) ∧ (∃ z. ((f(z) = g(f(z))) ∨ ((∀ y, z. S(y, z)) → ⟘))))",
792            "",
793        );
794        success_to_string(
795            p_formula,
796            "not forall x, y . P(x) and Q(y) implies h(z) = z",
797            "(¬(∀ x, y. (P(x) ∧ Q(y)))) → (h(z) = z)",
798            "",
799        );
800        success_to_string(
801            p_formula,
802            "∀ x. ∃ y. ((x = y) ∧ ¬P(y)) ∨ (Q(x) → R(y))",
803            "∀ x. (∃ y. (((x = y) ∧ (¬P(y))) ∨ (Q(x) → R(y))))",
804            "",
805        );
806        success_to_string(
807            p_formula,
808            "∀ x. (∃ y. (((x = y) ∧ (¬P(y))) ∨ (Q(x) → R(y))))",
809            "∀ x. (∃ y. (((x = y) ∧ (¬P(y))) ∨ (Q(x) → R(y))))",
810            "",
811        );
812        success_to_string(
813            p_formula,
814            "! x. ? y. ((x = y) & ~P(y)) | (Q(x) -> R(y))",
815            "∀ x. (∃ y. (((x = y) ∧ (¬P(y))) ∨ (Q(x) → R(y))))",
816            "",
817        );
818        success_to_string(
819            p_formula,
820            "! x. (? y. (((x = y) & (~P(y))) | (Q(x) -> R(y))))",
821            "∀ x. (∃ y. (((x = y) ∧ (¬P(y))) ∨ (Q(x) → R(y))))",
822            "",
823        );
824    }
825
826    #[test]
827    fn test_theory() {
828        success_to_string(
829            theory,
830            "  P(x)   ;",
831            "P(x)",
832            "",
833        );
834        success_to_string(
835            theory,
836            "E(x,x);\
837            E(x,y) -> E(y,x) ;\
838            E(x,y) & E(y,z) -> E(x,z);",
839            "E(x, x)\nE(x, y) → E(y, x)\n(E(x, y) ∧ E(y, z)) → E(x, z)",
840            "",
841        );
842        success_to_string(
843            theory,
844            "// comment 0\n\
845            E(x,x)\
846            ;\
847            // another comment\n\
848            E(x,y) -> E(y,x) ;\
849            E(x,y) & E(y,z) -> E(x,z);",
850            "E(x, x)\nE(x, y) → E(y, x)\n(E(x, y) ∧ E(y, z)) → E(x, z)",
851            "",
852        );
853        success_to_string(
854            theory,
855            "// comment 0\n\
856            E /*reflexive*/(//first argument \n\
857            x, \n\
858            /*second argument*/ x)\
859            ;\
860            // another comment\n\
861            /* yet another comment */
862            E(x,y) -> E(y,x) /*symmetric*/ ;\
863            E(x,y) & E(y,z) -> /* transitivity */ E(x,z);",
864            "E(x, x)\nE(x, y) → E(y, x)\n(E(x, y) ∧ E(y, z)) → E(x, z)",
865            "",
866        );
867        success_to_string(
868            theory,
869            "P(x);exists x . Q(x);R(x) -> S(x);",
870            "P(x)\n∃ x. Q(x)\nR(x) → S(x)",
871            "",
872        );
873    }
874
875    #[test]
876    fn parse_failure() {
877        {
878            let parsed: Result<Theory, Error> = "P(X)".parse();
879            assert_eq!("expecting 'term' on line 1, column 3; found \"X)\"", parsed.err().unwrap().to_string());
880        }
881        {
882            let parsed: Result<Theory, Error> = "P('A)".parse();
883            assert_eq!("expecting 'term' on line 1, column 3; found \"'A)\"", parsed.err().unwrap().to_string());
884        }
885        {
886            let parsed: Result<Theory, Error> = "P(x)".parse();
887            assert_eq!("missing ';' at line 1, column 5", parsed.err().unwrap().to_string());
888        }
889        {
890            let parsed: Result<Theory, Error> = "P(x".parse();
891            assert_eq!("missing ')' at line 1, column 4", parsed.err().unwrap().to_string());
892        }
893        {
894            let parsed: Result<Theory, Error> = "~P(x".parse();
895            assert_eq!("missing ')' at line 1, column 5", parsed.err().unwrap().to_string());
896        }
897        {
898            let parsed: Result<Theory, Error> = "P(x) and ".parse();
899            assert_eq!("expecting 'formula' on line 1, column 10", parsed.err().unwrap().to_string());
900        }
901        {
902            let parsed: Result<Theory, Error> = "P(x) and X".parse();
903            assert_eq!("expecting 'formula' on line 1, column 10; found \"X\"", parsed.err().unwrap().to_string());
904        }
905        {
906            let parsed: Result<Theory, Error> = "P(x) or".parse();
907            assert_eq!("expecting 'formula' on line 1, column 8", parsed.err().unwrap().to_string());
908        }
909        {
910            let parsed: Result<Theory, Error> = "P(x) or X".parse();
911            assert_eq!("expecting 'formula' on line 1, column 9; found \"X\"", parsed.err().unwrap().to_string());
912        }
913        {
914            let parsed: Result<Theory, Error> = "P(x) ->".parse();
915            assert_eq!("expecting 'formula' on line 1, column 8", parsed.err().unwrap().to_string());
916        }
917        {
918            let parsed: Result<Theory, Error> = "P(x) -> X".parse();
919            assert_eq!("expecting 'formula' on line 1, column 9; found \"X\"", parsed.err().unwrap().to_string());
920        }
921        {
922            let parsed: Result<Theory, Error> = "P(x) <=>".parse();
923            assert_eq!("expecting 'formula' on line 1, column 9", parsed.err().unwrap().to_string());
924        }
925        {
926            let parsed: Result<Theory, Error> = "P(x) <=> X".parse();
927            assert_eq!("expecting 'formula' on line 1, column 10; found \"X\"", parsed.err().unwrap().to_string());
928        }
929        {
930            let parsed: Result<Theory, Error> = "!x P(x".parse();
931            assert_eq!("missing '.' at line 1, column 4", parsed.err().unwrap().to_string());
932        }
933        {
934            let parsed: Result<Theory, Error> = "! P(x)".parse();
935            assert_eq!("expecting 'variables' on line 1, column 3; found \"P(x)\"", parsed.err().unwrap().to_string());
936        }
937        {
938            let parsed: Result<Theory, Error> = "!x . ".parse();
939            assert_eq!("expecting 'formula' on line 1, column 6", parsed.err().unwrap().to_string());
940        }
941        {
942            let parsed: Result<Theory, Error> = "!x . X".parse();
943            assert_eq!("expecting 'formula' on line 1, column 6; found \"X\"", parsed.err().unwrap().to_string());
944        }
945        {
946            let parsed: Result<Theory, Error> = "?x P(x".parse();
947            assert_eq!("missing '.' at line 1, column 4", parsed.err().unwrap().to_string());
948        }
949        {
950            let parsed: Result<Theory, Error> = "? P(x)".parse();
951            assert_eq!("expecting 'variables' on line 1, column 3; found \"P(x)\"", parsed.err().unwrap().to_string());
952        }
953        {
954            let parsed: Result<Theory, Error> = "?x . ".parse();
955            assert_eq!("expecting 'formula' on line 1, column 6", parsed.err().unwrap().to_string());
956        }
957        {
958            let parsed: Result<Theory, Error> = "?x . X".parse();
959            assert_eq!("expecting 'formula' on line 1, column 6; found \"X\"", parsed.err().unwrap().to_string());
960        }
961        {
962            let parsed: Result<Theory, Error> = "x".parse();
963            assert_eq!("failed to parse the input at line 1, column 1", parsed.err().unwrap().to_string());
964        }
965        {
966            let parsed: Result<Theory, Error> = "(X)".parse();
967            assert_eq!("expecting 'formula' on line 1, column 2; found \"X)\"", parsed.err().unwrap().to_string());
968        }
969        {
970            let parsed: Result<Theory, Error> = "(P(x)".parse();
971            assert_eq!("missing ')' at line 1, column 6", parsed.err().unwrap().to_string());
972        }
973        {
974            let parsed: Result<Theory, Error> = "P(x)\n\
975            Q(x) <=> R(x);".parse();
976            assert_eq!("missing ';' at line 2, column 1", parsed.err().unwrap().to_string());
977        }
978        {
979            let parsed: Result<Theory, Error> = "P(x);\n\
980            Q(x) <=> R(x);\n\
981            S(x) => Q(x);".parse();
982            assert_eq!("missing ';' at line 3, column 6", parsed.err().unwrap().to_string());
983        }
984        {
985            let parsed: Result<Theory, Error> = "P(x);\n\
986            Q(x) <=> R(x);\n\
987            S(x) and ".parse();
988            assert_eq!("expecting 'formula' on line 3, column 10", parsed.err().unwrap().to_string());
989        }
990    }
991}
992
993