smt2parser 0.6.1

Generic parser library for the SMT-LIB-2 format
Documentation
// Copyright (c) Facebook, Inc. and its affiliates
// SPDX-License-Identifier: MIT OR Apache-2.0

//! The visiting traits expected by the SMT2 parser.

use crate::{Binary, Decimal, Hexadecimal, Numeral};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use strum::EnumIter;

pub trait ConstantVisitor {
    type T;
    type E;

    fn visit_numeral_constant(&mut self, value: Numeral) -> Result<Self::T, Self::E>;
    fn visit_decimal_constant(&mut self, value: Decimal) -> Result<Self::T, Self::E>;
    fn visit_hexadecimal_constant(&mut self, value: Hexadecimal) -> Result<Self::T, Self::E>;
    fn visit_binary_constant(&mut self, value: Binary) -> Result<Self::T, Self::E>;
    fn visit_string_constant(&mut self, value: String) -> Result<Self::T, Self::E>;
}

#[derive(Debug, Clone, Copy, PartialOrd, PartialEq, Ord, Eq, Hash, EnumIter)]
pub enum SymbolKind {
    Unknown,
    Variable,
    Constant,
    Function,
    Sort,
    Datatype,
    TypeVar,
    Constructor,
    Selector,
}

pub trait SymbolVisitor {
    type T;
    type E;

    fn visit_fresh_symbol(&mut self, value: String, kind: SymbolKind) -> Result<Self::T, Self::E>;

    fn visit_bound_symbol(&mut self, value: String) -> Result<Self::T, Self::E> {
        self.visit_fresh_symbol(value, SymbolKind::Unknown)
    }

    // If the symbol is not a valid bound symbol, try to create a fresh one.
    fn visit_any_symbol(&mut self, value: String) -> Result<Self::T, Self::E> {
        self.visit_bound_symbol(value.clone())
            .or_else(|_| self.visit_fresh_symbol(value, SymbolKind::Unknown))
    }

    fn bind_symbol(&mut self, _symbol: &Self::T) {}

    fn unbind_symbol(&mut self, _symbol: &Self::T) {}
}

pub trait KeywordVisitor {
    type T;
    type E;

    fn visit_keyword(&mut self, value: String) -> Result<Self::T, Self::E>;
}

pub trait SExprVisitor<Constant, Symbol, Keyword> {
    type T;
    type E;

    fn visit_constant_s_expr(&mut self, value: Constant) -> Result<Self::T, Self::E>;
    fn visit_symbol_s_expr(&mut self, value: Symbol) -> Result<Self::T, Self::E>;
    fn visit_keyword_s_expr(&mut self, value: Keyword) -> Result<Self::T, Self::E>;
    fn visit_application_s_expr(&mut self, values: Vec<Self::T>) -> Result<Self::T, Self::E>;
}

#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
pub enum Index<Symbol = crate::concrete::Symbol> {
    Numeral(Numeral),
    Symbol(Symbol),
}

impl<S> Index<S> {
    /// Remap the symbols of an Index value.
    pub(crate) fn remap<F, V, T, E>(self, v: &mut V, f: F) -> Result<Index<T>, E>
    where
        F: Copy + Fn(&mut V, S) -> Result<T, E>,
    {
        use Index::*;
        match self {
            Numeral(n) => Ok(Numeral(n)),
            Symbol(s) => Ok(Symbol(f(v, s)?)),
        }
    }
}

/// Concrete identifier.
#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
pub enum Identifier<Symbol = crate::concrete::Symbol> {
    Simple {
        symbol: Symbol,
    },
    Indexed {
        symbol: Symbol,
        indices: Vec<Index<Symbol>>,
    },
}

impl<S> Identifier<S> {
    /// Remap the symbols of an Identifier value.
    pub(crate) fn remap<F, V, T, E>(self, v: &mut V, f: F) -> Result<Identifier<T>, E>
    where
        F: Copy + Fn(&mut V, S) -> Result<T, E>,
    {
        use Identifier::*;
        match self {
            Simple { symbol } => Ok(Simple {
                symbol: f(v, symbol)?,
            }),
            Indexed { symbol, indices } => Ok(Indexed {
                symbol: f(v, symbol)?,
                indices: indices
                    .into_iter()
                    .map(|i| i.remap(v, f))
                    .collect::<Result<_, E>>()?,
            }),
        }
    }
}

pub trait SortVisitor<Symbol> {
    type T;
    type E;

    fn visit_simple_sort(&mut self, identifier: Identifier<Symbol>) -> Result<Self::T, Self::E>;
    fn visit_parameterized_sort(
        &mut self,
        identifier: Identifier<Symbol>,
        parameters: Vec<Self::T>,
    ) -> Result<Self::T, Self::E>;
}

pub trait QualIdentifierVisitor<Identifier, Sort> {
    type T;
    type E;

    fn visit_simple_identifier(&mut self, identifier: Identifier) -> Result<Self::T, Self::E>;
    fn visit_sorted_identifier(
        &mut self,
        identifier: Identifier,
        sort: Sort,
    ) -> Result<Self::T, Self::E>;
}

#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
pub enum AttributeValue<
    Constant = crate::concrete::Constant,
    Symbol = crate::concrete::Symbol,
    SExpr = crate::concrete::SExpr,
> {
    None,
    Constant(Constant),
    Symbol(Symbol),
    SExpr(Vec<SExpr>),
}

impl<T1, T2, T3> AttributeValue<T1, T2, T3> {
    /// Remap the generically-typed values of an AttributeValue.
    pub(crate) fn remap<V, F1, F2, F3, R1, R2, R3, E>(
        self,
        v: &mut V,
        fcst: F1,
        fsym: F2,
        fsexp: F3,
    ) -> Result<AttributeValue<R1, R2, R3>, E>
    where
        F1: Fn(&mut V, T1) -> Result<R1, E>,
        F2: Fn(&mut V, T2) -> Result<R2, E>,
        F3: Fn(&mut V, T3) -> Result<R3, E>,
    {
        use AttributeValue::*;
        let value = match self {
            None => None,
            Constant(value) => Constant(fcst(v, value)?),
            Symbol(value) => Symbol(fsym(v, value)?),
            SExpr(values) => SExpr(
                values
                    .into_iter()
                    .map(|x| fsexp(v, x))
                    .collect::<Result<_, E>>()?,
            ),
        };
        Ok(value)
    }
}

pub trait TermVisitor<Constant, QualIdentifier, Keyword, SExpr, Symbol, Sort> {
    type T;
    type E;

    fn visit_constant(&mut self, constant: Constant) -> Result<Self::T, Self::E>;

    fn visit_qual_identifier(
        &mut self,
        qual_identifier: QualIdentifier,
    ) -> Result<Self::T, Self::E>;

    fn visit_application(
        &mut self,
        qual_identifier: QualIdentifier,
        arguments: Vec<Self::T>,
    ) -> Result<Self::T, Self::E>;

    fn visit_let(
        &mut self,
        var_bindings: Vec<(Symbol, Self::T)>,
        term: Self::T,
    ) -> Result<Self::T, Self::E>;

    fn visit_forall(
        &mut self,
        vars: Vec<(Symbol, Sort)>,
        term: Self::T,
    ) -> Result<Self::T, Self::E>;

    fn visit_exists(
        &mut self,
        vars: Vec<(Symbol, Sort)>,
        term: Self::T,
    ) -> Result<Self::T, Self::E>;

    fn visit_match(
        &mut self,
        term: Self::T,
        cases: Vec<(Vec<Symbol>, Self::T)>,
    ) -> Result<Self::T, Self::E>;

    fn visit_attributes(
        &mut self,
        term: Self::T,
        attributes: Vec<(Keyword, AttributeValue<Constant, Symbol, SExpr>)>,
    ) -> Result<Self::T, Self::E>;
}

#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
pub struct ConstructorDec<Symbol, Sort> {
    pub symbol: Symbol,
    pub selectors: Vec<(Symbol, Sort)>,
}

impl<T1, T2> ConstructorDec<T1, T2> {
    /// Remap the generically-typed values of a ConstructorDec value.
    /// Note: Constructor symbols and selector symbols are remapped using distinct function `fcons` and `fsel`.
    pub(crate) fn remap<V, F1, F2, F3, R1, R2, E>(
        self,
        v: &mut V,
        fcons: F1,
        fsel: F2,
        fsort: F3,
    ) -> Result<ConstructorDec<R1, R2>, E>
    where
        F1: Fn(&mut V, T1) -> Result<R1, E>,
        F2: Fn(&mut V, T1) -> Result<R1, E>,
        F3: Fn(&mut V, T2) -> Result<R2, E>,
    {
        Ok(ConstructorDec {
            symbol: fcons(v, self.symbol)?,
            selectors: self
                .selectors
                .into_iter()
                .map(|(s1, s2)| Ok((fsel(v, s1)?, fsort(v, s2)?)))
                .collect::<Result<_, E>>()?,
        })
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
pub struct DatatypeDec<Symbol = crate::concrete::Symbol, Sort = crate::concrete::Sort> {
    pub parameters: Vec<Symbol>,
    pub constructors: Vec<ConstructorDec<Symbol, Sort>>,
}

impl<T1, T2> DatatypeDec<T1, T2> {
    /// Remap the generically-typed values of a DatatypeDec value.
    pub(crate) fn remap<V, F1, F2, F3, F4, R1, R2, E>(
        self,
        v: &mut V,
        fpar: F1,
        fcons: F2,
        fsel: F3,
        fsort: F4,
    ) -> Result<DatatypeDec<R1, R2>, E>
    where
        F1: Copy + Fn(&mut V, T1) -> Result<R1, E>,
        F2: Copy + Fn(&mut V, T1) -> Result<R1, E>,
        F3: Copy + Fn(&mut V, T1) -> Result<R1, E>,
        F4: Copy + Fn(&mut V, T2) -> Result<R2, E>,
    {
        Ok(DatatypeDec {
            parameters: self
                .parameters
                .into_iter()
                .map(|x| fpar(v, x))
                .collect::<Result<_, E>>()?,
            constructors: self
                .constructors
                .into_iter()
                .map(|c| c.remap(v, fcons, fsel, fsort))
                .collect::<Result<_, E>>()?,
        })
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
pub struct FunctionDec<Symbol = crate::concrete::Symbol, Sort = crate::concrete::Sort> {
    pub name: Symbol,
    pub parameters: Vec<(Symbol, Sort)>,
    pub result: Sort,
}

impl<T1, T2> FunctionDec<T1, T2> {
    /// Remap the generically-typed values of a FunctionDec value.
    pub(crate) fn remap<V, F1, F2, F3, R1, R2, E>(
        self,
        v: &mut V,
        ffun: F1,
        fvar: F2,
        fsort: F3,
    ) -> Result<FunctionDec<R1, R2>, E>
    where
        F1: Copy + Fn(&mut V, T1) -> Result<R1, E>,
        F2: Copy + Fn(&mut V, T1) -> Result<R1, E>,
        F3: Copy + Fn(&mut V, T2) -> Result<R2, E>,
    {
        Ok(FunctionDec {
            name: ffun(v, self.name)?,
            parameters: self
                .parameters
                .into_iter()
                .map(|(s1, s2)| Ok((fvar(v, s1)?, fsort(v, s2)?)))
                .collect::<Result<_, E>>()?,
            result: fsort(v, self.result)?,
        })
    }
}

pub trait CommandVisitor<Term, Symbol, Sort, Keyword, Constant, SExpr> {
    type T;
    type E;

    fn visit_assert(&mut self, term: Term) -> Result<Self::T, Self::E>;

    fn visit_check_sat(&mut self) -> Result<Self::T, Self::E>;

    fn visit_check_sat_assuming(
        &mut self,
        literals: Vec<(Symbol, bool)>,
    ) -> Result<Self::T, Self::E>;

    fn visit_declare_const(&mut self, symbol: Symbol, sort: Sort) -> Result<Self::T, Self::E>;

    fn visit_declare_datatype(
        &mut self,
        symbol: Symbol,
        datatype: DatatypeDec<Symbol, Sort>,
    ) -> Result<Self::T, Self::E>;

    fn visit_declare_datatypes(
        &mut self,
        datatypes: Vec<(Symbol, Numeral, DatatypeDec<Symbol, Sort>)>,
    ) -> Result<Self::T, Self::E>;

    fn visit_declare_fun(
        &mut self,
        symbol: Symbol,
        parameters: Vec<Sort>,
        sort: Sort,
    ) -> Result<Self::T, Self::E>;

    fn visit_declare_sort(&mut self, symbol: Symbol, arity: Numeral) -> Result<Self::T, Self::E>;

    fn visit_define_fun(
        &mut self,
        sig: FunctionDec<Symbol, Sort>,
        term: Term,
    ) -> Result<Self::T, Self::E>;

    fn visit_define_fun_rec(
        &mut self,
        sig: FunctionDec<Symbol, Sort>,
        term: Term,
    ) -> Result<Self::T, Self::E>;

    fn visit_define_funs_rec(
        &mut self,
        funs: Vec<(FunctionDec<Symbol, Sort>, Term)>,
    ) -> Result<Self::T, Self::E>;

    fn visit_define_sort(
        &mut self,
        symbol: Symbol,
        parameters: Vec<Symbol>,
        sort: Sort,
    ) -> Result<Self::T, Self::E>;

    fn visit_echo(&mut self, message: String) -> Result<Self::T, Self::E>;

    fn visit_exit(&mut self) -> Result<Self::T, Self::E>;

    fn visit_get_assertions(&mut self) -> Result<Self::T, Self::E>;

    fn visit_get_assignment(&mut self) -> Result<Self::T, Self::E>;

    fn visit_get_info(&mut self, flag: Keyword) -> Result<Self::T, Self::E>;

    fn visit_get_model(&mut self) -> Result<Self::T, Self::E>;

    fn visit_get_option(&mut self, keyword: Keyword) -> Result<Self::T, Self::E>;

    fn visit_get_proof(&mut self) -> Result<Self::T, Self::E>;

    fn visit_get_unsat_assumptions(&mut self) -> Result<Self::T, Self::E>;

    fn visit_get_unsat_core(&mut self) -> Result<Self::T, Self::E>;

    fn visit_get_value(&mut self, terms: Vec<Term>) -> Result<Self::T, Self::E>;

    fn visit_pop(&mut self, level: Numeral) -> Result<Self::T, Self::E>;

    fn visit_push(&mut self, level: Numeral) -> Result<Self::T, Self::E>;

    fn visit_reset(&mut self) -> Result<Self::T, Self::E>;

    fn visit_reset_assertions(&mut self) -> Result<Self::T, Self::E>;

    fn visit_set_info(
        &mut self,
        keyword: Keyword,
        value: AttributeValue<Constant, Symbol, SExpr>,
    ) -> Result<Self::T, Self::E>;

    fn visit_set_logic(&mut self, symbol: Symbol) -> Result<Self::T, Self::E>;

    fn visit_set_option(
        &mut self,
        keyword: Keyword,
        value: AttributeValue<Constant, Symbol, SExpr>,
    ) -> Result<Self::T, Self::E>;
}

/// A visitor for the entire SMT2 syntax.
pub trait Smt2Visitor:
    ConstantVisitor<T = <Self as Smt2Visitor>::Constant, E = <Self as Smt2Visitor>::Error>
    + SymbolVisitor<T = <Self as Smt2Visitor>::Symbol, E = <Self as Smt2Visitor>::Error>
    + KeywordVisitor<T = <Self as Smt2Visitor>::Keyword, E = <Self as Smt2Visitor>::Error>
    + SExprVisitor<
        <Self as Smt2Visitor>::Constant,
        <Self as Smt2Visitor>::Symbol,
        <Self as Smt2Visitor>::Keyword,
        T = <Self as Smt2Visitor>::SExpr,
        E = <Self as Smt2Visitor>::Error,
    > + QualIdentifierVisitor<
        Identifier<<Self as Smt2Visitor>::Symbol>,
        <Self as Smt2Visitor>::Sort,
        T = <Self as Smt2Visitor>::QualIdentifier,
        E = <Self as Smt2Visitor>::Error,
    > + SortVisitor<
        <Self as Smt2Visitor>::Symbol,
        T = <Self as Smt2Visitor>::Sort,
        E = <Self as Smt2Visitor>::Error,
    > + TermVisitor<
        <Self as Smt2Visitor>::Constant,
        <Self as Smt2Visitor>::QualIdentifier,
        <Self as Smt2Visitor>::Keyword,
        <Self as Smt2Visitor>::SExpr,
        <Self as Smt2Visitor>::Symbol,
        <Self as Smt2Visitor>::Sort,
        T = <Self as Smt2Visitor>::Term,
        E = <Self as Smt2Visitor>::Error,
    > + CommandVisitor<
        <Self as Smt2Visitor>::Term,
        <Self as Smt2Visitor>::Symbol,
        <Self as Smt2Visitor>::Sort,
        <Self as Smt2Visitor>::Keyword,
        <Self as Smt2Visitor>::Constant,
        <Self as Smt2Visitor>::SExpr,
        T = <Self as Smt2Visitor>::Command,
        E = <Self as Smt2Visitor>::Error,
    >
{
    type Error;
    type Constant;
    type QualIdentifier;
    type Keyword;
    type Sort;
    type SExpr;
    type Symbol;
    type Term;
    type Command;

    fn syntax_error(&mut self, position: crate::Position, s: String) -> Self::Error;
    fn parsing_error(&mut self, position: crate::Position, s: String) -> Self::Error;
}

impl<Symbol> std::fmt::Display for Index<Symbol>
where
    Symbol: std::fmt::Display,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        // ⟨numeral⟩ | ⟨symbol⟩
        match self {
            Index::Numeral(num) => write!(f, "{}", num),
            Index::Symbol(sym) => write!(f, "{}", sym),
        }
    }
}

impl<Symbol> std::fmt::Display for Identifier<Symbol>
where
    Symbol: std::fmt::Display,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        // ⟨symbol⟩ | ( _ ⟨symbol⟩ ⟨index⟩+ )
        match self {
            Identifier::Simple { symbol } => write!(f, "{}", symbol),
            Identifier::Indexed { symbol, indices } => {
                write!(f, "(_ {} {})", symbol, indices.iter().format(" "))
            }
        }
    }
}

impl<Constant, Symbol, SExpr> std::fmt::Display for AttributeValue<Constant, Symbol, SExpr>
where
    Constant: std::fmt::Display,
    Symbol: std::fmt::Display,
    SExpr: std::fmt::Display,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        // ⟨spec_constant⟩ | ⟨symbol⟩ | ( ⟨s_expr⟩∗ ) |
        use AttributeValue::*;
        match self {
            None => Ok(()),
            Constant(c) => write!(f, "{}", c),
            Symbol(s) => write!(f, "{}", s),
            SExpr(values) => write!(f, "({})", values.iter().format(" ")),
        }
    }
}

impl<Symbol, Sort> std::fmt::Display for ConstructorDec<Symbol, Sort>
where
    Symbol: std::fmt::Display,
    Sort: std::fmt::Display,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        // ( ⟨symbol⟩ ⟨selector_dec⟩∗ )
        write!(
            f,
            "({} {})",
            self.symbol,
            self.selectors
                .iter()
                .format_with(" ", |(symbol, sort), f| f(&format_args!(
                    "({} {})",
                    symbol, sort
                )))
        )
    }
}

impl<Symbol, Sort> std::fmt::Display for DatatypeDec<Symbol, Sort>
where
    Symbol: std::fmt::Display,
    Sort: std::fmt::Display,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        // ( ⟨constructor_dec⟩+ ) | ( par ( ⟨symbol⟩+ ) ( ⟨constructor_dec⟩+ ) )
        if self.parameters.is_empty() {
            write!(f, "({})", self.constructors.iter().format(" "))
        } else {
            let symbols = format!("({})", self.parameters.iter().format(" "));
            let constructors = format!("({})", self.constructors.iter().format(" "));
            write!(f, "(par {} {})", symbols, constructors)
        }
    }
}

impl<Symbol, Sort> std::fmt::Display for FunctionDec<Symbol, Sort>
where
    Symbol: std::fmt::Display,
    Sort: std::fmt::Display,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        // ⟨symbol⟩ ( ⟨sorted_var⟩∗ ) ⟨sort⟩
        let params = self
            .parameters
            .iter()
            .format_with(" ", |(symbol, sort), f| {
                f(&format_args!("({} {})", symbol, sort))
            });
        write!(f, "{} ({}) {}", self.name, params, self.result)
    }
}