#include <fstream>
#include "Debug/Assertion.hpp"
#include "Lib/Int.hpp"
#include "Lib/Environment.hpp"
#include "Kernel/Clause.hpp"
#include "Kernel/FormulaUnit.hpp"
#include "Kernel/FormulaVarIterator.hpp"
#include "Kernel/Inference.hpp"
#include "Kernel/Matcher.hpp"
#include "Kernel/Signature.hpp"
#include "Kernel/SortHelper.hpp"
#include "Kernel/SubstHelper.hpp"
#include "Kernel/TermIterators.hpp"
#include "Kernel/Theory.hpp"
#include "Shell/AnswerLiteralManager.hpp"
#include "Shell/Options.hpp"
#include "Shell/DistinctGroupExpansion.hpp"
#include "Shell/UIHelper.hpp"
#include "Parse/TPTP.hpp"
using namespace std;
using namespace Lib;
using namespace Kernel;
using namespace Shell;
using namespace Parse;
#define DEBUG_SHOW_UNITS 0
#define DEBUG_SOURCE 0
DHMap<unsigned, std::string> TPTP::_axiomNames;
DHMap<unsigned, Map<unsigned,std::string>> TPTP::_questionVariableNames;
const int TPTP::HOL_CONSTANTS_LOWER_BOUND = 99u;
const int TPTP::LAMBDA = 100u;
const int TPTP::APP = 101u;
const int TPTP::PI = 102u;
const int TPTP::SIGMA = 103u;
UnitList* TPTP::parse(istream& input)
{
Parse::TPTP parser(input);
parser.parse();
return parser.units();
}
Unit* TPTP::parseFormulaFromString(const std::string& str)
{
std::stringstream input(str+")."); Parse::TPTP parser(input);
parser._lastInputType = UnitInputType::AXIOM;
parser._bools.push(true); parser._strings.push("dummy_name");
parser._states.push(END_FOF); parser.parseImpl(FORMULA);
return parser._units.list()->head();
}
TPTP::TPTP(std::istream &in, UnitList::FIFO unitBuffer)
: _containsConjecture(false),
currentFile { &in, {}, {}, 1 },
_units(unitBuffer),
_isThf(false),
_containsPolymorphism(false),
_currentColor(COLOR_TRANSPARENT),
_lastPushed(TM),
_modelDefinition(false),
_insideEqualityArgument(0),
_unitSources(0),
_filterReserved(false),
_seenConjecture(false)
{
}
TPTP::~TPTP()
{
}
void TPTP::parse()
{
try {
parseImpl();
} catch (UserErrorException &e) {
e.line = lineNumber();
e.filename = currentPath();
throw;
}
}
void TPTP::parseImpl(State initialState)
{
_cend = 0;
_tend = 0;
currentFile.lineNumber = 1;
_states.push(initialState);
while (!_states.isEmpty()) {
State s = _states.pop();
#ifdef DEBUG_SHOW_STATE
cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << endl;
cout << toString(s) << endl;
#endif
switch (s) {
case UNIT_LIST:
unitList();
break;
case FOF:
fof(true);
break;
case THF:
_isThf = true;
case TFF:
tff();
break;
case CNF:
fof(false);
break;
case FORMULA:
formula();
break;
case FUN_APP:
funApp();
break;
case ARGS:
args();
break;
case TERM:
term();
break;
case TERM_INFIX:
termInfix();
break;
case END_TERM:
endTerm();
break;
case END_ARGS:
endArgs();
break;
case FORMULA_INFIX:
formulaInfix();
break;
case END_EQ:
endEquality();
break;
case MID_EQ:
midEquality();
break;
case VAR_LIST:
varList();
break;
case TAG:
tag();
break;
case END_FOF:
endFof();
break;
case SIMPLE_FORMULA:
simpleFormula();
break;
case END_FORMULA:
endFormula();
break;
case END_APP:
endApp();
break;
case HOL_FORMULA:
holFormula();
break;
case END_HOL_FORMULA:
endHolFormula();
break;
case HOL_TERM:
holTerm();
break;
case FORMULA_INSIDE_TERM:
formulaInsideTerm();
break;
case END_FORMULA_INSIDE_TERM:
endFormulaInsideTerm();
break;
case END_TERM_AS_FORMULA:
endTermAsFormula();
break;
case INCLUDE:
include();
break;
case TYPE:
type();
break;
case SIMPLE_TYPE:
simpleType();
break;
case END_TYPE:
endType();
break;
case END_TFF:
endTff();
break;
case UNBIND_VARIABLES:
unbindVariables();
break;
case VAMPIRE:
vampire();
break;
case END_ITE:
endIte();
break;
case LET_TYPE:
letType();
break;
case END_LET_TYPES:
endLetTypes();
break;
case DEFINITION:
definition();
break;
case MID_DEFINITION:
midDefinition();
break;
case END_DEFINITION:
endDefinition();
break;
case SYMBOL_DEFINITION:
symbolDefinition();
break;
case TUPLE_DEFINITION:
if(!env.options->newCNF()){ USER_ERROR("Set --newcnf on if using tuples"); }
tupleDefinition();
break;
case END_LET:
endLet();
break;
case END_THEORY_FUNCTION:
endTheoryFunction();
break;
case END_TUPLE:
if(!env.options->newCNF()){ USER_ERROR("Set --newcnf on if using tuples"); }
endTuple();
break;
default:
#if VDEBUG
PARSE_ERROR("Don't know how to process state "s + toString(s));
#else
PARSE_ERROR("Don't know how to process state ");
#endif
}
#ifdef DEBUG_SHOW_STATE
cout << "----------------------------------------" << endl;
printStacks();
cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << endl << endl;
#endif
}
}
std::string TPTP::Token::toString() const
{
std::string str = TPTP::toString(tag);
return str == "" ? content : str;
}
std::string TPTP::toString(Tag tag)
{
switch (tag) {
case T_EOF:
return "<eof>";
case T_LPAR:
return "(";
case T_RPAR:
return ")";
case T_LBRA:
return "[";
case T_RBRA:
return "]";
case T_COMMA:
return ",";
case T_COLON:
return ":";
case T_NOT:
return "~";
case T_AND:
return "&";
case T_EQUAL:
return "=";
case T_NEQ:
return "!=";
case T_FORALL:
return "!";
case T_EXISTS:
return "?";
case T_PI:
return "??";
case T_SIGMA:
return "!!";
case T_IMPLY:
return "=>";
case T_XOR:
return "<~>";
case T_IFF:
return "<=>";
case T_REVERSE_IMP:
return "<=";
case T_DOT:
return ".";
case T_OR:
return "|";
case T_ASS:
return ":=";
case T_LAMBDA:
return "^";
case T_APP:
return "@";
case T_STAR:
return "*";
case T_UNION:
return "+";
case T_ARROW:
return ">";
case T_SUBTYPE:
return "<<";
case T_NOT_OR:
return "~|";
case T_NOT_AND:
return "~&";
case T_SEQUENT:
return "-->";
case T_TYPE_QUANT:
return "!>";
case T_CHOICE:
return "@+";
case T_POLY_CHOICE:
return "@@+";
case T_DEF_DESC:
return "@-";
case T_POLY_DEF_DESC:
return "@@-";
case T_THF_QUANT_SOME:
return "?*";
case T_TRUE:
return "$true";
case T_FALSE:
return "$false";
case T_TTYPE:
return "$tType";
case T_BOOL_TYPE:
return "$o";
case T_DEFAULT_TYPE:
return "$i";
case T_RATIONAL_TYPE:
return "$rat";
case T_REAL_TYPE:
return "$real";
case T_INTEGER_TYPE:
return "$int";
case T_TUPLE:
return "$tuple";
case T_THEORY_SORT:
return "";
case T_THEORY_FUNCTION:
return "";
case T_FOT:
return "$fot";
case T_FOF:
return "$fof";
case T_TFF:
return "$tff";
case T_THF:
return "$thf";
case T_ITE:
return "$ite";
case T_LET:
return "$let";
case T_NAME:
case T_REAL:
case T_RAT:
case T_INT:
case T_VAR:
case T_DOLLARS:
case T_STRING:
return "";
default:
ASSERTION_VIOLATION
}
}
bool TPTP::readToken(Token& tok)
{
skipWhiteSpacesAndComments();
switch (getChar(0)) {
case 0:
tok.tag = T_EOF;
return false;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
tok.tag = T_NAME;
readName(tok);
return true;
case '$':
readReserved(tok);
return true;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
case '_':
tok.tag = T_VAR;
readName(tok);
return true;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
tok.tag = readNumber(tok);
return true;
case '"':
tok.tag = T_STRING;
readString(tok);
return true;
case '\'':
tok.tag = T_NAME;
readAtom(tok);
return true;
case '(':
tok.tag = T_LPAR;
resetChars();
return true;
case ')':
tok.tag = T_RPAR;
resetChars();
return true;
case '[':
tok.tag = T_LBRA;
resetChars();
return true;
case ']':
tok.tag = T_RBRA;
resetChars();
return true;
case ',':
tok.tag = T_COMMA;
resetChars();
return true;
case ':':
if (getChar(1) == '=') {
tok.tag = T_ASS;
resetChars();
return true;
}
tok.tag = T_COLON;
shiftChars(1);
return true;
case '~':
if (getChar(1) == '&') {
tok.tag = T_NOT_AND;
resetChars();
return true;
}
if (getChar(1) == '|') {
tok.tag = T_NOT_OR;
resetChars();
return true;
}
tok.tag = T_NOT;
shiftChars(1);
return true;
case '=':
if (getChar(1) == '>') {
tok.tag = T_IMPLY;
resetChars();
return true;
}
tok.tag = T_EQUAL;
shiftChars(1);
return true;
case '&':
tok.tag = T_AND;
resetChars();
return true;
case '^':
tok.tag = T_LAMBDA;
resetChars();
return true;
case '@':
if (getChar(1) == '+') {
tok.tag = T_CHOICE;
resetChars();
return true;
}
if (getChar(1) == '-') {
tok.tag = T_DEF_DESC;
resetChars();
return true;
}
if (getChar(1) == '@' && getChar(2) == '+'){
tok.tag = T_POLY_CHOICE;
resetChars();
return true;
}
if (getChar(1) == '@' && getChar(2) == '-'){
tok.tag = T_POLY_DEF_DESC;
resetChars();
return true;
}
tok.tag = T_APP;
shiftChars(1);
return true;
case '*':
tok.tag = T_STAR;
resetChars();
return true;
case '>':
tok.tag = T_ARROW;
resetChars();
return true;
case '!':
if (getChar(1) == '=') {
tok.tag = T_NEQ;
resetChars();
return true;
}
if (getChar(1) == '>') {
tok.tag = T_TYPE_QUANT;
resetChars();
return true;
}
if (getChar(1) == '!') {
tok.tag = T_PI;
resetChars();
return true;
}
tok.tag = T_FORALL;
shiftChars(1);
return true;
case '?':
if (getChar(1) == '?') {
tok.tag = T_SIGMA;
resetChars();
return true;
}
if (getChar(1) == '*') {
tok.tag = T_THF_QUANT_SOME;
resetChars();
return true;
}
tok.tag = T_EXISTS;
shiftChars(1);
return true;
case '<':
if (getChar(1) == '<') {
tok.tag = T_SUBTYPE;
resetChars();
return true;
}
if (getChar(1) == '~' && getChar(2) == '>') {
tok.tag = T_XOR;
resetChars();
return true;
}
if (getChar(1) != '=') {
PARSE_ERROR("unrecognized symbol");
}
if (getChar(2) == '>') {
tok.tag = T_IFF;
resetChars();
return true;
}
tok.tag = T_REVERSE_IMP;
shiftChars(2);
return true;
case '.':
tok.tag = T_DOT;
resetChars();
return true;
case '|':
tok.tag = T_OR;
resetChars();
return true;
case '-':
if (getChar(1) == '-' && getChar(2) == '>') {
tok.tag = T_SEQUENT;
resetChars();
return true;
}
tok.tag = readNumber(tok);
return true;
case '+':
if (getChar(1) < '0' || getChar(1) > '9') {
tok.tag = T_UNION;
shiftChars(1);
return true;
}
tok.tag = readNumber(tok);
return true;
default:
PARSE_ERROR("Bad character");
}
}
void TPTP::skipWhiteSpacesAndComments()
{
for (;;) {
switch (getChar(0)) {
case 0: return;
case '\n':
case '\r':
currentFile.lineNumber++;
case ' ':
case '\t':
case '\f':
resetChars();
break;
case '%': resetChars();
for (int n=0;;n++) {
int c = getChar(n);
if (c == 0) {
resetChars();
getChar(0);
return;
}
if (c == '\n') {
currentFile.lineNumber++;
#if VDEBUG
if(_units.list() == 0 && restoreFiles.empty()){
_chars[n]='\0';
std::string cline(_chars.content());
if(cline.find("Status")!=std::string::npos){
if(cline.find("Theorem")!=std::string::npos){ UIHelper::setExpectingUnsat(); }
else if(cline.find("Unsatisfiable")!=std::string::npos){ UIHelper::setExpectingUnsat(); }
else if(cline.find("ContradictoryAxioms")!=std::string::npos){ UIHelper::setExpectingUnsat(); }
else if(cline.find("Satisfiable")!=std::string::npos){ UIHelper::setExpectingSat(); }
else if(cline.find("CounterSatisfiable")!=std::string::npos){ UIHelper::setExpectingSat(); }
}
}
#endif
resetChars();
break;
}
}
break;
case '/': if (getChar(1) != '*') {
return;
}
resetChars();
for (;;) {
int c = getChar(0);
if( c == '\n' || c == '\r'){ currentFile.lineNumber++; }
if (!c) {
return;
}
resetChars();
if (c != '*') {
continue;
}
c = getChar(0);
resetChars();
if (c != '/') {
continue;
}
break;
}
break;
default:
return;
}
}
}
void TPTP::readName(Token& tok)
{
for (int n = 1;;n++) {
switch (getChar(n)) {
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
case '_':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
case '$':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
break;
default:
ASS(_chars.content()[0] != '$');
tok.content.assign(_chars.content(),n);
shiftChars(n);
return;
}
}
}
void TPTP::readReserved(Token& tok)
{
int n = 1;
for (;;n++) {
switch (getChar(n)) {
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
case '_':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
case '$':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
break;
default:
tok.content.assign(_chars.content(),n);
goto out;
}
}
out:
if (tok.content == "$true") {
tok.tag = T_TRUE;
}
else if (tok.content == "$false") {
tok.tag = T_FALSE;
}
else if (tok.content == "$ite_f" || tok.content == "$ite_t" || tok.content == "$ite") {
tok.tag = T_ITE;
tok.content = "$ite";
}
else if (tok.content == "$let_tt" || tok.content == "$let_tf" || tok.content == "$let_ft" || tok.content == "$let_ff" || tok.content == "$let") {
tok.tag = T_LET;
tok.content = "$let";
}
else if (tok.content == "$tType") {
tok.tag = T_TTYPE;
}
else if (tok.content == "$o" || tok.content == "$oType") {
tok.tag = T_BOOL_TYPE;
}
else if (tok.content == "$i" || tok.content == "$iType") {
tok.tag = T_DEFAULT_TYPE;
}
else if (tok.content == "$int") {
tok.tag = T_INTEGER_TYPE;
}
else if (tok.content == "$rat") {
tok.tag = T_RATIONAL_TYPE;
}
else if (tok.content == "$real") {
tok.tag = T_REAL_TYPE;
}
else if (tok.content == "$tuple") {
tok.tag = T_TUPLE;
}
else if (isTheoryFunction(tok.content)) {
tok.tag = T_THEORY_FUNCTION;
}
else if (isTheorySort(tok.content)) {
tok.tag = T_THEORY_SORT;
}
else if (tok.content == "$fot") {
tok.tag = T_FOT;
}
else if (tok.content == "$fof") {
tok.tag = T_FOF;
}
else if (tok.content == "$tff") {
tok.tag = T_TFF;
}
else if (tok.content == "$thf") {
tok.tag = T_THF;
}
else if (tok.content.substr(0,2) == "$$" && !_filterReserved) {
tok.tag = T_DOLLARS;
}
else {
if(_filterReserved){
unsigned c=0;
for(;;c++){ if(getChar(c)!='$') break;}
shiftChars(c);
n=n-c;
tok.content.assign(_chars.content(),n);
}
tok.tag = T_NAME;
}
shiftChars(n);
}
void TPTP::readString(Token& tok)
{
for (int n = 1;;n++) {
int c = getChar(n);
if (!c) {
PARSE_ERROR("non-terminated string");
}
if (c == '\\') { c = getChar(++n);
if (!c) {
PARSE_ERROR("non-terminated string");
}
continue;
}
if (c == '"') {
tok.content.assign(_chars.content()+1,n-1);
resetChars();
return;
}
}
}
void TPTP::readAtom(Token& tok)
{
for (int n = 1;;n++) {
int c = getChar(n);
if (!c) {
PARSE_ERROR("non-terminated quoted atom");
}
if (c == '\\') { c = getChar(++n);
if (!c) {
PARSE_ERROR("non-terminated quoted atom");
}
continue;
}
if (c == '\'') {
tok.content.assign(_chars.content()+1,n-1);
resetChars();
return;
}
}
}
void TPTP::ParseErrorException::cry(std::ostream& str) const
{
str << "parse error in " << _path << ", line " << _ln << ": ";
str << _message << "\n";
}
TPTP::Tag TPTP::readNumber(Token& tok)
{
int c = getChar(0);
ASS(c);
int pos = decimal((c == '+' || c == '-') ? 1 : 0);
switch (getChar(pos)) {
case '/':
pos = positiveDecimal(pos+1);
tok.content.assign(_chars.content(),pos);
shiftChars(pos);
return T_RAT;
case 'E':
case 'e':
{
char c = getChar(pos+1);
pos = decimal((c == '+' || c == '-') ? pos+2 : pos+1);
tok.content.assign(_chars.content(),pos);
shiftChars(pos);
}
return T_REAL;
case '.':
{
int p = pos;
do {
c = getChar(++pos);
}
while (c >= '0' && c <= '9');
if (pos == p+1) {
PARSE_ERROR("wrong number format");
}
c = getChar(pos);
if (c == 'e' || c == 'E') {
c = getChar(pos+1);
pos = decimal((c == '+' || c == '-') ? pos+2 : pos+1);
}
tok.content.assign(_chars.content(),pos);
shiftChars(pos);
}
return T_REAL;
default:
tok.content.assign(_chars.content(),pos);
shiftChars(pos);
return T_INT;
}
}
int TPTP::decimal(int pos)
{
switch (getChar(pos)) {
case '0':
return pos+1;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
break;
default:
PARSE_ERROR("wrong number format");
}
int c;
do {
c = getChar(++pos);
}
while (c >= '0' && c <= '9');
return pos;
}
int TPTP::positiveDecimal(int pos)
{
switch (getChar(pos)) {
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
break;
default:
PARSE_ERROR("wrong number format");
}
int c;
do {
c = getChar(++pos);
}
while (c >= '0' && c <= '9');
return pos;
}
void TPTP::unitList()
{
Token& tok = getTok(0);
if (tok.tag == T_EOF) {
resetToks();
if (restoreFiles.empty()) {
return;
}
resetChars();
delete currentFile.in;
currentFile = std::move(restoreFiles.back());
restoreFiles.pop_back();
_states.push(UNIT_LIST);
return;
}
if (tok.tag != T_NAME) {
PARSE_ERROR_TOK("cnf(), fof(), vampire() or include() expected",tok);
}
std::string name(tok.content);
_states.push(UNIT_LIST);
if (name == "cnf") {
_states.push(CNF);
resetToks();
return;
}
if (name == "fof") {
_states.push(FOF);
resetToks();
return;
}
if (name == "tff") {
_states.push(TFF);
resetToks();
return;
}
if (name == "thf") {
_states.push(THF);
resetToks();
return;
}
if (name == "vampire") {
_states.push(VAMPIRE);
resetToks();
return;
}
if (name == "include") {
_states.push(INCLUDE);
resetToks();
return;
}
PARSE_ERROR_TOK("cnf(), fof(), vampire() or include() expected",tok);
}
void TPTP::fof(bool fo)
{
_bools.push(fo);
consumeToken(T_LPAR);
Token& tok = getTok(0);
switch(tok.tag) {
case T_NAME:
_strings.push(tok.content);
resetToks();
break;
case T_INT:
_strings.push(tok.content);
resetToks();
break;
default:
PARSE_ERROR_TOK("Unit name expected",tok);
}
consumeToken(T_COMMA);
tok = getTok(0);
std::string tp = name();
_isQuestion = false;
if(_modelDefinition){
_lastInputType = UnitInputType::MODEL_DEFINITION;
}
else if (tp == "axiom" || tp == "plain") {
_lastInputType = UnitInputType::AXIOM;
}
else if(tp == "extensionality"){
_lastInputType = UnitInputType::EXTENSIONALITY_AXIOM;
}
else if (tp == "definition") {
_lastInputType = UnitInputType::AXIOM;
}
else if (tp == "conjecture") {
_containsConjecture = true;
_lastInputType = UnitInputType::CONJECTURE;
}
else if (tp == "question") {
_isQuestion = true;
_containsConjecture = true;
_lastInputType = UnitInputType::CONJECTURE;
}
else if (tp == "negated_conjecture") {
_lastInputType = UnitInputType::NEGATED_CONJECTURE;
}
else if (tp == "hypothesis" || tp == "theorem" || tp == "lemma") {
_lastInputType = UnitInputType::ASSUMPTION;
}
else if (tp == "claim") {
_lastInputType = UnitInputType::CLAIM;
}
else if (tp == "assumption" || tp == "unknown") {
USER_ERROR("Unsupported unit type '", tp, "' found");
}
else {
PARSE_ERROR("unit type, such as axiom or definition expected but "s + tp + " found");
}
consumeToken(T_COMMA);
_states.push(END_FOF);
_states.push(FORMULA);
}
void TPTP::tff()
{
consumeToken(T_LPAR);
Token& tok = getTok(0);
switch(tok.tag) {
case T_NAME:
case T_INT:
_strings.push(tok.content);
resetToks();
break;
default:
PARSE_ERROR_TOK("Unit name expected",tok);
}
consumeToken(T_COMMA);
tok = getTok(0);
std::string tp = name();
if (tp == "type") {
consumeToken(T_COMMA);
int lpars = 0;
for (;;) {
tok = getTok(0);
if (tok.tag != T_LPAR) {
break;
}
lpars++;
resetToks();
}
std::string nm = name();
consumeToken(T_COLON);
if(_isThf){
tok = getTok(0);
if (tok.tag == T_TTYPE) {
resetToks();
unsigned arity = getConstructorArity();
bool added = false;
unsigned fun = env.signature->addTypeCon(nm, arity, added);
Signature::Symbol* symbol = env.signature->getTypeCon(fun);
OperatorType* ot = OperatorType::getTypeConType(arity);
if (!added) {
if(symbol->fnType()!=ot){
PARSE_ERROR_TOK("Type constructor declared with two different types",tok);
}
} else{
symbol->setType(ot);
_typeConstructorArities.insert(nm, arity);
}
while (lpars--) {
consumeToken(T_RPAR);
}
consumeToken(T_RPAR);
consumeToken(T_DOT);
return;
}
}
_ints.push(lpars);
_strings.push(nm);
_states.push(END_TFF);
_states.push(TYPE);
return;
}
_bools.push(true); _isQuestion = false;
if(_modelDefinition){
_lastInputType = UnitInputType::MODEL_DEFINITION;
}
else if (tp == "axiom" || tp == "plain") {
_lastInputType = UnitInputType::AXIOM;
}
else if (tp == "extensionality"){
_lastInputType = UnitInputType::EXTENSIONALITY_AXIOM;
}
else if (tp == "definition") {
_lastInputType = UnitInputType::AXIOM;
}
else if (tp == "conjecture") {
_containsConjecture = true;
_lastInputType = UnitInputType::CONJECTURE;
}
else if (tp == "question") {
_isQuestion = true;
_containsConjecture = true;
_lastInputType = UnitInputType::CONJECTURE;
}
else if (tp == "negated_conjecture") {
_lastInputType = UnitInputType::NEGATED_CONJECTURE;
}
else if (tp == "hypothesis" || tp == "theorem" || tp == "lemma") {
_lastInputType = UnitInputType::ASSUMPTION;
}
else if (tp == "assumption" || tp == "unknown") {
USER_ERROR("Unsupported unit type '", tp);
}
else if (tp == "claim") {
_lastInputType = UnitInputType::CLAIM;
}
else {
PARSE_ERROR("unit type, such as axiom or definition expected but " + tp + " found");
}
consumeToken(T_COMMA);
_states.push(END_FOF);
_states.push(FORMULA);
}
unsigned TPTP::getConstructorArity()
{
unsigned arity = 0;
Token tok = getTok(0);
while(tok.tag == T_ARROW || tok.tag == T_TTYPE){
arity += (tok.tag == T_TTYPE);
resetToks();
tok = getTok(0);
}
return arity;
}
void TPTP::holFormula()
{
Token tok = getTok(0);
switch (tok.tag) {
case T_NOT:
resetToks();
_connectives.push(NOT);
_states.push(HOL_FORMULA);
return;
case T_SIGMA:
resetToks();
readTypeArgs(1);
_termLists.push(createFunctionApplication("vSIGMA", 1));
return;
case T_PI:
resetToks();
readTypeArgs(1);
_termLists.push(createFunctionApplication("vPI", 1));
return;
case T_FORALL:
case T_EXISTS:
case T_LAMBDA:
resetToks();
consumeToken(T_LBRA);
_connectives.push(tok.tag == T_FORALL ? FORALL : (tok.tag == T_LAMBDA ? LAMBDA : EXISTS));
_states.push(HOL_FORMULA);
addTagState(T_COLON);
addTagState(T_RBRA);
_states.push(VAR_LIST);
return;
case T_LPAR:
resetToks();
addTagState(T_RPAR);
_connectives.push(-1);
_states.push(END_HOL_FORMULA);
_states.push(HOL_FORMULA);
return;
case T_RPAR: {
ASS(_connectives.top() == NOT);
_connectives.pop();
_termLists.push(createFunctionApplication("vNOT", 0));
return;
}
case T_CHOICE:
case T_DEF_DESC:
case T_POLY_CHOICE:
case T_POLY_DEF_DESC:
{
USER_ERROR("At the moment Vampire HOL cannot parse definite and indefinite description operators");
}
case T_STRING:
case T_INT:
case T_RAT:
case T_REAL: _states.push(END_EQ);
_states.push(TERM);
_states.push(MID_EQ);
_states.push(TERM);
return;
case T_TRUE:
resetToks();
_formulas.push(new Formula(true));
_lastPushed = FORM;
return;
case T_FALSE:
resetToks();
_formulas.push(new Formula(false));
_lastPushed = FORM;
return;
case T_AND:
case T_OR:
case T_IMPLY:
case T_IFF:
case T_NAME:
case T_VAR:
case T_ITE:
case T_THEORY_FUNCTION:
case T_LET:
case T_LBRA:
_states.push(HOL_TERM);
return;
case T_APP:
if(_connectives.top() == NOT ||
_connectives.top() == PI ||
_connectives.top() == SIGMA){
resetToks();
_states.push(HOL_FORMULA);
return;
}
default:
PARSE_ERROR_TOK("formula or term expected",tok);
}
}
void TPTP::holTerm()
{
Token tok = getTok(0);
resetToks();
std::string name = tok.content;
unsigned arity = _typeArities.find(name) ? _typeArities.get(name) : 0;
switch (tok.tag) {
case T_BOOL_TYPE:
case T_DEFAULT_TYPE: {
resetToks();
switch (tok.tag) {
case T_BOOL_TYPE:
_termLists.push(AtomicSort::boolSort());
break;
case T_DEFAULT_TYPE:
_termLists.push(AtomicSort::defaultSort());
break;
default:
ASSERTION_VIOLATION;
}
return;
}
case T_REAL_TYPE:
case T_RATIONAL_TYPE:
case T_STRING:
case T_INT:
case T_REAL:
case T_RAT: {
USER_ERROR("Vampire higher-order is currently not compatible with theory reasoning");
}
case T_AND:
case T_OR:
case T_IMPLY:
case T_IFF:
case T_XOR:{
ASS(arity == 0);
name = convert(tok.tag);
_termLists.push(createFunctionApplication(name, arity)); break;
}
case T_NAME:{
if(name.at(0) == '$'){
USER_ERROR("Vampire higher-order is currently not compatible with theory reasoning");
}
readTypeArgs(arity);
_termLists.push(createFunctionApplication(name, arity)); break;
}
case T_VAR:{
unsigned var = _vars.insert(name, _vars.size());
_termLists.push(TermList(var, false)); break;
}
default:
PARSE_ERROR_TOK("unexpected token", tok);
}
_lastPushed = TM;
}
std::string TPTP::convert(Tag t)
{
switch(t){
case T_AND:
return "vAND";
case T_OR:
return "vOR";
case T_IMPLY:
return "vIMP";
case T_IFF:
return "vIFF";
case T_XOR:
return "vXOR";
case T_NOT:
return "vNOT";
case T_PI:
return "vPI";
case T_SIGMA:
return "vSIGMA";
default:
ASSERTION_VIOLATION;
}
}
void TPTP::endHolFormula()
{
int con = _connectives.pop();
if (con == -2){
if(_termLists.size() == 1){
endTermAsFormula();
}
return;
}
if ((con < HOL_CONSTANTS_LOWER_BOUND) && (con != -1) && (_lastPushed == TM)){
endTermAsFormula();
}
Formula* f;
TermList fun;
bool conReverse = false;
switch (con) {
case IMP:
case AND:
case OR:
conReverse = _bools.pop();
break;
case IFF:
case XOR:
case APP:
case -2:
case -1:
break;
case NOT:
f = _formulas.pop();
_formulas.push(new NegatedFormula(f));
_lastPushed = FORM;
_states.push(END_HOL_FORMULA);
return;
case FORALL:
case EXISTS:
f = _formulas.pop();
_formulas.push(new QuantifiedFormula((Connective)con,_varLists.pop(),_sortLists.pop(),f));
_lastPushed = FORM;
_states.push(END_HOL_FORMULA);
_states.push(UNBIND_VARIABLES);
return;
case LAMBDA:{
if(_lastPushed == FORM){
endFormulaInsideTerm();
}
fun = _termLists.pop();
TermList ts(Term::createLambda(fun, _varLists.pop(), _sortLists.pop(), sortOf(fun)));
_termLists.push(ts);
_lastPushed = TM;
_states.push(END_HOL_FORMULA);
_states.push(UNBIND_VARIABLES);
return;
}
case LITERAL:
default:
throw ::Exception("tell me how to handle connective " + Int::toString(con));
}
Token& tok = getTok(0);
Tag tag = tok.tag;
int c;
bool cReverse = false;
switch (tag) {
case T_AND:
c = AND;
break;
case T_NOT_AND:
cReverse = true;
c = AND;
break;
case T_NOT_OR:
cReverse = true;
c = OR;
break;
case T_OR:
c = OR;
break;
case T_XOR:
c = XOR;
break;
case T_IFF:
c = IFF;
break;
case T_IMPLY:
c = IMP;
break;
case T_REVERSE_IMP:
cReverse = true;
c = IMP;
break;
case T_APP:
c = APP;
break;
case T_EQUAL:
case T_NEQ: {
_states.push(END_EQ);
_connectives.push(-1);
_states.push(END_HOL_FORMULA);
_states.push(HOL_FORMULA);
_states.push(MID_EQ);
if(_lastPushed == FORM){
endFormulaInsideTerm();
}
return;
}
default:
switch (con) {
case IMP:
f = _formulas.pop();
if (conReverse) {
f = new BinaryFormula((Connective)con,f,_formulas.pop());
}
else {
f = new BinaryFormula((Connective)con,_formulas.pop(),f);
}
_formulas.push(f);
_lastPushed = FORM;
_states.push(END_HOL_FORMULA);
return;
case APP:
_states.push(END_HOL_FORMULA);
_states.push(END_APP);
return;
case IFF:
case XOR:
f = _formulas.pop();
f = new BinaryFormula((Connective)con,_formulas.pop(),f);
_formulas.push(f);
_lastPushed = FORM;
_states.push(END_HOL_FORMULA);
return;
case AND:
case OR:
f = _formulas.pop();
f = makeJunction((Connective)con,_formulas.pop(),f);
if (conReverse) {
f = new NegatedFormula(f);
}
_formulas.push(f);
_lastPushed = FORM;
_states.push(END_HOL_FORMULA);
return;
case -1:
return;
default:
ASSERTION_VIOLATION;
}
}
if ((c != APP) && (con == -1) && (_lastPushed == TM)){
endTermAsFormula();
}
if (higherPrecedence(con,c)) {
if (con == APP){
_states.push(END_HOL_FORMULA);
_states.push(END_APP);
return;
}
f = _formulas.pop();
Formula* g = _formulas.pop();
if (con == AND || con == OR) {
f = makeJunction((Connective)con,g,f);
if (conReverse) {
f = new NegatedFormula(f);
}
}
else if (con == IMP && conReverse) {
f = new BinaryFormula((Connective)con,f,g);
}else {
f = new BinaryFormula((Connective)con,g,f);
}
_formulas.push(f);
_lastPushed = FORM;
_states.push(END_HOL_FORMULA);
return;
}
_connectives.push(con);
if (con == IMP || con == AND || con == OR) {
_bools.push(conReverse);
}
_connectives.push(c);
if (c == IMP || c == AND || c == OR) {
_bools.push(cReverse);
}
resetToks();
_states.push(END_HOL_FORMULA);
_states.push(HOL_FORMULA);
}
void TPTP::endApp()
{
if(_lastPushed == FORM){
endFormulaInsideTerm();
}
TermStack args;
TermList rhs = _termLists.pop();
TermList lhs = _termLists.pop();
TermList lhsSort = sortOf(lhs);
ASS_REP2(lhsSort.isTerm() && lhsSort.term()->arity() == 2, lhs.toString(), lhsSort.toString());
TermList s1 = *(lhsSort.term()->nthArgument(0));
TermList s2 = *(lhsSort.term()->nthArgument(1));
args.push(s1);
args.push(s2);
args.push(lhs);
args.push(rhs);
unsigned app = env.signature->getApp();
_termLists.push(TermList(Term::create(app, 4, args.begin())));
_lastPushed = TM;
}
void TPTP::endIte()
{
TermList elseBranch = _termLists.pop();
TermList thenBranch = _termLists.pop();
Formula* condition = _formulas.pop();
TermList thenSort = sortOf(thenBranch);
TermList ts(Term::createITE(condition,thenBranch,elseBranch,thenSort));
TermList elseSort = sortOf(elseBranch);
if (thenSort != elseSort) {
USER_ERROR("sort mismatch in the if-then-else expression: " +
thenBranch.toString() + " has the sort " + thenSort.toString() + ", whereas " +
elseBranch.toString() + " has the sort " + elseSort.toString());
}
_termLists.push(ts);
}
void TPTP::endTheoryFunction() {
Theory::Interpretation itp;
TermList args[3]; TermList arraySort;
TheoryFunction tf = _theoryFunctions.pop();
switch (tf) {
case TF_SELECT: {
TermList index = _termLists.pop();
TermList array = _termLists.pop();
arraySort = sortOf(array);
if (!arraySort.isArraySort()) {
USER_ERROR("$select is being incorrectly used on a type of array " + arraySort.toString() + " that has not be defined");
}
TermList indexSort = SortHelper::getIndexSort(arraySort);
if (sortOf(index) != indexSort) {
USER_ERROR("sort of index is not the same as the index sort of the array");
}
args[0] = array;
args[1] = index;
if (SortHelper::getInnerSort(arraySort) == AtomicSort::boolSort()) {
itp = Theory::Interpretation::ARRAY_BOOL_SELECT;
} else {
itp = Theory::Interpretation::ARRAY_SELECT;
}
break;
}
case TF_STORE: {
TermList value = _termLists.pop();
TermList index = _termLists.pop();
TermList array = _termLists.pop();
arraySort = sortOf(array);
if (!arraySort.isArraySort()) {
USER_ERROR("store is being incorrectly used on a type of array that has not be defined");
}
TermList indexSort = SortHelper::getIndexSort(arraySort);
if (sortOf(index) != indexSort) {
USER_ERROR("sort of index is not the same as the index sort of the array");
}
TermList innerSort = SortHelper::getInnerSort(arraySort);
if (sortOf(value) != innerSort) {
USER_ERROR("sort of value is not the same as the value sort of the array");
}
args[0] = array;
args[1] = index;
args[2] = value;
itp = Theory::Interpretation::ARRAY_STORE;
break;
}
default:
ASSERTION_VIOLATION_REP(tf);
}
OperatorType* type = Theory::getArrayOperatorType(arraySort,itp);
unsigned symbol = env.signature->getInterpretingSymbol(itp, type);
unsigned arity = Theory::getArity(itp);
if (Theory::isFunction(itp)) {
Term* term = Term::create(symbol, arity, args);
_termLists.push(TermList(term));
} else {
Literal* literal = Literal::create(symbol, arity, true, args);
_formulas.push(new AtomicFormula(literal));
_states.push(END_FORMULA_INSIDE_TERM);
}
}
namespace fs = std::filesystem;
fs::path TPTP::resolveInclude(const fs::path included)
{
if(included.is_absolute())
return included;
auto relativeToCurrentFileDirectory = currentFile.path.parent_path() / included;
if(fs::exists(relativeToCurrentFileDirectory))
return relativeToCurrentFileDirectory;
char *envTPTP = getenv("TPTP");
if(envTPTP) {
auto relativeToTPTP = envTPTP / included;
if(fs::exists(relativeToTPTP))
return relativeToTPTP;
}
auto include = env.options->include();
if(!include.empty()) {
auto relativeToInclude = include / included;
if(fs::exists(relativeToInclude))
return relativeToInclude;
}
return included;
}
void TPTP::include()
{
consumeToken(T_LPAR);
Token& tok = getTok(0);
if (tok.tag != T_NAME) {
PARSE_ERROR_TOK("file name expected",tok);
}
resetToks();
const std::string included = std::move(tok.content);
std::unordered_set<std::string> allowedNames;
tok = getTok(0);
if (tok.tag == T_COMMA) {
resetToks();
consumeToken(T_LBRA);
for(;;) {
tok = getTok(0);
if (tok.tag != T_NAME) {
PARSE_ERROR_TOK("formula name expected",tok);
}
resetToks();
allowedNames.insert(std::move(tok.content));
tok = getTok(0);
if (tok.tag == T_RBRA) {
resetToks();
break;
}
consumeToken(T_COMMA);
}
}
consumeToken(T_RPAR);
consumeToken(T_DOT);
std::filesystem::path path = fs::absolute(resolveInclude(included));
auto in = new ifstream(path);
if (!*in) {
delete in;
USER_ERROR("cannot open file " + std::string(path));
}
restoreFiles.emplace_back(std::move(currentFile));
currentFile.in = in;
currentFile.allowedNames = std::move(allowedNames);
currentFile.path = std::move(path);
currentFile.lineNumber = 1;
}
std::string TPTP::name()
{
Token& tok = getTok(0);
if (tok.tag != T_NAME) {
PARSE_ERROR_TOK("name expected",tok);
}
std::string nm = tok.content;
resetToks();
return nm;
}
void TPTP::consumeToken(Tag t)
{
Token& tok = getTok(0);
if (tok.tag != t) {
std::string expected = toString(t);
PARSE_ERROR_TOK(expected + " expected",tok);
}
resetToks();
}
void TPTP::formula()
{
if(_isThf){
_connectives.push(-2); _connectives.push(-1);
_states.push(END_HOL_FORMULA);
_states.push(END_HOL_FORMULA);
_states.push(HOL_FORMULA);
}else{
_connectives.push(-1);
_states.push(END_FORMULA);
_states.push(SIMPLE_FORMULA);
}
}
void TPTP::termInfix()
{
Token tok = getTok(0);
switch (tok.tag) {
case T_EQUAL:
case T_NEQ:
_states.push(END_FORMULA_INSIDE_TERM);
_states.push(FORMULA_INFIX);
return;
case T_COMMA:
case T_RPAR:
case T_RBRA:
case T_ASS:
_states.push(END_TERM);
return;
case T_AND:
case T_NOT_AND:
case T_NOT_OR:
case T_OR:
case T_XOR:
case T_IFF:
case T_IMPLY:
case T_REVERSE_IMP:
if (_insideEqualityArgument > 0) {
_states.push(END_TERM);
return;
}
_connectives.push(-1);
_states.push(END_FORMULA_INSIDE_TERM);
_states.push(END_FORMULA);
_states.push(FORMULA_INFIX);
return;
default:
PARSE_ERROR_TOK("term or formula expected", tok);
}
}
void TPTP::type()
{
_typeTags.push(TT_ATOMIC);
_states.push(END_TYPE);
_states.push(SIMPLE_TYPE);
}
void TPTP::funApp()
{
Token tok = getTok(0);
resetToks();
if (tok.tag == T_LBRA) {
_strings.push(toString(T_TUPLE));
} else {
_strings.push(tok.content);
}
switch (tok.tag) {
case T_THEORY_FUNCTION:
consumeToken(T_LPAR);
addTagState(T_RPAR);
switch (getTheoryFunction(tok)) {
case TF_SELECT:
_states.push(TERM);
addTagState(T_COMMA);
_states.push(TERM);
break;
case TF_STORE:
_states.push(TERM);
addTagState(T_COMMA);
_states.push(TERM);
addTagState(T_COMMA);
_states.push(TERM);
break;
default:
ASSERTION_VIOLATION_REP(tok.content);
}
return;
case T_ITE:
consumeToken(T_LPAR);
addTagState(T_RPAR);
_states.push(TERM);
addTagState(T_COMMA);
_states.push(TERM);
addTagState(T_COMMA);
_states.push(FORMULA);
return;
case T_LET: {
consumeToken(T_LPAR);
addTagState(T_RPAR);
_states.push(TERM);
addTagState(T_COMMA);
_states.push(DEFINITION);
_letDefinitions.push(LetDefinitions());
addTagState(T_COMMA);
bool multipleLetTypes = false;
if (getTok(0).tag == T_LBRA) {
resetToks();
addTagState(T_RBRA);
multipleLetTypes = true;
}
_bools.push(multipleLetTypes);
_states.push(END_LET_TYPES);
_states.push(LET_TYPE);
_letTypedSymbols.push(LetSymbols());
return;
}
case T_LBRA:
_states.push(ARGS);
_ints.push(1); return;
case T_VAR:
_ints.push(-1); return;
case T_NAME:
if (getTok(0).tag == T_LPAR) {
resetToks();
_states.push(ARGS);
_ints.push(1); } else {
_ints.push(0); }
return;
default:
PARSE_ERROR_TOK("unexpected token", tok);
}
}
void TPTP::letType()
{
_states.push(TYPE);
addTagState(T_COLON);
_strings.push(name());
}
void TPTP::endLetTypes()
{
std::string name = _strings.pop();
Type* t = _types.pop();
DHSet<unsigned> iTypeVars;
OperatorType* type = constructOperatorType(t, nullptr, &iTypeVars);
unsigned arity = type->arity();
bool isPredicate = type->isPredicateType();
unsigned functor = isPredicate
? env.signature->addFreshPredicate(arity, name.c_str())
: env.signature->addFreshFunction(arity, name.c_str());
Signature::Symbol *symbol = isPredicate
? env.signature->getPredicate(functor)
: env.signature->getFunction(functor);
symbol->setType(type);
auto ivars = TermStack::fromIterator(iterTraits(iTypeVars.iterator())
.map(unsignedToVarFn));
LetSymbolName symbolName(name, arity-ivars.size());
LetSymbolReference symbolReference { functor, isPredicate, std::move(ivars) };
LetSymbols scope = _letTypedSymbols.pop();
if (findLetSymbol(symbolName, scope, symbolReference)) {
USER_ERROR("The symbol " + name + " of arity " + Int::toString(arity) + " is defined twice in a $let-expression.");
}
scope.push(LetSymbol(symbolName, symbolReference));
_letTypedSymbols.push(scope);
bool multipleLetTypes = _bools.pop();
if (multipleLetTypes && getTok(0).tag == T_COMMA) {
resetToks();
_bools.push(multipleLetTypes);
_states.push(END_LET_TYPES);
_states.push(LET_TYPE);
}
}
void TPTP::definition()
{
switch (getTok(0).tag) {
case T_NAME:
_bools.push(false); _strings.push(name());
_states.push(SYMBOL_DEFINITION);
return;
case T_LBRA: {
resetToks();
switch (getTok(0).tag) {
case T_NAME:
_strings.push(name());
switch (getTok(0).tag) {
case T_ASS:
case T_LPAR:
_bools.push(true); addTagState(T_RBRA);
_states.push(SYMBOL_DEFINITION);
return;
case T_COMMA:
resetToks();
_bools.push(false); _states.push(TUPLE_DEFINITION);
return;
default:
PARSE_ERROR_TOK(toString(T_ASS) + " or " + toString(T_LPAR) + " or " + toString(T_COMMA) + " expected",
getTok(0));
}
return;
case T_LBRA:
resetToks();
_bools.push(true); addTagState(T_RBRA);
_states.push(TUPLE_DEFINITION);
return;
default:
PARSE_ERROR_TOK("name or " + toString(T_LBRA) + " expected",getTok(0));
}
}
default:
PARSE_ERROR_TOK("name or " + toString(T_LBRA) + " expected",getTok(0));
}
}
void TPTP::midDefinition()
{
switch (getTok(0).tag) {
case T_NAME:
_strings.push(name());
_states.push(SYMBOL_DEFINITION);
break;
case T_LBRA:
resetToks();
_states.push(TUPLE_DEFINITION);
break;
default:
PARSE_ERROR_TOK("name or " + toString(T_LBRA) + " expected",getTok(0));
}
}
void TPTP::symbolDefinition()
{
std::string nm = _strings.pop();
unsigned arity = 0;
VList* vs = VList::empty();
Stack<unsigned> vars;
if (getTok(0).tag == T_LPAR) {
resetToks();
for (;;) {
if (getTok(0).tag == T_VAR) {
unsigned var = _vars.insert(getTok(0).content, _vars.size());
vars.push(var);
resetToks();
} else {
PARSE_ERROR_TOK("variable expected", getTok(0));
}
if (getTok(0).tag == T_COMMA) {
resetToks();
continue;
}
if (getTok(0).tag == T_RPAR) {
resetToks();
break;
}
PARSE_ERROR_TOK("comma or closing bracket expected", getTok(0));
}
arity = (unsigned)vars.size();
}
LetSymbolName name(nm, arity);
LetSymbolReference ref;
if (!findLetSymbol(name, _letTypedSymbols.top(), ref)) {
USER_ERROR("Symbol " + nm + " with arity " + Int::toString(arity) + " is used in a let definition without a declared type");
}
auto symbol = SYMBOL(ref);
auto isPredicate = IS_PREDICATE(ref);
if (arity > 0) {
OperatorType* type = isPredicate
? env.signature->getPredicate(symbol)->predType()
: env.signature->getFunction(symbol)->fnType();
auto subst = getTypeSub(ref);
auto index = ref.iTypeArgs.size();
iterTraits(vars.iterFifo())
.forEach([&](unsigned var) {
bindVariable(var, SubstHelper::apply(type->arg(index++), subst));
VList::push(var, vs);
});
_bindLists.push(vs);
_states.push(UNBIND_VARIABLES);
}
_letDefinitions.top().push(std::move(ref));
_varLists.push(vs);
_states.push(END_DEFINITION);
consumeToken(T_ASS);
_states.push(TERM);
}
void TPTP::tupleDefinition()
{
Set<std::string> uniqueConstants;
Stack<unsigned> symbols;
TermStack sorts;
std::string constant = _strings.pop();
do {
if (uniqueConstants.contains(constant)) {
USER_ERROR("The symbol " + constant + " is defined twice in a tuple $let-expression.");
} else {
uniqueConstants.insert(constant);
}
LetSymbolName constantName(constant, 0);
LetSymbolReference ref;
if (!findLetSymbol(constantName, _letTypedSymbols.top(), ref)) {
USER_ERROR("Constant " + constant + " is used in a tuple let definition without a declared sort");
}
auto symbol = SYMBOL(ref);
auto isPredicate = IS_PREDICATE(ref);
symbols.push(symbol);
TermList sort = isPredicate
? AtomicSort::boolSort()
: env.signature->getFunction(symbol)->fnType()->result();
auto subst = getTypeSub(ref);
sorts.push(SubstHelper::apply(sort, subst));
if (getTok(0).tag == T_NAME) {
constant = name();
if (getTok(0).tag == T_COMMA) {
resetToks();
}
} else {
break;
}
} while (true);
auto tupleFunctor = Theory::tuples()->getConstructor(sorts.size());
LetDefinitions definitions = _letDefinitions.pop();
definitions.push(LetSymbolReference{ tupleFunctor, false, std::move(sorts) });
_letDefinitions.push(definitions);
VList* constants = VList::empty();
VList::pushFromIterator(Stack<unsigned>::Iterator(symbols), constants);
_varLists.push(constants);
_states.push(END_DEFINITION);
_states.push(TERM);
addTagState(T_ASS);
addTagState(T_RBRA);
}
void TPTP::endDefinition()
{
auto ref = _letDefinitions.top().top();
auto symbol = SYMBOL(ref);
auto isPredicate = IS_PREDICATE(ref);
TermList definition = _termLists.top();
TermList definitionSort = sortOf(definition);
TermList refSort = isPredicate
? AtomicSort::boolSort()
: env.signature->getFunction(symbol)->fnType()->result();
auto subst = getTypeSub(ref);
auto refSortS = SubstHelper::apply(refSort, subst);
if (refSortS != definitionSort) {
auto refSymbolName = isPredicate
? env.signature->predicateName(symbol)
: env.signature->functionName(symbol);
USER_ERROR("The term " + definition.toString() + " of the sort " + definitionSort.toString() +
" is used as definition of the symbol " + refSymbolName +
" of the sort " + refSortS.toString());
}
bool multipleDefinitions = _bools.pop();
if (multipleDefinitions && getTok(0).tag == T_COMMA) {
resetToks();
_bools.push(multipleDefinitions);
_states.push(MID_DEFINITION);
} else {
_letSymbols.push(_letTypedSymbols.pop());
}
}
Substitution TPTP::getTypeSub(const TPTP::LetSymbolReference& ref)
{
Substitution subst;
iterTraits(ref.iTypeArgs.iterFifo())
.enumerate([&](unsigned i, TermList arg) { subst.bind(i, arg); });
return subst;
}
bool TPTP::findLetSymbol(LetSymbolName symbolName, LetSymbolReference& symbolReference) {
Stack<LetSymbols>::TopFirstIterator scopes(_letSymbols);
while (scopes.hasNext()) {
LetSymbols scope = scopes.next();
if (findLetSymbol(symbolName, scope, symbolReference)) {
return true;
}
}
return false;
}
bool TPTP::findLetSymbol(LetSymbolName symbolName, LetSymbols scope, LetSymbolReference& symbolReference) {
for (const auto& [name,ref] : scope) {
if (name == symbolName) {
symbolReference = ref;
return true;
}
}
return false;
}
void TPTP::endLet()
{
TermList let = _termLists.pop();
TermList sort = sortOf(let);
_letSymbols.pop();
LetDefinitions scope = _letDefinitions.pop(); LetDefinitions::TopFirstIterator definitions(scope);
while (definitions.hasNext()) {
auto ref = definitions.next();
auto symbol = SYMBOL(ref);
auto isPredicate = IS_PREDICATE(ref);
VList* varList = _varLists.pop();
TermList body = _termLists.pop();
bool isTuple = false;
if (!isPredicate) {
TermList resultSort = env.signature->getFunction(symbol)->fnType()->result();
isTuple = resultSort.isTupleSort();
}
TermStack args = ref.iTypeArgs;
auto vars = VList::empty();
if (isTuple) {
iterTraits(varList->iter()).enumerate([&](unsigned i, unsigned fn) {
if (ref.iTypeArgs[i].isBoolSort()) {
args.emplace(Term::createFormula(new AtomicFormula(Literal::create(fn, true, {}))));
} else {
auto argType = env.signature->getFunction(fn)->fnType();
ASS_EQ(argType->arity()-argType->numTypeArguments(),0);
Substitution subst;
MatchingUtils::matchTerms(argType->result(), ref.iTypeArgs[i], subst);
auto argArgs = TermStack::fromIterator(range(0,argType->numTypeArguments())
.map([&](unsigned i) {
#if VDEBUG
TermList unused;
ASS(subst.findBinding(i, unused));
#endif
return subst.apply(i);
}));
args.emplace(Term::create(fn, argArgs));
}
});
} else {
if (varList) {
args.loadFromIterator(iterTraits(varList->iter()).map(unsignedToVarFn));
}
vars = varList;
}
auto binding = Formula::createDefinition(Term::create(symbol, args), body, vars);
let = TermList(Term::createLet(binding, let, sort));
}
_termLists.push(let);
}
void TPTP::endTuple()
{
unsigned arity = (unsigned)_ints.pop();
ASS_GE(_termLists.size(), arity);
DArray<TermList> args(2*arity);
for (int i = arity - 1; i >= 0; i--) {
TermList ts = _termLists.pop();
args[arity+i] = ts;
args[i] = sortOf(ts);
}
auto t = Term::create(Theory::tuples()->getConstructor(arity), 2*arity, args.begin());
_termLists.push(TermList(t));
}
void TPTP::args()
{
_states.push(END_ARGS);
_states.push(TERM);
}
void TPTP::endArgs()
{
Token tok = getTok(0);
switch (tok.tag) {
case T_COMMA:
resetToks();
_ints.push(_ints.pop()+1);
_states.push(END_ARGS);
_states.push(TERM);
return;
case T_RPAR:
resetToks();
return;
case T_RBRA:
resetToks();
return;
default:
PARSE_ERROR_TOK(", ) or ] expected after an end of a term",tok);
}
}
void TPTP::bindVariable(unsigned var,TermList sort)
{
SList** definitions;
_variableSorts.getValuePtr(var,definitions,SList::empty());
SList::push(sort,*definitions); }
void TPTP::varList()
{
Stack<int> vars;
for (;;) {
Token& tok = getTok(0);
if (tok.tag != T_VAR) {
PARSE_ERROR_TOK("variable expected",tok);
}
unsigned var = _vars.insert(tok.content, _vars.size());
if (_isQuestion) {
_curQuestionVarNames.insert(var,tok.content);
}
vars.push(var);
resetToks();
bool sortDeclared = false;
afterVar:
tok = getTok(0);
switch (tok.tag) {
case T_COLON: if (sortDeclared) {
PARSE_ERROR_TOK("two declarations of variable sort",tok);
}
resetToks();
bindVariable(var,(_isThf ? readArrowSort() : readSort()));
sortDeclared = true;
goto afterVar;
case T_COMMA:
if (!sortDeclared) {
bindVariable(var,AtomicSort::defaultSort());
}
resetToks();
break;
default:
{
if (!sortDeclared) {
bindVariable(var,AtomicSort::defaultSort());
}
VList* vs = VList::empty();
SList* ss = SList::empty();
while (!vars.isEmpty()) {
int v = vars.pop();
VList::push(v,vs);
SList::push(sortOf(TermList(v,false)),ss);
}
_varLists.push(vs);
_sortLists.push(ss);
_bindLists.push(vs);
return;
}
}
}
}
void TPTP::term()
{
Token tok = getTok(0);
switch (tok.tag) {
case T_NAME:
case T_THEORY_FUNCTION:
case T_VAR:
case T_ITE:
case T_LET:
case T_LBRA:
_states.push(TERM_INFIX);
_states.push(FUN_APP);
return;
case T_INTEGER_TYPE:
case T_REAL_TYPE:
case T_RATIONAL_TYPE:
case T_BOOL_TYPE:
case T_DEFAULT_TYPE: {
resetToks();
switch (tok.tag) {
case T_INTEGER_TYPE:
_termLists.push(AtomicSort::intSort());
break;
case T_REAL_TYPE:
_termLists.push(AtomicSort::realSort());
break;
case T_RATIONAL_TYPE:
_termLists.push(AtomicSort::rationalSort());
break;
case T_BOOL_TYPE:
_termLists.push(AtomicSort::boolSort());
break;
case T_DEFAULT_TYPE:
_termLists.push(AtomicSort::defaultSort());
break;
default:
ASSERTION_VIOLATION;
}
return;
}
case T_STRING:
case T_INT:
case T_REAL:
case T_RAT: {
resetToks();
unsigned number;
switch (tok.tag) {
case T_STRING:
number = env.signature->addStringConstant(tok.content);
env.signature->getFunction(number)->setType(
OperatorType::getConstantsType(AtomicSort::defaultSort())
);
break;
case T_INT:
number = addNumeralConstant<IntegerConstantType>(tok.content);
break;
case T_REAL:
number = addNumeralConstant<RealConstantType>(tok.content);
break;
case T_RAT:
number = addNumeralConstant<RationalConstantType>(tok.content);
break;
default:
ASSERTION_VIOLATION;
}
_termLists.push(TermList(Term::createConstant(number)));
return;
}
default:
_states.push(FORMULA_INSIDE_TERM);
}
}
void TPTP::endTerm()
{
std::string name = _strings.pop();
if (name == toString(T_ITE)) {
_states.push(END_ITE);
return;
}
if (name == toString(T_LET)) {
_states.push(END_LET);
return;
}
if (name == toString(T_TUPLE)) {
_states.push(END_TUPLE);
return;
}
TheoryFunction tf;
if (findTheoryFunction(name, tf)) {
_theoryFunctions.push(tf);
_states.push(END_THEORY_FUNCTION);
return;
}
int arity = _ints.pop();
if (arity == -1) {
unsigned var = _vars.insert(name, _vars.size());
_termLists.push(TermList(var, false));
return;
}
LetSymbolReference ref;
if (env.signature->predicateExists(name, arity) ||
(findLetSymbol(LetSymbolName(name, arity), ref) && IS_PREDICATE(ref)) ||
findInterpretedPredicate(name, arity)) {
_formulas.push(createPredicateApplication(name, arity));
_states.push(END_FORMULA_INSIDE_TERM);
return;
}
if(env.signature->typeConExists(name, arity)){
_termLists.push(createTypeConApplication(name, arity));
return;
}
_termLists.push(createFunctionApplication(name, arity));
}
void TPTP::formulaInfix()
{
Token tok = getTok(0);
if (tok.tag == T_EQUAL || tok.tag == T_NEQ) {
_states.push(END_EQ);
_states.push(TERM);
_states.push(MID_EQ);
_states.push(END_TERM);
return;
}
std::string name = _strings.pop();
if (name == toString(T_ITE)) {
_states.push(END_TERM_AS_FORMULA);
_states.push(END_ITE);
return;
}
TheoryFunction tf;
if (findTheoryFunction(name, tf)) {
switch (tf) {
case TF_STORE:
USER_ERROR("$store expression cannot be used as formula");
break;
case TF_SELECT:
_theoryFunctions.push(tf);
_states.push(END_TERM_AS_FORMULA);
_states.push(END_THEORY_FUNCTION);
break;
default:
ASSERTION_VIOLATION_REP(name);
}
return;
}
if (name == toString(T_LET)) {
_states.push(END_TERM_AS_FORMULA);
_states.push(END_LET);
return;
}
int arity = _ints.pop();
if (arity == -1) {
unsigned var = _vars.insert(name, _vars.size());
_termLists.push(TermList(var, false));
_states.push(END_TERM_AS_FORMULA);
return;
}
if(env.signature->functionExists(name, arity)){
_termLists.push(createFunctionApplication(name, arity));
_states.push(END_TERM_AS_FORMULA);
return;
}
_formulas.push(createPredicateApplication(name, arity));
}
void TPTP::endEquality()
{
_insideEqualityArgument--;
if((_isThf) && (_lastPushed == FORM)){
endFormulaInsideTerm();
}
TermList rhs = _termLists.pop();
TermList lhs = _termLists.pop();
if (sortOf(rhs) != sortOf(lhs)) {
TermList rsort = sortOf(rhs);
TermList lsort = sortOf(lhs);
USER_ERROR("Cannot create equality between terms of different types.\n"+
rhs.toString()+" is "+rsort.toString()+"\n"+
lhs.toString()+" is "+lsort.toString()
);
}
Literal* l = createEquality(_bools.pop(),lhs,rhs);
_formulas.push(new AtomicFormula(l, lhs != l->termArg(0)));
_lastPushed = FORM;
}
void TPTP::midEquality()
{
_insideEqualityArgument++;
Token tok = getTok(0);
switch (tok.tag) {
case T_EQUAL:
_bools.push(true);
break;
case T_NEQ:
_bools.push(false);
break;
default:
PARSE_ERROR_TOK("either = or != expected",tok);
}
resetToks();
}
Literal* TPTP::createEquality(bool polarity,TermList& lhs,TermList& rhs)
{
TermList masterVar;
TermList sort;
if (!SortHelper::getResultSortOrMasterVariable(lhs, sort, masterVar)) {
SList* vs;
if (_variableSorts.find(masterVar.var(),vs) && vs) {
sort = vs->head();
}
else { sort = AtomicSort::defaultSort();
}
}
return Literal::createEquality(polarity,lhs,rhs,sort);
}
Formula* TPTP::createPredicateApplication(std::string name, unsigned arity)
{
ASS_GE(_termLists.size(), arity);
int pred;
LetSymbolReference ref;
if (findLetSymbol(LetSymbolName(name, arity), ref) && IS_PREDICATE(ref)) {
pred = (int)SYMBOL(ref);
insertImplicitLetTypeArguments(ref, arity);
} else {
if (arity > 0) {
bool dummy;
pred = addPredicate(name, arity, dummy, _termLists.top());
} else {
pred = env.signature->addPredicate(name, 0);
}
}
if (pred == -1) { TermList rhs = _termLists.pop();
TermList lhs = _termLists.pop();
Literal *l = createEquality(true,lhs,rhs); return new AtomicFormula(l, lhs != l->termArg(0));
}
if (pred == -2){ if(arity<5){
static Stack<unsigned> distincts;
distincts.reset();
for(int i=arity-1;i >= 0; i--){
TermList t = _termLists.pop();
if(t.isVar() || t.term()->arity()!=0){
USER_ERROR("$distinct can only be used with constants. Found "+t.toString());
}
distincts.push(t.term()->functor());
}
Formula* distinct_formula = DistinctGroupExpansion(0 ).expand(distincts);
return distinct_formula;
}else{
unsigned grpIdx = env.signature->createDistinctGroup(0);
for(int i = arity-1;i >=0; i--){
TermList ts = _termLists.pop();
if(!ts.isTerm() || ts.term()->arity()!=0){
USER_ERROR("$distinct can only be used with constants. Found "+ts.toString());
}
env.signature->addToDistinctGroup(ts.term()->functor(),grpIdx);
}
return new Formula(true); }
}
auto args = nLastTermLists(arity);
OperatorType* type = env.signature->getPredicate(pred)->predType();
for (auto i : range(0, arity)) {
TermList sort = type->arg(i);
TermList ts = args[i];
TermList tsSort = sortOf(ts);
if(i < type->numTypeArguments()){
if(tsSort != AtomicSort::superSort()){
USER_ERROR("The sort ", tsSort, " of type argument ", ts, " is not $ttype as mandated by TF1");
}
} else {
_substScratchpad.reset();
if(!_substScratchpad.match(sort, 0, tsSort, 1)) {
USER_ERROR("Failed to create predicate application for ", name, " of type ", type->toString(), "\n",
"The sort ", tsSort, " of the intended term argument ", ts, " (at index ", i, ") "
"is not an instance of sort ", sort);
}
}
}
auto out = new AtomicFormula(Literal::create(pred, arity, true, args));
_termLists.pop(arity);
return out;
}
TermList TPTP::createFunctionApplication(std::string name, unsigned arity)
{ ASS_GE(_termLists.size(), arity);
unsigned fun;
LetSymbolReference ref;
if (findLetSymbol(LetSymbolName(name, arity), ref) && !IS_PREDICATE(ref)) {
fun = SYMBOL(ref);
insertImplicitLetTypeArguments(ref, arity);
} else {
bool dummy;
if (arity > 0) {
fun = addFunction(name, arity, dummy, _termLists.top());
} else {
fun = addUninterpretedConstant(name, dummy);
}
}
OperatorType* type = env.signature->getFunction(fun)->fnType();
auto args = nLastTermLists(arity);
for (unsigned i : range(0, arity)) {
TermList sort = type->arg(i);
TermList ss = args[i];
TermList ssSort = sortOf(ss);
if(i < type->numTypeArguments()){
if(ssSort != AtomicSort::superSort()){
USER_ERROR("The sort " + ssSort.toString() + " of type argument " + ss.toString() + " "
"is not $tType as mandated by TF1");
}
} else {
_substScratchpad.reset();
if(!_substScratchpad.match(sort, 0, ssSort, 1)){
USER_ERROR("Failed to create function application for " + name + " of type " + type->toString() + "\n" +
"The sort " + ssSort.toString() + " of the intended term argument " + ss.toString() + " (at index " + Int::toString(i) +") "
"is not an instance of sort " + sort.toString());
}
}
}
auto t = TermList(Term::create(fun, arity, args));
_termLists.pop(arity);
return t;
}
TermList TPTP::createTypeConApplication(std::string name, unsigned arity)
{
ASS_GE(_termLists.size(), arity);
bool added = false;
unsigned typeCon = env.signature->addTypeCon(name,arity,added);
if(added)
USER_ERROR("Undeclared type constructor ", name, "/", arity);
auto args = nLastTermLists(arity);
for (auto i : range(0, arity)) {
auto term = args[i];
auto sort = sortOf(term);
if (sort != AtomicSort::superSort())
USER_ERROR("The sort ", sort, " of type argument ", term, " is not $tType as mandated by TF1");
}
auto s = TermList(AtomicSort::create(typeCon, arity, args));
_termLists.pop(arity);
return s;
}
void TPTP::insertImplicitLetTypeArguments(const LetSymbolReference& ref, unsigned& arity)
{
auto numITypeArgs = ref.iTypeArgs.size();
range(0, numITypeArgs)
.forEach([&](unsigned i) { _termLists.push(TermList()); });
arity += numITypeArgs;
if (numITypeArgs) {
auto args = nLastTermLists(arity);
for (unsigned i : range(numITypeArgs,arity)) {
unsigned ri = arity - 1 - i;
args[ri + numITypeArgs] = args[ri];
}
range(0, numITypeArgs)
.forEach([&](unsigned i) { args[i] = ref.iTypeArgs[i]; });
}
}
void TPTP::endFormula()
{
int con = _connectives.pop();
Formula* f;
bool conReverse = false;
switch (con) {
case IMP:
case AND:
case OR:
conReverse = _bools.pop();
break;
case IFF:
case XOR:
case -1:
break;
case NOT:
f = _formulas.pop();
if(f->connective()==LITERAL){
auto af = static_cast<AtomicFormula*>(f);
Literal* oldLit = af->literal();
Literal* newLit = Literal::create(oldLit,!oldLit->polarity());
_formulas.push(new AtomicFormula(newLit, af->flipForPrinting));
}
else{
_formulas.push(new NegatedFormula(f));
}
_states.push(END_FORMULA);
return;
case FORALL:
case EXISTS:
f = _formulas.pop();
_formulas.push(new QuantifiedFormula((Connective)con,_varLists.pop(),_sortLists.pop(),f));
_states.push(END_FORMULA);
return;
case LITERAL:
default:
throw ::Exception("tell me how to handle connective " + Int::toString(con));
}
Token& tok = getTok(0);
Tag tag = tok.tag;
Connective c;
bool cReverse = false;
switch (tag) {
case T_AND:
c = AND;
break;
case T_NOT_AND:
cReverse = true;
c = AND;
break;
case T_NOT_OR:
cReverse = true;
c = OR;
break;
case T_OR:
c = OR;
break;
case T_XOR:
c = XOR;
break;
case T_IFF:
c = IFF;
break;
case T_IMPLY:
c = IMP;
break;
case T_REVERSE_IMP:
cReverse = true;
c = IMP;
break;
case T_EQUAL:
case T_NEQ: {
_states.push(END_EQ);
_states.push(TERM);
_states.push(MID_EQ);
_states.push(END_FORMULA_INSIDE_TERM);
return;
}
default:
switch (con) {
case IMP:
f = _formulas.pop();
if (conReverse) {
f = new BinaryFormula((Connective)con,f,_formulas.pop());
}
else {
f = new BinaryFormula((Connective)con,_formulas.pop(),f);
}
_formulas.push(f);
_states.push(END_FORMULA);
return;
case IFF:
case XOR:
f = _formulas.pop();
f = new BinaryFormula((Connective)con,_formulas.pop(),f);
_formulas.push(f);
_states.push(END_FORMULA);
return;
case AND:
case OR:
f = _formulas.pop();
f = makeJunction((Connective)con,f,_formulas.pop());
if (conReverse) {
f = new NegatedFormula(f);
}
_formulas.push(f);
_states.push(END_FORMULA);
return;
case -1:
return;
default:
ASSERTION_VIOLATION;
}
}
if (higherPrecedence(con,c)) {
f = _formulas.pop();
Formula* g = _formulas.pop();
if (con == AND || con == OR) {
f = makeJunction((Connective)con,g,f);
if (conReverse) {
f = new NegatedFormula(f);
}
}
else if (con == IMP && conReverse) {
f = new BinaryFormula((Connective)con,f,g);
}
else {
f = new BinaryFormula((Connective)con,g,f);
}
_formulas.push(f);
_states.push(END_FORMULA);
return;
}
_connectives.push(con);
if (con == IMP || con == AND || con == OR) {
_bools.push(conReverse);
}
_connectives.push(c);
if (c == IMP || c == AND || c == OR) {
_bools.push(cReverse);
}
resetToks();
_states.push(END_FORMULA);
_states.push(SIMPLE_FORMULA);
}
void TPTP::formulaInsideTerm()
{
_states.push(END_FORMULA_INSIDE_TERM);
_states.push(FORMULA);
}
void TPTP::endFormulaInsideTerm()
{
Formula* f = _formulas.pop();
TermList ts(Term::createFormula(f));
_termLists.push(ts);
_lastPushed = TM;
}
void TPTP::endTermAsFormula()
{
TermList t = _termLists.pop();
TermList tSort = sortOf(t);
if (tSort != AtomicSort::boolSort()) {
USER_ERROR("Non-boolean term " + t.toString() + " of sort " + tSort.toString() + " is used in a formula context");
}
if (t.isTerm() && t.term()->isFormula()) {
_formulas.push(t.term()->getSpecialData()->getFormula());
_lastPushed = FORM;
} else {
_formulas.push(new BoolTermFormula(t));
_lastPushed = FORM;
}
}
void TPTP::endType()
{
TypeTag tt = _typeTags.pop();
Type* t = _types.pop();
switch (tt) {
case TT_ATOMIC:
break;
case TT_PRODUCT:
t = new ProductType(_types.pop(),t);
tt = _typeTags.pop();
break;
case TT_ARROW:
t = new ArrowType(_types.pop(),t);
tt = _typeTags.pop();
break;
case TT_QUANTIFIED:
VList* vl = _varLists.pop();
_sortLists.pop();
t = new QuantifiedType(t, vl);
tt = _typeTags.pop();
break;
}
ASS(tt == TT_ATOMIC);
_types.push(t);
Token tok = getTok(0);
switch (tok.tag) {
case T_STAR:
_typeTags.push(tt);
_typeTags.push(TT_PRODUCT);
break;
case T_ARROW:
_typeTags.push(tt);
_typeTags.push(TT_ARROW);
break;
default:
return;
}
resetToks();
_states.push(END_TYPE);
_states.push(SIMPLE_TYPE);
}
void TPTP::tag()
{
consumeToken(_tags.pop());
}
void TPTP::endFof()
{
TPTP::SourceRecord* source = 0;
if (_unitSources) {
source = getSource();
}
#if DEBUG_SOURCE
else{
_unitSources = new DHMap<Unit*,SourceRecord*>();
source = getSource();
}
#endif
skipToRPAR();
consumeToken(T_DOT);
_vars.reset();
bool isFof = _bools.pop();
Formula* f = _formulas.pop();
std::string nm = _strings.pop(); if (!currentFile.allowedNames.empty() && !currentFile.allowedNames.count(nm)) {
return;
}
Unit *unit, *original;
if (isFof) { if (freeVariables(f)) {
USER_ERROR("unquantified variable detected for a formula named '",nm,"'");
}
original = unit = new FormulaUnit(f,FromInput(_lastInputType));
unit->setInheritedColor(_currentColor);
}
else { Stack<Formula*> forms;
Stack<Literal*> lits;
Formula* g = nullptr;
forms.push(f);
bool needsFlipDocumenting = false;
while (! forms.isEmpty()) {
g = forms.pop();
switch (g->connective()) {
case OR:
{
FormulaList::Iterator fs(static_cast<JunctionFormula*>(g)->getArgs());
while (fs.hasNext()) {
forms.push(fs.next());
}
}
break;
case LITERAL:
case NOT:
{
bool positive = true;
while (g->connective() == NOT) {
g = static_cast<NegatedFormula*>(g)->subformula();
positive = !positive;
}
if (g->connective() != LITERAL) {
USER_ERROR("input formula not in CNF: " + f->toString());
}
auto af = static_cast<AtomicFormula*>(g);
needsFlipDocumenting = needsFlipDocumenting || af->flipForPrinting;
Literal* l = af->literal();
lits.push(positive ? l : Literal::complementaryLiteral(l));
}
break;
case TRUE:
return;
case FALSE:
break;
default:
USER_ERROR("input formula not in CNF: " + f->toString());
}
}
if(needsFlipDocumenting) {
FormulaUnit *fu = new FormulaUnit(f, FromInput(_lastInputType));
original = fu;
FormulaClauseTransformation transform(InferenceRule::REORIENT_EQUATIONS, fu);
unit = Clause::fromStack(lits, transform);
}
else
original = unit = Clause::fromStack(lits, FromInput(_lastInputType));
unit->setInheritedColor(_currentColor);
}
if(source) {
ASS(_unitSources);
_unitSources->insert(original,source);
}
if (env.options->outputAxiomNames()) {
assignAxiomName(original,nm);
}
#if DEBUG_SHOW_UNITS
cout << "Unit: " << unit->toString() << "\n";
#endif
if (!restoreFiles.empty()) {
unit->inference().markIncluded();
}
switch (_lastInputType) {
case UnitInputType::CONJECTURE:
if(!isFof) USER_ERROR("conjecture is not allowed in cnf");
if(_seenConjecture) USER_ERROR("Vampire only supports a single conjecture in a problem");
_seenConjecture=true;
{
ASS_EQ(freeVariables(f),VList::empty())
f = new NegatedFormula(f);
unit = new FormulaUnit(f,
FormulaClauseTransformation(InferenceRule::NEGATED_CONJECTURE,unit));
if (_isQuestion) {
_questionVariableNames.insert(unit->number(),std::move(_curQuestionVarNames));
}
}
break;
case UnitInputType::CLAIM:
unit = processClaimFormula(unit,f,nm);
break;
default:
break;
}
_units.pushBack(unit);
}
Unit* TPTP::processClaimFormula(Unit* unit, Formula * f, const std::string& nm)
{
bool added;
unsigned pred = env.signature->addPredicate(nm,0,added);
if (!added) {
USER_ERROR("Names of claims must be unique: "+nm);
}
env.signature->getPredicate(pred)->markLabel();
Formula* claim = new AtomicFormula(Literal::create(pred, true, {}));
ASS_EQ(freeVariables(f),VList::empty())
f = new BinaryFormula(IFF,claim,f);
return new FormulaUnit(f,
FormulaClauseTransformation(InferenceRule::CLAIM_DEFINITION,unit));
}
void TPTP::addTagState(Tag t)
{
_states.push(TAG);
_tags.push(t);
}
void TPTP::endTff()
{
int rpars= _ints.pop();
while (rpars--) {
consumeToken(T_RPAR);
}
skipToRPAR();
consumeToken(T_DOT);
ASS(_typeTags.isEmpty());
Type* t = _types.pop();
ASS(_types.isEmpty());
OperatorType* ot = constructOperatorType(t);
std::string name = _strings.pop();
unsigned arity = ot->arity();
bool isPredicate = ot->isPredicateType() && !_isThf;
bool isTypeCon = !isPredicate && (ot->result() == AtomicSort::superSort());
bool added;
Signature::Symbol* symbol;
if (isPredicate) {
unsigned pred = env.signature->addPredicate(name, arity, added);
symbol = env.signature->getPredicate(pred);
if (!added) {
if(symbol->predType() != ot){
USER_ERROR("Predicate symbol type is declared after its use: " + name);
}
}
else{
if (arity != 0) {
symbol->setType(ot);
}
}
} else if (isTypeCon){
unsigned typeCon = env.signature->addTypeCon(name, arity, added);
symbol = env.signature->getTypeCon(typeCon);
if (!added) {
if(symbol->typeConType() != ot){
USER_ERROR("Type constructor type is declared after its use: " + name);
}
}
else{
symbol->setType(ot);
}
} else {
unsigned fun = arity == 0
? addUninterpretedConstant(name, added)
: env.signature->addFunction(name, arity, added);
symbol = env.signature->getFunction(fun);
if (!added) {
if(symbol->fnType() != ot){
USER_ERROR("Function symbol type is declared after its use: " + name);
}
}
else {
symbol->setType(ot);
if(_isThf){
if(!_typeArities.insert(name, ot->numTypeArguments())){
USER_ERROR("Symbol " + name + " used with different type arities");
}
}
}
}
}
OperatorType* TPTP::constructOperatorType(Type* t, VList* vars, DHSet<unsigned>* ivars)
{
TermList resultSort;
Stack<TermList> argumentSorts;
switch (t->tag()) {
case TT_PRODUCT:
USER_ERROR("product types are not supported");
case TT_ATOMIC: {
resultSort = static_cast<AtomicType*>(t)->sort();
break;
}
case TT_ARROW: {
ArrowType* at = static_cast<ArrowType*>(t);
Type* rhs = at->returnType();
if (rhs->tag() != TT_ATOMIC) {
USER_ERROR("complex return types are not supported");
}
resultSort = static_cast<AtomicType*>(rhs)->sort();
Stack<Type*> types;
types.push(at->argumentType());
while (!types.isEmpty()) {
Type *tp = types.pop();
switch (tp->tag()) {
case TT_ARROW:
USER_ERROR("higher-order types are not supported");
case TT_ATOMIC: {
TermList sort = static_cast<AtomicType*>(tp)->sort();
argumentSorts.push(sort);
break;
}
case TT_PRODUCT: {
ProductType* pt = static_cast<ProductType*>(tp);
types.push(pt->rhs());
types.push(pt->lhs());
break;
}
default:
ASSERTION_VIOLATION;
}
}
break;
}
case TT_QUANTIFIED: {
if (vars) {
USER_ERROR("Only prenex (rank-1) polymorphism is allowed!");
}
QuantifiedType* qt = static_cast<QuantifiedType*>(t);
return constructOperatorType(qt->qtype(), qt->vars(), ivars);
}
default:
ASSERTION_VIOLATION;
}
if (ivars) {
auto pushFn = [&](TermList var) {
auto v = var.var();
if (!VList::member(v, vars)) {
ivars->insert(v);
}
};
for (const auto& argSort : argumentSorts) {
iterTraits(VariableIterator(argSort)).forEach(pushFn);
}
iterTraits(VariableIterator(resultSort)).forEach(pushFn);
for (const auto& v : iterTraits(ivars->iterator())) {
vars = VList::cons(v, vars);
}
}
bool isPredicate = resultSort == AtomicSort::boolSort();
unsigned arity = (unsigned)argumentSorts.size();
if(_containsPolymorphism){
SortHelper::normaliseArgSorts(vars, argumentSorts);
SortHelper::normaliseSort(vars, resultSort);
}
if (isPredicate && !_isThf) { return OperatorType::getPredicateType(arity, argumentSorts.begin(), VList::length(vars));
} else {
return OperatorType::getFunctionType(arity, argumentSorts.begin(), resultSort, VList::length(vars));
}
}
TPTP::SourceRecord* TPTP::getSource()
{
if (getTok(0).tag != T_COMMA) { return 0;
}
consumeToken(T_COMMA);
Token& source_kind = getTok(0);
if(source_kind.tag != T_NAME) return 0;
resetToks();
if (getTok(0).tag != T_LPAR) {
return 0;
} else {
resetToks();
}
if(source_kind.content == "file"){
std::string fileName = getTok(0).content;
resetToks();
consumeToken(T_COMMA);
resetToks();
std::string nameInFile = getTok(0).content;
resetToks();
consumeToken(T_RPAR);
return new FileSourceRecord(fileName,nameInFile);
}
else if(source_kind.content == "inference" || source_kind.content == "introduced"){
bool introduced = (source_kind.content == "introduced");
std::string name = getTok(0).content;
resetToks();
InferenceSourceRecord* r = new InferenceSourceRecord(name);
if(introduced){
resetToks();
skipToRPAR();
return r;
}
consumeToken(T_COMMA);
consumeToken(T_LBRA);
skipToRBRA();
consumeToken(T_COMMA);
consumeToken(T_LBRA);
Token tok;
while((tok=getTok(0)).tag != T_RBRA){
resetToks();
if(tok.tag == T_COMMA) continue;
if (tok.tag != T_NAME && tok.tag != T_INT) {
cout << "read token " << tok.tag << " with content " << tok.content << endl;
PARSE_ERROR_TOK("Source unit name expected",tok);
}
std::string premise = tok.content;
tok = getTok(0);
if (tok.tag != T_COMMA && tok.tag != T_RBRA) {
resetToks();
skipToRPAR();
} else {
r->premises.push(premise);
}
}
resetToks();
consumeToken(T_RPAR);
return r;
} else {
skipToRPAR();
}
return 0;
}
void TPTP::skipToRPAR()
{
int balance = 0;
for (;;) {
Token tok = getTok(0);
switch (tok.tag) {
case T_EOF:
PARSE_ERROR_TOK(") not found",tok);
case T_LPAR:
resetToks();
balance++;
break;
case T_RPAR:
resetToks();
balance--;
if (balance == -1) {
return;
}
break;
default:
resetToks();
break;
}
}
}
void TPTP::skipToRBRA()
{
int balance = 0;
for (;;) {
Token tok = getTok(0);
switch (tok.tag) {
case T_EOF:
PARSE_ERROR_TOK(") not found",tok);
case T_LBRA:
resetToks();
balance++;
break;
case T_RBRA:
resetToks();
balance--;
if (balance == -1) {
return;
}
break;
default:
resetToks();
break;
}
}
}
void TPTP::simpleFormula()
{
Token tok = getTok(0);
switch (tok.tag) {
case T_NOT:
resetToks();
_connectives.push(NOT);
_states.push(SIMPLE_FORMULA);
return;
case T_FORALL:
case T_EXISTS:
resetToks();
consumeToken(T_LBRA);
_connectives.push(tok.tag == T_FORALL ? FORALL : EXISTS);
_states.push(UNBIND_VARIABLES);
_states.push(SIMPLE_FORMULA);
addTagState(T_COLON);
addTagState(T_RBRA);
_states.push(VAR_LIST);
return;
case T_LPAR:
resetToks();
addTagState(T_RPAR);
_states.push(FORMULA);
return;
case T_STRING:
_states.push(END_EQ);
_states.push(TERM);
_states.push(MID_EQ);
_states.push(TERM);
return;
case T_INT:
case T_RAT:
case T_REAL:
_states.push(END_EQ);
_states.push(TERM);
_states.push(MID_EQ);
_states.push(TERM);
return;
case T_TRUE:
resetToks();
_formulas.push(new Formula(true));
return;
case T_FALSE:
resetToks();
_formulas.push(new Formula(false));
return;
case T_NAME:
case T_VAR:
case T_ITE:
case T_THEORY_FUNCTION:
case T_LET:
case T_LBRA:
_states.push(FORMULA_INFIX);
_states.push(FUN_APP);
return;
default:
PARSE_ERROR_TOK("formula or term expected",tok);
}
}
void TPTP::unbindVariables()
{
VList::Iterator vs(_bindLists.pop());
while (vs.hasNext()) {
unsigned var = vs.next();
SList** sorts = _variableSorts.getPtr(var); ALWAYS(sorts);
SList::pop(*sorts); }
}
void TPTP::simpleType()
{
Token& tok = getTok(0);
if(tok.tag == T_TYPE_QUANT) {
_containsPolymorphism = true;
resetToks();
_typeTags.push(TT_QUANTIFIED);
consumeToken(T_LBRA);
_states.push(UNBIND_VARIABLES);
_states.push(TYPE);
addTagState(T_COLON);
addTagState(T_RBRA);
_states.push(VAR_LIST);
return;
}
if(_isThf){
_types.push(new AtomicType(readArrowSort()));
return;
}
if (tok.tag == T_LPAR) {
resetToks();
addTagState(T_RPAR);
_states.push(TYPE);
return;
}
_types.push(new AtomicType(readSort()));
}
TermList TPTP::readArrowSort()
{
int inBrackets = 0;
TermStack terms;
Token tok = getTok(0);
TermList sort;
TermList dummy = TermList(0, true);
while((tok.tag != T_COMMA) && (tok.tag != T_RBRA) && (tok.tag != T_APP)){
switch(tok.tag){
case T_LPAR: terms.push(dummy);
inBrackets += 1;
break;
case T_ARROW:
break;
case T_RPAR:
inBrackets -= 1;
if(inBrackets < 0)
goto afterWhile;
foldl(&terms);
break;
default:{
sort = readSort();
terms.push(sort);
if(!sort.isVar() && sort.term()->arity()){
tok = getTok(0);
continue;
}
}
}
resetToks();
tok = getTok(0);
}
afterWhile:
if(terms.size() != 1){
foldl(&terms);
}
ASS(terms.size() == 1);
return terms.pop();
}
void TPTP::foldl(TermStack* terms)
{
TermList item1 = terms->pop();
TermList item2 = terms->pop();
while(!(terms->isEmpty()) && (!item2.isSpecialVar())){
item1 = AtomicSort::arrowSort(item2, item1);
item2 = terms->pop();
}
if (!item2.isSpecialVar()){
item1 = AtomicSort::arrowSort(item2, item1);;
}
terms->push(item1);
}
void TPTP::readTypeArgs(unsigned arity)
{
for(unsigned i = 0; i < arity; i++){
consumeToken(T_APP);
Token tok = getTok(0);
if(tok.tag == T_LPAR){
resetToks();
_termLists.push(readArrowSort());
consumeToken(T_RPAR);
} else {
_termLists.push(readArrowSort());
}
}
}
TermList TPTP::readSort()
{
Token tok = getTok(0);
resetToks();
switch (tok.tag) {
case T_NAME:
{
unsigned arity = 0;
std::string fname = tok.content;
if(_isThf){
arity = _typeConstructorArities.find(fname) ? _typeConstructorArities.get(fname) : 0;
readTypeArgs(arity);
} else {
int c = getChar(0);
if(c == '('){
consumeToken(T_LPAR);
for(;;){
arity++;
_termLists.push(readSort());
tok = getTok(0);
if(tok.tag == T_COMMA){
consumeToken(T_COMMA);
}else if(tok.tag == T_RPAR){
consumeToken(T_RPAR);
break;
} else{
ASSERTION_VIOLATION;
}
}
}
}
return createTypeConApplication(fname, arity);
}
case T_VAR:
{
std::string vname = tok.content;
unsigned var = _vars.insert(vname, _vars.size());
return TermList(var, false);
}
case T_DEFAULT_TYPE:
return AtomicSort::defaultSort();
case T_BOOL_TYPE:
return AtomicSort::boolSort();
case T_INTEGER_TYPE:
return AtomicSort::intSort();
case T_RATIONAL_TYPE:
return AtomicSort::rationalSort();
case T_REAL_TYPE:
return AtomicSort::realSort();
case T_TTYPE:
return AtomicSort::superSort();
case T_LBRA:
{
TermStack sorts;
for (;;) {
TermList sort = readSort();
sorts.push(sort);
if (getTok(0).tag == T_COMMA) {
resetToks();
} else {
consumeToken(T_RBRA);
break;
}
}
if (sorts.length() < 2) {
USER_ERROR("Tuple sort with less than two arguments");
}
return AtomicSort::tupleSort((unsigned) sorts.length(), sorts.begin());
}
case T_THEORY_SORT: {
TermList sort;
consumeToken(T_LPAR);
switch (getTheorySort(tok)) {
case TS_ARRAY: {
TermList indexSort = readSort();
consumeToken(T_COMMA);
TermList innerSort = readSort();
sort = AtomicSort::arraySort(indexSort, innerSort);
break;
}
default:
ASSERTION_VIOLATION;
}
consumeToken(T_RPAR);
return sort;
}
default:
PARSE_ERROR_TOK("sort expected",tok);
}
}
bool TPTP::higherPrecedence(int c1,int c2)
{
if (c1 == APP) return true;
if (c1 == c2) return false;
if (c1 == -1) return false;
if (c2 == IFF) return true;
if (c1 == IFF) return false;
if (c2 == XOR) return true;
if (c1 == XOR) return false;
if (c2 == IMP) return true;
if (c1 == IMP) return false;
if (c2 == OR) return true;
if (c1 == OR) return false;
ASSERTION_VIOLATION;
}
bool TPTP::findInterpretedPredicate(std::string name, unsigned arity) {
if (name == "$evaleq" || name == "$equal" || name == "$distinct") {
return true;
}
if (name == "$is_int" || name == "$is_rat") {
return arity == 1;
}
if (name == "$less" || name == "$lesseq" || name == "$greater" || name == "$greatereq" || name == "$divides") {
return arity == 2;
}
return false;
}
Formula* TPTP::makeJunction (Connective c,Formula* lhs,Formula* rhs)
{
if (lhs->connective() == c) {
FormulaList* largs = lhs->args();
if (rhs->connective() == c) {
FormulaList::concat(largs,rhs->args());
delete static_cast<JunctionFormula*>(rhs);
return lhs;
}
FormulaList::concat(largs,new FormulaList(rhs));
return lhs;
}
if (rhs->connective() == c) {
static_cast<JunctionFormula*>(rhs)->setArgs(new FormulaList(lhs,
rhs->args()));
return rhs;
}
return new JunctionFormula(c,
new FormulaList(lhs,
new FormulaList(rhs)));
}
unsigned TPTP::addFunction(std::string name,int arity,bool& added,TermList& arg)
{
if (name == "$sum") {
return addOverloadedFunction(name,arity,2,added,arg,
Theory::INT_PLUS,
Theory::RAT_PLUS,
Theory::REAL_PLUS);
}
if (name == "$difference") {
return addOverloadedFunction(name,arity,2,added,arg,
Theory::INT_MINUS,
Theory::RAT_MINUS,
Theory::REAL_MINUS);
}
if (name == "$product") {
return addOverloadedFunction(name,arity,2,added,arg,
Theory::INT_MULTIPLY,
Theory::RAT_MULTIPLY,
Theory::REAL_MULTIPLY);
}
if (name == "$divide") {
return addOverloadedFunction(name,arity,2,added,arg,
Theory::INT_QUOTIENT_E,
Theory::RAT_QUOTIENT,
Theory::REAL_QUOTIENT);
}
if (name == "$modulo"){
if(sortOf(arg)!=AtomicSort::intSort()){
USER_ERROR("$modulo can only be used with integer type");
}
return addOverloadedFunction(name,arity,2,added,arg,
Theory::INT_REMAINDER_E, Theory::INT_REMAINDER_E, Theory::INT_REMAINDER_E); }
if (name == "$abs"){
if(sortOf(arg)!=AtomicSort::intSort()){
USER_ERROR("$abs can only be used with integer type");
}
return addOverloadedFunction(name,arity,1,added,arg,
Theory::INT_ABS,
Theory::INT_ABS, Theory::INT_ABS); }
if (name == "$quotient") {
if(sortOf(arg)==AtomicSort::intSort()){
USER_ERROR("$quotient cannot be used with integer type");
}
return addOverloadedFunction(name,arity,2,added,arg,
Theory::INT_QUOTIENT_E, Theory::RAT_QUOTIENT,
Theory::REAL_QUOTIENT);
}
if (name == "$quotient_e") {
return addOverloadedFunction(name,arity,2,added,arg,
Theory::INT_QUOTIENT_E,
Theory::RAT_QUOTIENT_E,
Theory::REAL_QUOTIENT_E);
}
if (name == "$quotient_t") {
return addOverloadedFunction(name,arity,2,added,arg,
Theory::INT_QUOTIENT_T,
Theory::RAT_QUOTIENT_T,
Theory::REAL_QUOTIENT_T);
}
if (name == "$quotient_f") {
return addOverloadedFunction(name,arity,2,added,arg,
Theory::INT_QUOTIENT_F,
Theory::RAT_QUOTIENT_F,
Theory::REAL_QUOTIENT_F);
}
if (name == "$remainder_e") {
return addOverloadedFunction(name,arity,2,added,arg,
Theory::INT_REMAINDER_E,
Theory::RAT_REMAINDER_E,
Theory::REAL_REMAINDER_E);
}
if (name == "$remainder_t") {
return addOverloadedFunction(name,arity,2,added,arg,
Theory::INT_REMAINDER_T,
Theory::RAT_REMAINDER_T,
Theory::REAL_REMAINDER_T);
}
if (name == "$remainder_f") {
return addOverloadedFunction(name,arity,2,added,arg,
Theory::INT_REMAINDER_F,
Theory::RAT_REMAINDER_F,
Theory::REAL_REMAINDER_F);
}
if (name == "$uminus") {
return addOverloadedFunction(name,arity,1,added,arg,
Theory::INT_UNARY_MINUS,
Theory::RAT_UNARY_MINUS,
Theory::REAL_UNARY_MINUS);
}
if (name == "$successor"){
if(sortOf(arg)!=AtomicSort::intSort()){
USER_ERROR("$succ can only be used with integer type");
}
return addOverloadedFunction(name,arity,1,added,arg,
Theory::INT_SUCCESSOR,
Theory::INT_SUCCESSOR, Theory::INT_SUCCESSOR); }
if (name == "$floor") {
return addOverloadedFunction(name,arity,1,added,arg,
Theory::INT_FLOOR,
Theory::RAT_FLOOR,
Theory::REAL_FLOOR);
}
if (name == "$ceiling") {
return addOverloadedFunction(name,arity,1,added,arg,
Theory::INT_CEILING,
Theory::RAT_CEILING,
Theory::REAL_CEILING);
}
if (name == "$truncate") {
return addOverloadedFunction(name,arity,1,added,arg,
Theory::INT_TRUNCATE,
Theory::RAT_TRUNCATE,
Theory::REAL_TRUNCATE);
}
if (name == "$round") {
return addOverloadedFunction(name,arity,1,added,arg,
Theory::INT_ROUND,
Theory::RAT_ROUND,
Theory::REAL_ROUND);
}
if (name == "$to_int") {
return addOverloadedFunction(name,arity,1,added,arg,
Theory::INT_TO_INT,
Theory::RAT_TO_INT,
Theory::REAL_TO_INT);
}
if (name == "$to_rat") {
return addOverloadedFunction(name,arity,1,added,arg,
Theory::INT_TO_RAT,
Theory::RAT_TO_RAT,
Theory::REAL_TO_RAT);
}
if (name == "$to_real") {
return addOverloadedFunction(name,arity,1,added,arg,
Theory::INT_TO_REAL,
Theory::RAT_TO_REAL,
Theory::REAL_TO_REAL);
}
if (name == "vPI" || name == "vSIGMA"){
return env.signature->getPiSigmaProxy(name);
}
if (arity > 0) {
return env.signature->addFunction(name,arity,added);
}
return addUninterpretedConstant(name,added);
}
int TPTP::addPredicate(std::string name,int arity,bool& added,TermList& arg)
{
if (name == "$evaleq" || name == "$equal") {
return -1;
}
if (name == "$less") {
return addOverloadedPredicate(name,arity,2,added,arg,
Theory::INT_LESS,
Theory::RAT_LESS,
Theory::REAL_LESS);
}
if (name == "$lesseq") {
return addOverloadedPredicate(name,arity,2,added,arg,
Theory::INT_LESS_EQUAL,
Theory::RAT_LESS_EQUAL,
Theory::REAL_LESS_EQUAL);
}
if (name == "$greater") {
return addOverloadedPredicate(name,arity,2,added,arg,
Theory::INT_GREATER,
Theory::RAT_GREATER,
Theory::REAL_GREATER);
}
if (name == "$greatereq") {
return addOverloadedPredicate(name,arity,2,added,arg,
Theory::INT_GREATER_EQUAL,
Theory::RAT_GREATER_EQUAL,
Theory::REAL_GREATER_EQUAL);
}
if (name == "$is_int") {
return addOverloadedPredicate(name,arity,1,added,arg,
Theory::INT_IS_INT,
Theory::RAT_IS_INT,
Theory::REAL_IS_INT);
}
if (name == "$divides"){
if(sortOf(arg)!=AtomicSort::intSort()){
USER_ERROR("$divides can only be used with integer type");
}
return addOverloadedPredicate(name,arity,2,added,arg,
Theory::INT_DIVIDES,
Theory::INT_DIVIDES, Theory::INT_DIVIDES); }
if (name == "$is_rat") {
return addOverloadedPredicate(name,arity,1,added,arg,
Theory::INT_IS_RAT,
Theory::RAT_IS_RAT,
Theory::REAL_IS_RAT);
}
if(name == "$distinct"){
return -2;
}
return env.signature->addPredicate(name,arity,added);
}
unsigned TPTP::addOverloadedFunction(std::string name,int arity,int symbolArity,bool& added,TermList& arg,
Theory::Interpretation integer,Theory::Interpretation rational,
Theory::Interpretation real)
{
if (arity != symbolArity) {
USER_ERROR(name + " is used with " + Int::toString(arity) + " argument(s) when there were "+Int::toString(symbolArity)+" expected");
}
TermList srt = sortOf(arg);
TermList* n = arg.next();
for(int i=1;i<arity;i++){
if(sortOf(*n)!=srt){
std::string msg = "The interpreted function symbol " + name + " is not used with a single sort.";
msg += "\nArgument 0 is "+srt.toString()+" and argument "+Lib::Int::toString(i)+" is "+sortOf(*n).toString();
USER_ERROR(msg);
}
n = n->next();
}
if (srt == AtomicSort::intSort()) {
return env.signature->addInterpretedFunction(integer,name);
}
if (srt == AtomicSort::rationalSort()) {
return env.signature->addInterpretedFunction(rational,name);
}
if (srt == AtomicSort::realSort()) {
return env.signature->addInterpretedFunction(real,name);
}
USER_ERROR("The symbol " + name + " is used with a non-numeric type");
}
unsigned TPTP::addOverloadedPredicate(std::string name,int arity,int symbolArity,bool& added,TermList& arg,
Theory::Interpretation integer,Theory::Interpretation rational,
Theory::Interpretation real)
{
if (arity != symbolArity) {
USER_ERROR(name + " is used with " + Int::toString(arity) + " argument(s) when there were "+Int::toString(symbolArity)+" expected");
}
TermList srt = sortOf(arg);
TermList* n = arg.next();
for(int i=1;i<arity;i++){
if(sortOf(*n)!=srt){
std::string msg = "The interpreted predicate symbol " + name + " is not used with a single sort.";
msg += "\nArgument 0 is "+srt.toString()+" and argument "+Lib::Int::toString(i)+" is "+sortOf(*n).toString();
USER_ERROR(msg);
}
n = n->next();
}
if (srt == AtomicSort::intSort()) {
return env.signature->addInterpretedPredicate(integer,name);
}
if (srt == AtomicSort::rationalSort()) {
return env.signature->addInterpretedPredicate(rational,name);
}
if (srt == AtomicSort::realSort()) {
return env.signature->addInterpretedPredicate(real,name);
}
USER_ERROR("The symbol " + name + " is used with a non-numeric type");
}
TermList TPTP::sortOf(TermList t)
{
for (;;) {
if (t.isVar()) {
SList* sorts;
if (_variableSorts.find(t.var(),sorts) && SList::isNonEmpty(sorts)) {
return sorts->head();
}
TermList def = AtomicSort::defaultSort();
bindVariable(t.var(), def);
return def;
}
TermList sort;
TermList mvar;
if (SortHelper::getResultSortOrMasterVariable(t.term(), sort, mvar)) { return sort;
} else {
t = mvar;
}
}
}
unsigned TPTP::addUninterpretedConstant(const std::string& name, bool& added)
{
if(name == "vAND" || name == "vOR" || name == "vIMP" ||
name == "vIFF" || name == "vXOR"){
return env.signature->getBinaryProxy(name);
} else if (name == "vNOT"){
return env.signature->getNotProxy();
}
return env.signature->addFunction(name,0,added);
}
void TPTP::assignAxiomName(const Unit* unit, std::string& name)
{
ALWAYS(_axiomNames.insert(unit->number(), name));
}
bool TPTP::findAxiomName(const Unit* unit, std::string& result)
{
return _axiomNames.find(unit->number(), result);
}
void TPTP::vampire()
{
consumeToken(T_LPAR);
std::string nm = name();
if (nm == "option") { consumeToken(T_COMMA);
std::string opt = name();
consumeToken(T_COMMA);
Token tok = getTok(0);
switch (tok.tag) {
case T_INT:
case T_REAL:
case T_NAME:
env.options->set(opt,tok.content);
resetToks();
break;
default:
PARSE_ERROR_TOK("either atom or number expected as a value of a Vampire option",tok);
}
}
else if (nm == "symbol") {
consumeToken(T_COMMA);
std::string kind = name();
bool pred;
if (kind == "predicate") {
pred = true;
}
else if (kind == "function") {
pred = false;
}
else {
PARSE_ERROR_TOK("either 'predicate' or 'function' expected",getTok(0));
}
consumeToken(T_COMMA);
std::string symb = name();
consumeToken(T_COMMA);
Token tok = getTok(0);
if (tok.tag != T_INT) {
PARSE_ERROR_TOK("a non-negative integer (denoting arity) expected",tok);
}
unsigned arity;
if (!Int::stringToUnsignedInt(tok.content,arity)) {
PARSE_ERROR_TOK("a number denoting arity expected",tok);
}
resetToks();
consumeToken(T_COMMA);
Color color = COLOR_INVALID;
bool skip = false, uncomputable = false;
std::string lr = name();
if (lr == "left") {
color=COLOR_LEFT;
}
else if (lr == "right") {
color=COLOR_RIGHT;
}
else if (lr == "skip") {
skip = true;
}
else if (lr == "uncomputable") {
uncomputable = true;
}
else {
PARSE_ERROR_TOK("'left', 'right', 'skip' or 'uncomputable' expected",getTok(0));
}
if (!uncomputable) {
env.colorUsed = true;
}
unsigned f = pred ? env.signature->addPredicate(symb,arity) : env.signature->addFunction(symb,arity);
Signature::Symbol* sym = pred ? env.signature->getPredicate(f) : env.signature->getFunction(f);
if (skip) {
sym->markSkip();
}
else if (uncomputable) {
if (env.options->questionAnswering() != Options::QuestionAnsweringMode::SYNTHESIS) {
std::cout << "% WARNING: Found the :uncomputable option but synthesis is not enabled. Consider running with '-qa synthesis'." << endl;
} else {
static_cast<Shell::SynthesisALManager*>(Shell::SynthesisALManager::getInstance())->addDeclaredSymbolAnnotatedAsUncomputable(std::make_pair(f, pred));
}
}
else {
ASS_NEQ(color, COLOR_INVALID);
sym->addColor(color);
}
}
else if (nm == "left_formula") { _currentColor = COLOR_LEFT;
}
else if (nm == "right_formula") { _currentColor = COLOR_RIGHT;
}
else if (nm == "end_formula") { _currentColor = COLOR_TRANSPARENT;
}
else if (nm == "model_check"){
consumeToken(T_COMMA);
std::string command = name();
if(command == "formulas_start"){
_modelDefinition = false;
}
else if(command == "formulas_end"){
}
else if(command == "model_start"){
_modelDefinition = true;
}
else if(command == "model_end"){
_modelDefinition = false;
}
else USER_ERROR("Unknown model_check command");
}
else {
USER_ERROR("Unknown vampire directive: "+nm);
}
consumeToken(T_RPAR);
consumeToken(T_DOT);
}
#if VDEBUG
const char* TPTP::toString(State s)
{
switch (s) {
case UNIT_LIST:
return "UNIT_LIST";
case CNF:
return "CNF";
case FOF:
return "FOF";
case VAMPIRE:
return "VAMPIRE";
case FORMULA:
return "FORMULA";
case END_FOF:
return "END_FOF";
case SIMPLE_FORMULA:
return "SIMPLE_FORMULA";
case END_FORMULA:
return "END_FORMULA";
case FORMULA_INSIDE_TERM:
return "FORMULA_INSIDE_TERM";
case END_FORMULA_INSIDE_TERM:
return "END_FORMULA_INSIDE_TERM";
case END_TERM_AS_FORMULA:
return "END_TERM_AS_FORMULA";
case VAR_LIST:
return "VAR_LIST";
case FUN_APP:
return "FUN_APP";
case FORMULA_INFIX:
return "FORMULA_INFIX";
case ARGS:
return "ARGS";
case TERM:
return "TERM";
case TERM_INFIX:
return "TERM_INFIX";
case END_TERM:
return "END_TERM";
case TAG:
return "TAG";
case INCLUDE:
return "INCLUDE";
case END_EQ:
return "END_EQ";
case TFF:
return "TFF";
case THF:
return "THF";
case TYPE:
return "TYPE";
case END_TFF:
return "END_TFF";
case END_APP:
return "END_APP";
case HOL_FORMULA:
return "HOL_FORMULA";
case END_HOL_FORMULA:
return "END_HOL_FORMULA";
case HOL_TERM:
return "HOL_TERM";
case END_TYPE:
return "END_TYPE";
case SIMPLE_TYPE:
return "SIMPLE_TYPE";
case END_THEORY_FUNCTION:
return "END_THEORY_FUNCTION";
case END_ARGS:
return "END_ARGS";
case MID_EQ:
return "MID_EQ";
case LET_TYPE:
return "LET_TYPE";
case END_LET_TYPES:
return "END_LET_TYPES";
case DEFINITION:
return "DEFINITION";
case MID_DEFINITION:
return "MID_DEFINITION";
case END_DEFINITION:
return "END_DEFINITION";
case SYMBOL_DEFINITION:
return "SYMBOL_DEFINITION";
case TUPLE_DEFINITION:
return "TUPLE_DEFINITION";
case END_LET:
return "END_LET";
case UNBIND_VARIABLES:
return "UNBIND_VARIABLES";
case END_ITE:
return "END_ITE";
case END_TUPLE:
return "END_TUPLE";
default:
cout << (int)s << "\n";
ASS(false);
break;
}
}
#endif
#ifdef DEBUG_SHOW_STATE
void TPTP::printStacks() {
Stack<State>::Iterator stit(_states);
cout << "States:";
if (!stit.hasNext()) cout << " <empty>";
while (stit.hasNext()) cout << " " << toString(stit.next());
cout << endl;
Stack<TermList>::Iterator tit(_termLists);
cout << "Terms:";
if (!tit.hasNext()) cout << " <empty>";
while (tit.hasNext()) cout << " " << tit.next().toString();
cout << endl;
Stack<Formula*>::Iterator fit(_formulas);
cout << "Formulas:";
if (!fit.hasNext()) cout << " <empty>";
while (fit.hasNext()) cout << " " << fit.next()->toString();
cout << endl;
cout << endl;
}
#endif