mirror of
https://github.com/Z3Prover/z3
synced 2026-05-25 03:16:21 +00:00
fix tptp errors
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
2ba86c1ac3
commit
eeddc94647
1 changed files with 65 additions and 100 deletions
|
|
@ -282,6 +282,7 @@ class tptp_parser {
|
||||||
expr_ref_vector m_pinned_exprs; // prevents bound variable apps from being freed
|
expr_ref_vector m_pinned_exprs; // prevents bound variable apps from being freed
|
||||||
std::unordered_map<std::string, std::pair<std::vector<sort*>, sort*>> m_typed_decls;
|
std::unordered_map<std::string, std::pair<std::vector<sort*>, sort*>> m_typed_decls;
|
||||||
std::vector<std::unordered_map<std::string, app*>> m_bound;
|
std::vector<std::unordered_map<std::string, app*>> m_bound;
|
||||||
|
bool m_in_at_arg = false; // true when parsing inside @ argument (lambda body stops consuming @)
|
||||||
struct implicit_var_scope {
|
struct implicit_var_scope {
|
||||||
std::unordered_map<std::string, app*> vars;
|
std::unordered_map<std::string, app*> vars;
|
||||||
ptr_vector<app> order;
|
ptr_vector<app> order;
|
||||||
|
|
@ -350,6 +351,8 @@ class tptp_parser {
|
||||||
case token_kind::nor_tok: return "~|";
|
case token_kind::nor_tok: return "~|";
|
||||||
case token_kind::and_tok: return "&";
|
case token_kind::and_tok: return "&";
|
||||||
case token_kind::nand_tok: return "~&";
|
case token_kind::nand_tok: return "~&";
|
||||||
|
case token_kind::equal_tok: return "=";
|
||||||
|
case token_kind::neq_tok: return "!=";
|
||||||
default: return nullptr;
|
default: return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -501,17 +504,17 @@ class tptp_parser {
|
||||||
func_decl* mk_decl_or_ho_const(std::string const& name, unsigned arity, bool pred) {
|
func_decl* mk_decl_or_ho_const(std::string const& name, unsigned arity, bool pred) {
|
||||||
if (arity == 0) {
|
if (arity == 0) {
|
||||||
// Check if there's a typed decl at any arity > 0 for this name
|
// Check if there's a typed decl at any arity > 0 for this name
|
||||||
for (unsigned try_arity = 1; try_arity <= 10; ++try_arity) {
|
for (unsigned try_arity = 1; try_arity <= 30; ++try_arity) {
|
||||||
auto itt = m_typed_decls.find(mk_typed_key(name, try_arity));
|
auto itt = m_typed_decls.find(mk_typed_key(name, try_arity));
|
||||||
if (itt != m_typed_decls.end()) {
|
if (itt != m_typed_decls.end()) {
|
||||||
auto const& sig = itt->second;
|
auto const& sig = itt->second;
|
||||||
sort* ho = get_ho_sort(sig.first, sig.second);
|
sort* ho = get_ho_sort(sig.first, sig.second);
|
||||||
std::string key = mk_decl_key(name, 0, 'h');
|
std::string dkey = mk_decl_key(name, 0, 'h');
|
||||||
auto itd = m_decls.find(key);
|
auto itd = m_decls.find(dkey);
|
||||||
if (itd != m_decls.end()) return itd->second;
|
if (itd != m_decls.end()) return itd->second;
|
||||||
func_decl* f = m.mk_func_decl(symbol(name), 0, static_cast<sort**>(nullptr), ho);
|
func_decl* f = m.mk_func_decl(symbol(name), 0, static_cast<sort**>(nullptr), ho);
|
||||||
m_pinned_decls.push_back(f);
|
m_pinned_decls.push_back(f);
|
||||||
m_decls.emplace(key, f);
|
m_decls.emplace(dkey, f);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -951,7 +954,11 @@ class tptp_parser {
|
||||||
}
|
}
|
||||||
expect(token_kind::colon, "':'");
|
expect(token_kind::colon, "':'");
|
||||||
m_bound.push_back(scope);
|
m_bound.push_back(scope);
|
||||||
|
// Quantifier body in @-arg should NOT consume @ — those belong to enclosing application
|
||||||
|
bool save_in_at_arg = m_in_at_arg;
|
||||||
|
m_in_at_arg = true;
|
||||||
expr_ref body = parse_formula();
|
expr_ref body = parse_formula();
|
||||||
|
m_in_at_arg = save_in_at_arg;
|
||||||
m_bound.pop_back();
|
m_bound.pop_back();
|
||||||
return mk_quantifier(is_forall, vars, body);
|
return mk_quantifier(is_forall, vars, body);
|
||||||
}
|
}
|
||||||
|
|
@ -994,34 +1001,19 @@ class tptp_parser {
|
||||||
|
|
||||||
expr_ref parse_atomic_formula() {
|
expr_ref parse_atomic_formula() {
|
||||||
if (accept(token_kind::lparen)) {
|
if (accept(token_kind::lparen)) {
|
||||||
|
// Parentheses create a new scope for @ consumption
|
||||||
|
bool save_in_at_arg = m_in_at_arg;
|
||||||
|
m_in_at_arg = false;
|
||||||
expr_ref e = parse_formula();
|
expr_ref e = parse_formula();
|
||||||
// Handle equality/inequality inside parenthesized expressions
|
|
||||||
// In THF, (A = B) is used even for Bool-sorted expressions (meaning iff)
|
|
||||||
if (is(token_kind::equal_tok) || is(token_kind::neq_tok)) {
|
|
||||||
bool neq = accept(token_kind::neq_tok);
|
|
||||||
if (!neq) expect(token_kind::equal_tok, "'='");
|
|
||||||
expr_ref rhs = m.is_bool(e) ? parse_formula() : parse_term();
|
|
||||||
e = coerce_eq(e, rhs);
|
|
||||||
expr_ref eq(m.mk_eq(e, rhs), m);
|
|
||||||
e = neq ? expr_ref(m.mk_not(eq), m) : eq;
|
|
||||||
}
|
|
||||||
expect(token_kind::rparen, "')'");
|
expect(token_kind::rparen, "')'");
|
||||||
return apply_at(e);
|
m_in_at_arg = save_in_at_arg;
|
||||||
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle negative numerals in formula position: -2 = $uminus(2)
|
// Handle negative numerals in formula position: -2 = $uminus(2)
|
||||||
if (accept(token_kind::minus_tok)) {
|
if (accept(token_kind::minus_tok)) {
|
||||||
expr_ref t = parse_term();
|
expr_ref t = parse_term();
|
||||||
expr_ref lhs(m_arith.mk_uminus(t), m);
|
return expr_ref(m_arith.mk_uminus(t), m);
|
||||||
if (is(token_kind::equal_tok) || is(token_kind::neq_tok)) {
|
|
||||||
bool neq = accept(token_kind::neq_tok);
|
|
||||||
if (!neq) expect(token_kind::equal_tok, "'='");
|
|
||||||
expr_ref rhs = parse_term();
|
|
||||||
lhs = coerce_eq(lhs, rhs);
|
|
||||||
expr_ref eq(m.mk_eq(lhs, rhs), m);
|
|
||||||
return neq ? expr_ref(m.mk_not(eq), m) : eq;
|
|
||||||
}
|
|
||||||
return lhs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string n = parse_name();
|
std::string n = parse_name();
|
||||||
|
|
@ -1029,15 +1021,7 @@ class tptp_parser {
|
||||||
if (n == "$false") return expr_ref(m.mk_false(), m);
|
if (n == "$false") return expr_ref(m.mk_false(), m);
|
||||||
|
|
||||||
if (is_nonempty_digit_string(n)) {
|
if (is_nonempty_digit_string(n)) {
|
||||||
expr_ref lhs = parse_numeral_from_name(n);
|
return parse_numeral_from_name(n);
|
||||||
if (is(token_kind::equal_tok) || is(token_kind::neq_tok)) {
|
|
||||||
bool neq = accept(token_kind::neq_tok);
|
|
||||||
if (!neq) expect(token_kind::equal_tok, "'='");
|
|
||||||
expr_ref rhs = parse_term();
|
|
||||||
expr_ref eq(m.mk_eq(lhs, rhs), m);
|
|
||||||
return neq ? expr_ref(m.mk_not(eq), m) : eq;
|
|
||||||
}
|
|
||||||
throw parse_error("numeric term used as formula");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
expr_ref_vector args(m);
|
expr_ref_vector args(m);
|
||||||
|
|
@ -1061,19 +1045,7 @@ class tptp_parser {
|
||||||
// Table-driven prefix operator dispatch
|
// Table-driven prefix operator dispatch
|
||||||
auto op_it = m_ops.find(n);
|
auto op_it = m_ops.find(n);
|
||||||
if (op_it != m_ops.end() && !op_it->second.is_infix) {
|
if (op_it != m_ops.end() && !op_it->second.is_infix) {
|
||||||
expr_ref result = op_it->second.builder(args);
|
return op_it->second.builder(args);
|
||||||
// If result is non-Bool, check for trailing = or !=
|
|
||||||
if (!m.is_bool(result)) {
|
|
||||||
if (is(token_kind::equal_tok) || is(token_kind::neq_tok)) {
|
|
||||||
bool neq = accept(token_kind::neq_tok);
|
|
||||||
if (!neq) expect(token_kind::equal_tok, "'='");
|
|
||||||
expr_ref rhs = parse_term();
|
|
||||||
result = coerce_eq(result, rhs);
|
|
||||||
expr_ref eq(m.mk_eq(result, rhs), m);
|
|
||||||
return neq ? expr_ref(m.mk_not(eq), m) : eq;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
expr_ref lhs(m);
|
expr_ref lhs(m);
|
||||||
|
|
@ -1090,56 +1062,19 @@ class tptp_parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is(token_kind::equal_tok) || is(token_kind::neq_tok)) {
|
if (has_lhs)
|
||||||
if (!has_lhs) {
|
return lhs;
|
||||||
func_decl* f = mk_decl_or_ho_const(n, args.size(), false);
|
|
||||||
if (!args.empty()) coerce_args(f, args);
|
|
||||||
lhs = args.empty() ? m.mk_const(f) : m.mk_app(f, args.size(), args.data());
|
|
||||||
}
|
|
||||||
bool neq = accept(token_kind::neq_tok);
|
|
||||||
if (!neq) expect(token_kind::equal_tok, "'='");
|
|
||||||
expr_ref rhs = parse_term();
|
|
||||||
lhs = coerce_eq(lhs, rhs);
|
|
||||||
expr_ref eq(m.mk_eq(lhs, rhs), m);
|
|
||||||
return neq ? expr_ref(m.mk_not(eq), m) : eq;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (has_lhs) {
|
|
||||||
lhs = apply_at(lhs);
|
|
||||||
if (is(token_kind::equal_tok) || is(token_kind::neq_tok)) {
|
|
||||||
bool neq = accept(token_kind::neq_tok);
|
|
||||||
if (!neq) expect(token_kind::equal_tok, "'='");
|
|
||||||
expr_ref rhs = parse_term();
|
|
||||||
lhs = coerce_eq(lhs, rhs);
|
|
||||||
expr_ref eq(m.mk_eq(lhs, rhs), m);
|
|
||||||
return neq ? expr_ref(m.mk_not(eq), m) : eq;
|
|
||||||
}
|
|
||||||
return lhs; // In THF, variables of any sort can appear in formula position (e.g., with @)
|
|
||||||
}
|
|
||||||
|
|
||||||
auto typed = m_typed_decls.find(mk_typed_key(n, args.size()));
|
auto typed = m_typed_decls.find(mk_typed_key(n, args.size()));
|
||||||
if (typed != m_typed_decls.end()) {
|
if (typed != m_typed_decls.end()) {
|
||||||
func_decl* f = args.empty() ? mk_decl_or_ho_const(n, 0, false) : mk_decl(n, args.size(), false);
|
func_decl* f = args.empty() ? mk_decl_or_ho_const(n, 0, false) : mk_decl(n, args.size(), false);
|
||||||
if (!args.empty()) coerce_args(f, args);
|
if (!args.empty()) coerce_args(f, args);
|
||||||
expr_ref e(args.empty() ? m.mk_const(f) : m.mk_app(f, args.size(), args.data()), m);
|
return expr_ref(args.empty() ? m.mk_const(f) : m.mk_app(f, args.size(), args.data()), m);
|
||||||
e = apply_at(e);
|
|
||||||
if (is(token_kind::equal_tok) || is(token_kind::neq_tok)) {
|
|
||||||
bool neq = accept(token_kind::neq_tok);
|
|
||||||
if (!neq) expect(token_kind::equal_tok, "'='");
|
|
||||||
expr_ref rhs = parse_term();
|
|
||||||
e = coerce_eq(e, rhs);
|
|
||||||
expr_ref eq(m.mk_eq(e, rhs), m);
|
|
||||||
return neq ? expr_ref(m.mk_not(eq), m) : eq;
|
|
||||||
}
|
|
||||||
if (!m.is_bool(e))
|
|
||||||
return e; // In THF, non-Bool typed expressions can appear in formula position (e.g., as @ args)
|
|
||||||
return e;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func_decl* pred = mk_decl_or_ho_const(n, args.size(), true);
|
func_decl* pred = mk_decl_or_ho_const(n, args.size(), true);
|
||||||
if (!args.empty()) coerce_args(pred, args);
|
if (!args.empty()) coerce_args(pred, args);
|
||||||
expr_ref result(args.empty() ? m.mk_const(pred) : m.mk_app(pred, args.size(), args.data()), m);
|
return expr_ref(args.empty() ? m.mk_const(pred) : m.mk_app(pred, args.size(), args.data()), m);
|
||||||
return apply_at(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse THF lambda expression: ^ [X: T, ...] : body
|
// Parse THF lambda expression: ^ [X: T, ...] : body
|
||||||
|
|
@ -1169,21 +1104,25 @@ class tptp_parser {
|
||||||
}
|
}
|
||||||
expect(token_kind::colon, "':'");
|
expect(token_kind::colon, "':'");
|
||||||
m_bound.push_back(scope);
|
m_bound.push_back(scope);
|
||||||
|
// Lambda body does NOT consume @ — @ belongs to the enclosing application
|
||||||
|
bool save_in_at_arg = m_in_at_arg;
|
||||||
|
m_in_at_arg = true;
|
||||||
expr_ref body = parse_formula();
|
expr_ref body = parse_formula();
|
||||||
|
m_in_at_arg = save_in_at_arg;
|
||||||
m_bound.pop_back();
|
m_bound.pop_back();
|
||||||
if (vars.empty())
|
if (vars.empty())
|
||||||
return body;
|
return body;
|
||||||
// Use expr_abstract to replace named constants with de Bruijn indices,
|
// Create nested single-variable lambdas (curried) to match our curried array encoding.
|
||||||
// then wrap with mk_lambda.
|
// ^[X:A, Y:B] : body becomes ^[X:A] : (^[Y:B] : body) with sort Array(A, Array(B, body_sort))
|
||||||
expr_ref abs_body(m);
|
expr_ref result = body;
|
||||||
expr_abstract(m, 0, vars.size(), (expr* const*)vars.data(), body, abs_body);
|
for (int i = (int)vars.size() - 1; i >= 0; --i) {
|
||||||
ptr_vector<sort> sorts;
|
expr_ref abs_body(m);
|
||||||
svector<symbol> names;
|
expr_abstract(m, 0, 1, (expr* const*)&vars[i], result, abs_body);
|
||||||
for (unsigned i = 0; i < vars.size(); ++i) {
|
sort* s = vars[i]->get_sort();
|
||||||
sorts.push_back(vars[i]->get_sort());
|
symbol nm = vars[i]->get_decl()->get_name();
|
||||||
names.push_back(vars[i]->get_decl()->get_name());
|
result = expr_ref(m.mk_lambda(1, &s, &nm, abs_body), m);
|
||||||
}
|
}
|
||||||
return expr_ref(m.mk_lambda(sorts.size(), sorts.data(), names.data(), abs_body), m);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
expr_ref parse_unary_formula() {
|
expr_ref parse_unary_formula() {
|
||||||
|
|
@ -1260,9 +1199,23 @@ class tptp_parser {
|
||||||
return parse_atomic_formula();
|
return parse_atomic_formula();
|
||||||
}
|
}
|
||||||
|
|
||||||
expr_ref parse_expr(unsigned min_prec) {
|
expr_ref parse_expr(unsigned min_prec, bool consume_at = true) {
|
||||||
expr_ref e = parse_unary_formula();
|
expr_ref e = parse_unary_formula();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
// Handle @ (function application) with highest precedence
|
||||||
|
// But NOT when we're inside a lambda body that's an @ argument
|
||||||
|
if (consume_at && !m_in_at_arg && is(token_kind::at_tok)) {
|
||||||
|
next();
|
||||||
|
expr_ref arg = parse_at_arg();
|
||||||
|
sort* e_sort = e->get_sort();
|
||||||
|
if (!m_array.is_array(e_sort)) {
|
||||||
|
std::ostringstream out;
|
||||||
|
out << "application operator (@) requires array/function type on left-hand side, got sort " << e_sort->get_name();
|
||||||
|
throw parse_error(out.str());
|
||||||
|
}
|
||||||
|
e = expr_ref(m_array.mk_select(e, arg), m);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
char const* op_name = token_to_op_name();
|
char const* op_name = token_to_op_name();
|
||||||
if (!op_name) break;
|
if (!op_name) break;
|
||||||
auto it = m_ops.find(op_name);
|
auto it = m_ops.find(op_name);
|
||||||
|
|
@ -1270,7 +1223,7 @@ class tptp_parser {
|
||||||
if (it->second.precedence < min_prec) break;
|
if (it->second.precedence < min_prec) break;
|
||||||
next(); // consume the operator token
|
next(); // consume the operator token
|
||||||
unsigned next_prec = it->second.right_assoc ? it->second.precedence : it->second.precedence + 1;
|
unsigned next_prec = it->second.right_assoc ? it->second.precedence : it->second.precedence + 1;
|
||||||
expr_ref rhs = parse_expr(next_prec);
|
expr_ref rhs = parse_expr(next_prec, consume_at);
|
||||||
expr_ref_vector args(m);
|
expr_ref_vector args(m);
|
||||||
args.push_back(e);
|
args.push_back(e);
|
||||||
args.push_back(rhs);
|
args.push_back(rhs);
|
||||||
|
|
@ -1622,6 +1575,18 @@ public:
|
||||||
m_ops["~&"] = { true, PREC_AND, false, [&](expr_ref_vector const& args) -> expr_ref {
|
m_ops["~&"] = { true, PREC_AND, false, [&](expr_ref_vector const& args) -> expr_ref {
|
||||||
return expr_ref(m.mk_not(m.mk_and(args[0], args[1])), m);
|
return expr_ref(m.mk_not(m.mk_and(args[0], args[1])), m);
|
||||||
}};
|
}};
|
||||||
|
m_ops["="] = { true, PREC_EQ, false, [&](expr_ref_vector const& args) -> expr_ref {
|
||||||
|
expr_ref lhs(args[0], m);
|
||||||
|
expr_ref rhs(args[1], m);
|
||||||
|
lhs = coerce_eq(lhs, rhs);
|
||||||
|
return expr_ref(m.mk_eq(lhs, rhs), m);
|
||||||
|
}};
|
||||||
|
m_ops["!="] = { true, PREC_EQ, false, [&](expr_ref_vector const& args) -> expr_ref {
|
||||||
|
expr_ref lhs(args[0], m);
|
||||||
|
expr_ref rhs(args[1], m);
|
||||||
|
lhs = coerce_eq(lhs, rhs);
|
||||||
|
return expr_ref(m.mk_not(m.mk_eq(lhs, rhs)), m);
|
||||||
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_input(std::istream& in, std::string const& current_file) {
|
void parse_input(std::istream& in, std::string const& current_file) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue