#![allow(unused_braces)]
#![allow(clippy::type_complexity)]
#![allow(clippy::upper_case_acronyms)]
#![allow(clippy::needless_lifetimes)]
pub use internal::{Parser, Token};
pomelo! {
%module internal;
%include { use crate::visitors; }
%stack_size 0;
%parser pub struct Parser<'a, T: visitors::Smt2Visitor> {};
%extra_argument (&'a mut T, &'a mut crate::lexer::Position);
%error T::Error;
%syntax_error { match token {
Some(token) => Err(extra.0.syntax_error(extra.1.clone(), format!("unexpected token: {:?}", token))),
None => Err(extra.0.syntax_error(extra.1.clone(), "unexpected end of input".into())),
}};
%parse_fail { extra.0.parsing_error(extra.1.clone(), "unrecoverable parsing error".into()) };
%token #[derive(Clone, Debug, PartialEq, Eq)] pub enum Token {};
%type Keyword String;
%type Symbol String;
%type Numeral crate::Numeral;
%type Decimal crate::Decimal;
%type Hexadecimal crate::Hexadecimal;
%type Binary crate::Binary;
%type String String;
%type command T::Command;
%type term T::Term;
%type terms Vec<T::Term>;
%type constant T::Constant;
%type qual_identifier T::QualIdentifier;
%type identifier visitors::Identifier<T::Symbol>;
%type bound_symbol T::Symbol;
%type fresh_symbol T::Symbol;
%type fresh_symbols Vec<T::Symbol>;
%type any_symbol T::Symbol;
%type pattern_symbols Vec<T::Symbol>;
%type pattern Vec<T::Symbol>;
%type keyword T::Keyword;
%type sort T::Sort;
%type sorts Vec<T::Sort>;
%type attribute_value visitors::AttributeValue<T::Constant, T::Symbol, T::SExpr>;
%type attributes Vec<(T::Keyword, visitors::AttributeValue<T::Constant, T::Symbol, T::SExpr>)>;
%type s_expr T::SExpr;
%type s_exprs Vec<T::SExpr>;
%type index visitors::Index<T::Symbol>;
%type indices Vec<visitors::Index<T::Symbol>>;
%type var_binding (T::Symbol, T::Term);
%type var_bindings Vec<(T::Symbol, T::Term)>;
%type sorted_var (T::Symbol, T::Sort);
%type sorted_vars Vec<(T::Symbol, T::Sort)>;
%type match_case (Vec<T::Symbol>, T::Term);
%type match_cases Vec<(Vec<T::Symbol>, T::Term)>;
%type prop_literal (T::Symbol, bool);
%type prop_literals Vec<(T::Symbol, bool)>;
%type datatype_dec visitors::DatatypeDec<T::Symbol, T::Sort>;
%type datatype_decs Vec<visitors::DatatypeDec<T::Symbol, T::Sort>>;
%type selector_dec (T::Symbol, T::Sort);
%type selector_decs Vec<(T::Symbol, T::Sort)>;
%type constructor_dec visitors::ConstructorDec<T::Symbol, T::Sort>;
%type constructor_decs Vec<visitors::ConstructorDec<T::Symbol, T::Sort>>;
%type function_dec visitors::FunctionDec<T::Symbol, T::Sort>;
%type function_decs Vec<visitors::FunctionDec<T::Symbol, T::Sort>>;
%type sort_dec (T::Symbol, crate::Numeral);
%type sort_decs Vec<(T::Symbol, crate::Numeral)>;
%start_symbol command;
bound_symbol ::= Symbol(s) { extra.0.visit_bound_symbol(s)? }
fresh_symbol ::= Symbol(s) { extra.0.visit_fresh_symbol(s, crate::visitors::SymbolKind::Unknown)? }
any_symbol ::= Symbol(s) { extra.0.visit_any_symbol(s)? }
keyword ::= Keyword(s) { extra.0.visit_keyword(s)? }
fresh_symbols ::= fresh_symbol(x) { vec![x] }
fresh_symbols ::= fresh_symbols(mut xs) fresh_symbol(x) { xs.push(x); xs }
pattern_symbols ::= any_symbol(x) { vec![x] }
pattern_symbols ::= fresh_symbols(mut xs) fresh_symbol(x) { xs.push(x); xs }
attribute_value ::= constant(x) { visitors::AttributeValue::Constant(x) }
attribute_value ::= bound_symbol(x) { visitors::AttributeValue::Symbol(x) }
attribute_value ::= LeftParen s_exprs?(xs) RightParen { visitors::AttributeValue::SExpr(xs.unwrap_or_else(Vec::new)) }
attribute_value ::= { visitors::AttributeValue::None }
attributes ::= keyword(k) attribute_value(v) { vec![(k, v)] }
attributes ::= attributes(mut xs) keyword(k) attribute_value(v) { xs.push((k, v)); xs }
s_expr ::= constant(x) { extra.0.visit_constant_s_expr(x)? }
s_expr ::= bound_symbol(x) { extra.0.visit_symbol_s_expr(x)? }
s_expr ::= keyword(x) { extra.0.visit_keyword_s_expr(x)? }
s_expr ::= LeftParen s_exprs?(xs) RightParen { extra.0.visit_application_s_expr(xs.unwrap_or_else(Vec::new))? }
s_exprs ::= s_expr(x) { vec![x] }
s_exprs ::= s_exprs(mut xs) s_expr(x) { xs.push(x); xs }
index ::= Numeral(x) { visitors::Index::Numeral(x) }
index ::= bound_symbol(x) { visitors::Index::Symbol(x) }
indices ::= index(x) { vec![x] }
indices ::= indices(mut xs) index(x) { xs.push(x); xs }
identifier ::= bound_symbol(symbol) { visitors::Identifier::Simple { symbol } }
identifier ::= LeftParen Underscore bound_symbol(symbol) indices(indices) RightParen { visitors::Identifier::Indexed { symbol, indices } }
sort ::= identifier(id) { extra.0.visit_simple_sort(id)? }
sort ::= LeftParen identifier(id) sorts(sorts) RightParen { extra.0.visit_parameterized_sort(id, sorts)? }
sorts ::= sort(x) { vec![x] }
sorts ::= sorts(mut xs) sort(x) { xs.push(x); xs }
qual_identifier ::= identifier(x) { extra.0.visit_simple_identifier(x)? }
qual_identifier ::= LeftParen As identifier(id) sort(s) RightParen { extra.0.visit_sorted_identifier(id, s)? }
constant ::= Numeral(x) { extra.0.visit_numeral_constant(x)? }
constant ::= Decimal(x) { extra.0.visit_decimal_constant(x)? }
constant ::= Hexadecimal(x) { extra.0.visit_hexadecimal_constant(x)? }
constant ::= Binary(x) { extra.0.visit_binary_constant(x)? }
constant ::= String(x) { extra.0.visit_string_constant(x)? }
var_binding ::= LeftParen fresh_symbol(s) term(t) RightParen { (s, t) }
var_bindings ::= var_binding(x) { vec![x] }
var_bindings ::= var_bindings(mut xs) var_binding(x) { xs.push(x); xs }
sorted_var ::= LeftParen fresh_symbol(s) sort(x) RightParen { (s, x) }
sorted_vars ::= sorted_var(x) { vec![x] }
sorted_vars ::= sorted_vars(mut xs) sorted_var(x) { xs.push(x); xs }
pattern ::= any_symbol(x) { vec![x] }
pattern ::= LeftParen pattern_symbols(xs) RightParen { xs }
match_case ::= LeftParen pattern(p) term(t) RightParen { (p, t) }
match_cases ::= match_case(x) { vec![x] }
match_cases ::= match_cases(mut xs) match_case(x) { xs.push(x); xs }
term ::= constant(x) { extra.0.visit_constant(x)? }
term ::= qual_identifier(x) { extra.0.visit_qual_identifier(x)? }
term ::= LeftParen Let LeftParen var_bindings(xs) RightParen term(t) RightParen { extra.0.visit_let(xs, t)? }
term ::= LeftParen Forall LeftParen sorted_vars(xs) RightParen term(t) RightParen { extra.0.visit_forall(xs, t)? }
term ::= LeftParen Exists LeftParen sorted_vars(xs) RightParen term(t) RightParen { extra.0.visit_exists(xs, t)? }
term ::= LeftParen Match term(t) LeftParen match_cases(xs) RightParen RightParen { extra.0.visit_match(t, xs)? }
term ::= LeftParen Exclam term(t) attributes(xs) RightParen { extra.0.visit_attributes(t, xs)? }
term ::= LeftParen qual_identifier(id) terms(xs) RightParen { extra.0.visit_application(id, xs)? }
terms ::= term(x) { vec![x] }
terms ::= terms(mut xs) term(x) { xs.push(x); xs }
prop_literal ::= bound_symbol(x) { (x, true) }
prop_literal ::= LeftParen Symbol(s) bound_symbol(x) RightParen {
if s != "not" {
return Err(extra.0.parsing_error(extra.1.clone(), format!("invalid prop_literal: found {} instead of `not`", s)));
}
(x, false)
}
prop_literals ::= prop_literal(x) { vec![x] }
prop_literals ::= prop_literals(mut xs) prop_literal(x) { xs.push(x); xs }
selector_dec ::= LeftParen fresh_symbol(x) sort(s) RightParen { (x, s) }
selector_decs ::= selector_dec(x) { vec![x] }
selector_decs ::= selector_decs(mut xs) selector_dec(x) { xs.push(x); xs }
constructor_dec ::= LeftParen fresh_symbol(x) selector_decs?(xs) RightParen
{
visitors::ConstructorDec { symbol:x, selectors:xs.unwrap_or_else(Vec::new) }
}
constructor_decs ::= constructor_dec(x) { vec![x] }
constructor_decs ::= constructor_decs(mut xs) constructor_dec(x) { xs.push(x); xs }
datatype_dec ::= LeftParen constructor_decs(xs) RightParen
{
visitors::DatatypeDec { parameters: Vec::new(), constructors: xs }
}
datatype_dec ::= LeftParen Par LeftParen fresh_symbols(ps) RightParen LeftParen constructor_decs(xs) RightParen RightParen
{
visitors::DatatypeDec { parameters: ps, constructors: xs }
}
datatype_decs ::= datatype_dec(x) { vec![x] }
datatype_decs ::= datatype_decs(mut xs) datatype_dec(x) { xs.push(x); xs }
function_dec ::= fresh_symbol(x) LeftParen sorted_vars?(xs) RightParen sort(s)
{
visitors::FunctionDec {
name: x,
parameters: xs.unwrap_or_else(Vec::new),
result: s,
}
}
function_decs ::= function_dec(x) { vec![x] }
function_decs ::= function_decs(mut xs) function_dec(x) { xs.push(x); xs }
sort_dec ::= LeftParen fresh_symbol(x) Numeral(num) RightParen { (x, num) }
sort_decs ::= sort_dec(x) { vec![x] }
sort_decs ::= sort_decs(mut xs) sort_dec(x) { xs.push(x); xs }
command ::= LeftParen Assert term(t) RightParen { extra.0.visit_assert(t)? }
command ::= LeftParen CheckSat RightParen { extra.0.visit_check_sat()? }
command ::= LeftParen CheckSatAssuming LeftParen prop_literals?(xs) RightParen RightParen
{
extra.0.visit_check_sat_assuming(xs.unwrap_or_else(Vec::new))?
}
command ::= LeftParen DeclareConst fresh_symbol(x) sort(s) RightParen
{
extra.0.visit_declare_const(x, s)?
}
command ::= LeftParen DeclareDatatype fresh_symbol(s) datatype_dec(d) RightParen
{
extra.0.visit_declare_datatype(s, d)?
}
command ::= LeftParen DeclareDatatypes LeftParen sort_decs(sorts) RightParen LeftParen datatype_decs(datatypes) RightParen RightParen
{
if sorts.len() == datatypes.len() {
let results = sorts
.into_iter()
.zip(datatypes.into_iter())
.map(|((sort, arity), datatype)| (sort, arity, datatype))
.collect::<Vec<_>>();
extra.0.visit_declare_datatypes(results)?
} else {
return Err(extra.0.parsing_error(extra.1.clone(), format!("wrong number of types in `declare-datatypes`: {} instead of {}", datatypes.len(), sorts.len())));
}
}
command ::= LeftParen DeclareFun fresh_symbol(x) LeftParen sorts?(xs) RightParen sort(r) RightParen
{
extra.0.visit_declare_fun(x, xs.unwrap_or_else(Vec::new), r)?
}
command ::= LeftParen DeclareSort fresh_symbol(x) Numeral(num) RightParen
{
extra.0.visit_declare_sort(x, num)?
}
command ::= LeftParen DefineFun function_dec(d) term(x) RightParen
{
extra.0.visit_define_fun(d, x)?
}
command ::= LeftParen DefineFunRec function_dec(d) term(x) RightParen
{
extra.0.visit_define_fun_rec(d, x)?
}
command ::= LeftParen DefineFunsRec LeftParen function_decs(sigs) RightParen LeftParen terms(xs) RightParen RightParen
{
if sigs.len() == xs.len() {
let defs = sigs.into_iter().zip(xs.into_iter()).collect::<Vec<_>>();
extra.0.visit_define_funs_rec(defs)?
} else {
return Err(extra.0.parsing_error(extra.1.clone(), format!("wrong number of function bodies in `define-funs-rec`: {} instead of {}", xs.len(), sigs.len())));
}
}
command ::= LeftParen DefineSort fresh_symbol(x) LeftParen fresh_symbols?(xs) RightParen sort(r) RightParen
{
extra.0.visit_define_sort(x, xs.unwrap_or_else(Vec::new), r)?
}
command ::= LeftParen Echo String(x) RightParen { extra.0.visit_echo(x)? }
command ::= LeftParen Exit RightParen { extra.0.visit_exit()? }
command ::= LeftParen GetAssertions RightParen { extra.0.visit_get_assertions()? }
command ::= LeftParen GetAssignment RightParen { extra.0.visit_get_assignment()? }
command ::= LeftParen GetInfo keyword(x) RightParen { extra.0.visit_get_info(x)? }
command ::= LeftParen GetModel RightParen { extra.0.visit_get_model()? }
command ::= LeftParen GetOption keyword(x) RightParen { extra.0.visit_get_option(x)? }
command ::= LeftParen GetProof RightParen { extra.0.visit_get_proof()? }
command ::= LeftParen GetUnsatAssumptions RightParen { extra.0.visit_get_unsat_assumptions()? }
command ::= LeftParen GetUnsatCore RightParen { extra.0.visit_get_unsat_core()? }
command ::= LeftParen GetValue terms(xs) RightParen { extra.0.visit_get_value(xs)? }
command ::= LeftParen Pop Numeral(x) RightParen { extra.0.visit_pop(x)? }
command ::= LeftParen Push Numeral(x) RightParen { extra.0.visit_push(x)? }
command ::= LeftParen Reset RightParen { extra.0.visit_reset()? }
command ::= LeftParen ResetAssertions RightParen { extra.0.visit_reset_assertions()? }
command ::= LeftParen SetInfo keyword(k) attribute_value(v) RightParen { extra.0.visit_set_info(k, v)? }
command ::= LeftParen SetLogic bound_symbol(x) RightParen { extra.0.visit_set_logic(x)? }
command ::= LeftParen SetOption keyword(k) attribute_value(v) RightParen { extra.0.visit_set_option(k, v)? }
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::{concrete::*, lexer::Lexer};
pub(crate) fn parse_tokens<I: IntoIterator<Item = Token>>(tokens: I) -> Result<Command, Error> {
let mut builder = SyntaxBuilder::default();
let mut position = crate::Position::default();
let mut p = Parser::new((&mut builder, &mut position));
for token in tokens.into_iter() {
p.parse(token)?;
}
Ok(p.end_of_input()?.0)
}
#[test]
fn test_echo() {
let value = parse_tokens(vec![
Token::LeftParen,
Token::Echo,
Token::String("foo".into()),
Token::RightParen,
])
.unwrap();
assert_eq!(
value,
Command::Echo {
message: "foo".into()
}
);
}
#[test]
fn test_assert_term() {
let value = parse_tokens(Lexer::new(&b"(assert 12)"[..])).unwrap();
assert_eq!(
value,
Command::Assert {
term: Term::Constant(Constant::Numeral(num::BigUint::from(12u32))),
}
);
let value = parse_tokens(Lexer::new(&b"(assert (as A B))"[..])).unwrap();
assert_eq!(
value,
Command::Assert {
term: Term::QualIdentifier(QualIdentifier::Sorted {
identifier: Identifier::Simple {
symbol: Symbol("A".into())
},
sort: Sort::Simple {
identifier: Identifier::Simple {
symbol: Symbol("B".into())
}
},
})
},
);
let value = parse_tokens(Lexer::new(&b"(assert (let ((x (f x 2))) (= x 3)))"[..])).unwrap();
assert_eq!(
value,
Command::Assert {
term: Term::Let {
var_bindings: vec![(
Symbol("x".into()),
Term::Application {
qual_identifier: QualIdentifier::Simple {
identifier: Identifier::Simple {
symbol: Symbol("f".into())
}
},
arguments: vec![
Term::QualIdentifier(QualIdentifier::Simple {
identifier: Identifier::Simple {
symbol: Symbol("x".into())
}
}),
Term::Constant(Constant::Numeral(num::BigUint::from(2u32)))
]
}
)],
term: Box::new(Term::Application {
qual_identifier: QualIdentifier::Simple {
identifier: Identifier::Simple {
symbol: Symbol("=".into())
}
},
arguments: vec![
Term::QualIdentifier(QualIdentifier::Simple {
identifier: Identifier::Simple {
symbol: Symbol("x".into())
}
}),
Term::Constant(Constant::Numeral(num::BigUint::from(3u32)))
]
}),
}
}
);
let value = parse_tokens(Lexer::new(
&b"(assert (forall ((x Bool) (y Int)) (f x y))\n ; dfg \n )"[..],
))
.unwrap();
assert!(matches!(
value,
Command::Assert {
term: Term::Forall { .. }
}
));
let result = parse_tokens(Lexer::new(&b"(assert (forall () (f x y)))"[..]));
assert!(result.is_err());
let value = parse_tokens(Lexer::new(
&b"(assert ( ;foo\n match 3 ( (x (+ x 2)) ) ))"[..],
))
.unwrap();
assert!(matches!(
value,
Command::Assert {
term: Term::Match { .. }
}
));
let value = parse_tokens(Lexer::new(&b"(assert ( ! 3 :f 1 :g (a 3) ))"[..])).unwrap();
assert!(matches!(
value,
Command::Assert {
term: Term::Attributes { .. }
}
));
let value = parse_tokens(Lexer::new(&b"(assert ( f 1 2 3 ))"[..])).unwrap();
assert!(matches!(
value,
Command::Assert {
term: Term::Application { .. }
}
));
}
#[test]
fn test_declare_datatypes_with_comment() {
let value = parse_tokens(Lexer::new(&b"(declare-datatypes ((T@$TypeValue 0)(T@$TypeValueArray 0)) ((($BooleanType ) ($IntegerType ) ($AddressType ) ($StrType ) ($VectorType (|t#$VectorType| T@$TypeValue) ) ($StructType (|name#$StructType| T@$TypeName) (|ts#$StructType| T@$TypeValueArray) ) ($TypeType ) ($ErrorType ) ) (($TypeValueArray (|v#$TypeValueArray| |T@[Int]$TypeValue|) (|l#$TypeValueArray| Int) ) ) ))"[..])).unwrap();
assert!(matches!(value, Command::DeclareDatatypes { .. }));
let mut builder = crate::concrete::SyntaxBuilder::default();
assert_eq!(value, value.clone().accept(&mut builder).unwrap());
}
}