int exec_file(const char *fn, const char *script, const char *tmpdir, char *logbuf, unsigned loglen) { unsigned old_err; FILE *f; struct extmacro *m; signal(SIGPIPE, SIG_IGN); vtc_loginit(logbuf, loglen); vltop = vtc_logopen("top"); AN(vltop); init_macro(); init_sema(); /* Apply extmacro definitions */ VTAILQ_FOREACH(m, &extmacro_list, list) macro_def(vltop, NULL, m->name, "%s", m->val); /* * We need an IP number which will not repond, ever, and that is a * lot harder than it sounds. This IP# is from RFC5737 and a * C-class broadcast at that. * If tests involving ${bad_ip} fails and you run linux, you should * check your /proc/sys/net/ipv4/ip_nonlocal_bind setting. */ macro_def(vltop, NULL, "bad_ip", "192.0.2.255"); /* Move into our tmpdir */ AZ(chdir(tmpdir)); macro_def(vltop, NULL, "tmpdir", "%s", tmpdir); /* Drop file to tell what was going on here */ f = fopen("INFO", "w"); AN(f); fprintf(f, "Test case: %s\n", fn); AZ(fclose(f)); vtc_stop = 0; vtc_log(vltop, 1, "TEST %s starting", fn); vtc_thread = pthread_self(); parse_string(script, cmds, NULL, vltop); old_err = vtc_error; vtc_stop = 1; vtc_log(vltop, 1, "RESETTING after %s", fn); reset_cmds(cmds); vtc_error = old_err; if (vtc_error) vtc_log(vltop, 1, "TEST %s FAILED", fn); else vtc_log(vltop, 1, "TEST %s completed", fn); return (vtc_error); }
bool is_lt(expr const & a, expr const & b, bool use_hash) { if (is_eqp(a, b)) return false; unsigned wa = get_weight(a); unsigned wb = get_weight(b); if (wa < wb) return true; if (wa > wb) return false; if (a.kind() != b.kind()) return a.kind() < b.kind(); if (use_hash) { if (a.hash() < b.hash()) return true; if (a.hash() > b.hash()) return false; } if (a == b) return false; switch (a.kind()) { case expr_kind::Var: return var_idx(a) < var_idx(b); case expr_kind::Constant: if (const_name(a) != const_name(b)) return const_name(a) < const_name(b); else return is_lt(const_levels(a), const_levels(b), use_hash); case expr_kind::App: if (app_fn(a) != app_fn(b)) return is_lt(app_fn(a), app_fn(b), use_hash); else return is_lt(app_arg(a), app_arg(b), use_hash); case expr_kind::Lambda: case expr_kind::Pi: if (binding_domain(a) != binding_domain(b)) return is_lt(binding_domain(a), binding_domain(b), use_hash); else return is_lt(binding_body(a), binding_body(b), use_hash); case expr_kind::Let: if (let_type(a) != let_type(b)) return is_lt(let_type(a), let_type(b), use_hash); else if (let_value(a) != let_value(b)) return is_lt(let_value(a), let_value(b), use_hash); else return is_lt(let_body(a), let_body(b), use_hash); case expr_kind::Sort: return is_lt(sort_level(a), sort_level(b), use_hash); case expr_kind::Local: case expr_kind::Meta: if (mlocal_name(a) != mlocal_name(b)) return mlocal_name(a) < mlocal_name(b); else return is_lt(mlocal_type(a), mlocal_type(b), use_hash); case expr_kind::Macro: if (macro_def(a) != macro_def(b)) return macro_def(a) < macro_def(b); if (macro_num_args(a) != macro_num_args(b)) return macro_num_args(a) < macro_num_args(b); for (unsigned i = 0; i < macro_num_args(a); i++) { if (macro_arg(a, i) != macro_arg(b, i)) return is_lt(macro_arg(a, i), macro_arg(b, i), use_hash); } return false; } lean_unreachable(); // LCOV_EXCL_LINE }
bool apply(expr const & a, expr const & b) { if (is_eqp(a, b)) return true; if (a.hash() != b.hash()) return false; if (a.kind() != b.kind()) return false; if (is_var(a)) return var_idx(a) == var_idx(b); if (m_cache.check(a, b)) return true; switch (a.kind()) { case expr_kind::Var: lean_unreachable(); // LCOV_EXCL_LINE case expr_kind::Constant: return const_name(a) == const_name(b) && compare(const_levels(a), const_levels(b), [](level const & l1, level const & l2) { return l1 == l2; }); case expr_kind::Meta: return mlocal_name(a) == mlocal_name(b) && apply(mlocal_type(a), mlocal_type(b)); case expr_kind::Local: return mlocal_name(a) == mlocal_name(b) && apply(mlocal_type(a), mlocal_type(b)) && (!CompareBinderInfo || local_pp_name(a) == local_pp_name(b)) && (!CompareBinderInfo || local_info(a) == local_info(b)); case expr_kind::App: check_system(); return apply(app_fn(a), app_fn(b)) && apply(app_arg(a), app_arg(b)); case expr_kind::Lambda: case expr_kind::Pi: check_system(); return apply(binding_domain(a), binding_domain(b)) && apply(binding_body(a), binding_body(b)) && (!CompareBinderInfo || binding_name(a) == binding_name(b)) && (!CompareBinderInfo || binding_info(a) == binding_info(b)); case expr_kind::Let: check_system(); return apply(let_type(a), let_type(b)) && apply(let_value(a), let_value(b)) && apply(let_body(a), let_body(b)) && (!CompareBinderInfo || let_name(a) == let_name(b)); case expr_kind::Sort: return sort_level(a) == sort_level(b); case expr_kind::Macro: check_system(); if (macro_def(a) != macro_def(b) || macro_num_args(a) != macro_num_args(b)) return false; for (unsigned i = 0; i < macro_num_args(a); i++) { if (!apply(macro_arg(a, i), macro_arg(b, i))) return false; } return true; } lean_unreachable(); // LCOV_EXCL_LINE }
bool expr_eq_fn::apply(expr const & a, expr const & b) { if (is_eqp(a, b)) return true; if (a.hash() != b.hash()) return false; if (a.kind() != b.kind()) return false; if (is_var(a)) return var_idx(a) == var_idx(b); if (m_counter >= LEAN_EQ_CACHE_THRESHOLD && is_shared(a) && is_shared(b)) { auto p = std::make_pair(a.raw(), b.raw()); if (!m_eq_visited) m_eq_visited.reset(new expr_cell_pair_set); if (m_eq_visited->find(p) != m_eq_visited->end()) return true; m_eq_visited->insert(p); } check_system("expression equality test"); switch (a.kind()) { case expr_kind::Var: lean_unreachable(); // LCOV_EXCL_LINE case expr_kind::Constant: return const_name(a) == const_name(b) && compare(const_levels(a), const_levels(b), [](level const & l1, level const & l2) { return l1 == l2; }); case expr_kind::Local: case expr_kind::Meta: return mlocal_name(a) == mlocal_name(b) && apply(mlocal_type(a), mlocal_type(b)); case expr_kind::App: m_counter++; return apply(app_fn(a), app_fn(b)) && apply(app_arg(a), app_arg(b)); case expr_kind::Lambda: case expr_kind::Pi: m_counter++; return apply(binding_domain(a), binding_domain(b)) && apply(binding_body(a), binding_body(b)) && (!m_compare_binder_info || binding_info(a) == binding_info(b)); case expr_kind::Sort: return sort_level(a) == sort_level(b); case expr_kind::Macro: m_counter++; if (macro_def(a) != macro_def(b) || macro_num_args(a) != macro_num_args(b)) return false; for (unsigned i = 0; i < macro_num_args(a); i++) { if (!apply(macro_arg(a, i), macro_arg(b, i))) return false; } return true; case expr_kind::Let: m_counter++; return apply(let_type(a), let_type(b)) && apply(let_value(a), let_value(b)) && apply(let_body(a), let_body(b)); } lean_unreachable(); // LCOV_EXCL_LINE }
bool is_lt_no_level_params(expr const & a, expr const & b) { if (is_eqp(a, b)) return false; unsigned wa = get_weight(a); unsigned wb = get_weight(b); if (wa < wb) return true; if (wa > wb) return false; if (a.kind() != b.kind()) return a.kind() < b.kind(); switch (a.kind()) { case expr_kind::Var: return var_idx(a) < var_idx(b); case expr_kind::Constant: if (const_name(a) != const_name(b)) return const_name(a) < const_name(b); else return is_lt_no_level_params(const_levels(a), const_levels(b)); case expr_kind::App: if (is_lt_no_level_params(app_fn(a), app_fn(b))) return true; else if (is_lt_no_level_params(app_fn(b), app_fn(a))) return false; else return is_lt_no_level_params(app_arg(a), app_arg(b)); case expr_kind::Lambda: case expr_kind::Pi: if (is_lt_no_level_params(binding_domain(a), binding_domain(b))) return true; else if (is_lt_no_level_params(binding_domain(b), binding_domain(a))) return false; else return is_lt_no_level_params(binding_body(a), binding_body(b)); case expr_kind::Sort: return is_lt_no_level_params(sort_level(a), sort_level(b)); case expr_kind::Local: case expr_kind::Meta: if (mlocal_name(a) != mlocal_name(b)) return mlocal_name(a) < mlocal_name(b); else return is_lt_no_level_params(mlocal_type(a), mlocal_type(b)); case expr_kind::Macro: if (macro_def(a) != macro_def(b)) return macro_def(a) < macro_def(b); if (macro_num_args(a) != macro_num_args(b)) return macro_num_args(a) < macro_num_args(b); for (unsigned i = 0; i < macro_num_args(a); i++) { if (is_lt_no_level_params(macro_arg(a, i), macro_arg(b, i))) return true; else if (is_lt_no_level_params(macro_arg(b, i), macro_arg(a, i))) return false; } return false; } lean_unreachable(); }
void get_structure_instance_info(expr const & e, name & struct_name, optional<expr> & source, buffer<name> & field_names, buffer<expr> & field_values) { lean_assert(is_structure_instance(e)); struct_name = static_cast<structure_instance_macro_cell const*>(macro_def(e).raw())->get_struct(); list<name> const & fns = static_cast<structure_instance_macro_cell const*>(macro_def(e).raw())->get_field_names(); to_buffer(fns, field_names); unsigned num_fields = field_names.size(); lean_assert(macro_num_args(e) == num_fields || macro_num_args(e) == num_fields+1); if (num_fields < macro_num_args(e)) source = macro_arg(e, num_fields); for (unsigned i = 0; i < num_fields; i++) field_values.push_back(macro_arg(e, i)); }
static bool contains_untrusted_macro(unsigned trust_lvl, expr const & e) { if (trust_lvl > LEAN_BELIEVER_TRUST_LEVEL) return false; return static_cast<bool>(find(e, [&](expr const & e, unsigned) { return is_macro(e) && macro_def(e).trust_level() >= trust_lvl; })); }
static bool contains_untrusted_macro(unsigned trust_lvl, expr const & e) { #if defined(LEAN_ALL_MACROS_HAVE_SMALL_TRUST_LVL) if (trust_lvl > LEAN_BELIEVER_TRUST_LEVEL) return false; #endif return static_cast<bool>(find(e, [&](expr const & e, unsigned) { return is_macro(e) && macro_def(e).trust_level() >= trust_lvl; })); }
static void varnish_start(struct varnish *v) { enum VCLI_status_e u; char *resp, *h, *p, *q; if (v->cli_fd < 0) varnish_launch(v); if (vtc_error) return; vtc_log(v->vl, 2, "Start"); u = varnish_ask_cli(v, "start", &resp); if (vtc_error) return; if (u != CLIS_OK) vtc_log(v->vl, 0, "CLI start command failed: %u %s", u, resp); wait_running(v); free(resp); u = varnish_ask_cli(v, "debug.xid 1000", &resp); if (vtc_error) return; if (u != CLIS_OK) vtc_log(v->vl, 0, "CLI debug.xid command failed: %u %s", u, resp); free(resp); u = varnish_ask_cli(v, "debug.listen_address", &resp); if (vtc_error) return; if (u != CLIS_OK) vtc_log(v->vl, 0, "CLI debug.listen_address command failed: %u %s", u, resp); h = resp; p = strchr(h, ' '); AN(p); *p++ = '\0'; q = strchr(p, '\n'); AN(q); *q = '\0'; vtc_log(v->vl, 2, "Listen on %s %s", h, p); macro_def(v->vl, v->name, "addr", "%s", h); macro_def(v->vl, v->name, "port", "%s", p); macro_def(v->vl, v->name, "sock", "%s %s", h, p); }
void destruct_structure_instance(expr const & e, expr & t, buffer<name> & field_names, buffer<expr> & field_values, buffer<expr> & using_exprs) { lean_assert(is_structure_instance(e)); t = macro_arg(e, 0); list<name> const & fns = static_cast<structure_instance_macro_cell const*>(macro_def(e).raw())->get_field_names(); unsigned num_fileds = length(fns); to_buffer(fns, field_names); for (unsigned i = 1; i < num_fileds+1; i++) field_values.push_back(macro_arg(e, i)); for (unsigned i = num_fileds+1; i < macro_num_args(e); i++) using_exprs.push_back(macro_arg(e, i)); }
static bool is_permutation(expr const & lhs, expr const & rhs, unsigned offset, buffer<optional<unsigned>> & p) { if (lhs.kind() != rhs.kind()) return false; switch (lhs.kind()) { case expr_kind::Constant: case expr_kind::Sort: case expr_kind::Meta: case expr_kind::Local: return lhs == rhs; case expr_kind::Var: if (var_idx(lhs) < offset) { return lhs == rhs; // locally bound variable } else if (var_idx(lhs) - offset < p.size()) { if (p[var_idx(lhs) - offset]) { return *(p[var_idx(lhs) - offset]) == var_idx(rhs); } else { p[var_idx(lhs) - offset] = var_idx(rhs); return true; } } else { return lhs == rhs; // free variable } case expr_kind::Lambda: case expr_kind::Pi: return is_permutation(binding_domain(lhs), binding_domain(rhs), offset, p) && is_permutation(binding_body(lhs), binding_body(rhs), offset+1, p); case expr_kind::App: return is_permutation(app_fn(lhs), app_fn(rhs), offset, p) && is_permutation(app_arg(lhs), app_arg(rhs), offset, p); case expr_kind::Macro: if (macro_def(lhs) != macro_def(rhs) || macro_num_args(lhs) != macro_num_args(rhs)) return false; for (unsigned i = 0; i < macro_num_args(lhs); i++) { if (!is_permutation(macro_arg(lhs, i), macro_arg(rhs, i), offset, p)) return false; } return true; } lean_unreachable(); }
virtual expr visit_macro(expr const & e) override { buffer<expr> new_args; for (unsigned i = 0; i < macro_num_args(e); i++) new_args.push_back(visit(macro_arg(e, i))); auto def = macro_def(e); expr r = update_macro(e, new_args.size(), new_args.data()); if (!m_trust_lvl || def.trust_level() >= *m_trust_lvl) { if (optional<expr> new_r = m_ctx.expand_macro(r)) { return visit(*new_r); } else { throw generic_exception(e, "failed to expand macro"); } } else { return r; } }
expr visit_macro(expr const & e) { buffer<expr> new_args; for (unsigned i = 0; i < macro_num_args(e); i++) new_args.push_back(visit(macro_arg(e, i))); auto def = macro_def(e); expr r = update_macro(e, new_args.size(), new_args.data()); if (def.trust_level() >= m_trust_lvl) { if (optional<expr> new_r = m_tc.expand_macro(r)) { return *new_r; } else { throw_generic_exception("failed to expand macro", e); } } else { return r; } }
options const & get_options_expr_options(expr const & e) { lean_assert(is_options_expr(e)); return static_cast<options_macro_cell const*>(macro_def(e).raw())->get_info(); }
int exec_file(const char *fn, const char *script, const char *tmpdir, char *logbuf, unsigned loglen) { unsigned old_err; char *cwd, *p; FILE *f; struct extmacro *m; signal(SIGPIPE, SIG_IGN); vtc_loginit(logbuf, loglen); vltop = vtc_logopen("top"); AN(vltop); init_macro(); init_sema(); /* Apply extmacro definitions */ VTAILQ_FOREACH(m, &extmacro_list, list) macro_def(vltop, NULL, m->name, m->val); /* Other macro definitions */ cwd = getcwd(NULL, PATH_MAX); macro_def(vltop, NULL, "pwd", cwd); macro_def(vltop, NULL, "topbuild", "%s/%s", cwd, TOP_BUILDDIR); macro_def(vltop, NULL, "bad_ip", "10.255.255.255"); /* Move into our tmpdir */ AZ(chdir(tmpdir)); macro_def(vltop, NULL, "tmpdir", tmpdir); /* Drop file to tell what was going on here */ f = fopen("INFO", "w"); AN(f); fprintf(f, "Test case: %s\n", fn); AZ(fclose(f)); vtc_stop = 0; vtc_desc = NULL; vtc_log(vltop, 1, "TEST %s starting", fn); p = strdup(script); AN(p); vtc_thread = pthread_self(); parse_string(p, cmds, NULL, vltop); old_err = vtc_error; vtc_stop = 1; vtc_log(vltop, 1, "RESETTING after %s", fn); reset_cmds(cmds); vtc_error = old_err; if (vtc_error) vtc_log(vltop, 1, "TEST %s FAILED", fn); else vtc_log(vltop, 1, "TEST %s completed", fn); free(vtc_desc); return (vtc_error); }
string_macro const & to_string_macro(expr const & e) { lean_assert(is_string_macro(e)); return *static_cast<string_macro const *>(macro_def(e).raw()); }
bool is_string_macro(expr const & e) { return is_macro(e) && dynamic_cast<string_macro const *>(macro_def(e).raw()) != nullptr; }
bool is_structure_instance(expr const & e) { return is_macro(e) && macro_def(e).get_name() == *g_structure_instance_name; }
name const & get_let_var_name(expr const & e) { lean_assert(is_let_macro(e)); return static_cast<let_macro_definition_cell const *>(macro_def(e).raw())->get_var_name(); }
decl_attributes const & get_nested_declaration_attributes(expr const & d) { lean_assert(is_nested_declaration(d)); return static_cast<nested_decl_macro_definition_cell const*>(macro_def(d).raw())->get_decl_attributes(); }
optional<name> const & get_nested_declaration_name(expr const & d) { lean_assert(is_nested_declaration(d)); return static_cast<nested_decl_macro_definition_cell const*>(macro_def(d).raw())->get_decl_name(); }
expr update_nested_declaration(expr const & e, expr const & new_d) { lean_assert(is_nested_declaration(e)); return mk_macro(macro_def(e), 1, &new_d); }
mpz const & prenum_value(expr const & e) { lean_assert(is_prenum(e)); return static_cast<prenum_macro_definition_cell const *>(macro_def(e).raw())->get_value(); }
bool is_prenum(expr const & e) { return is_macro(e) && dynamic_cast<prenum_macro_definition_cell const*>(macro_def(e).raw()) != nullptr; }
bool is_options_expr(expr const & e) { return is_macro(e) && macro_def(e).get_name() == *g_options_name; }
bool abstract_expr_manager::is_equal(expr const & a, expr const & b) { if (is_eqp(a, b)) return true; if (a.kind() != b.kind()) return false; if (is_var(a)) return var_idx(a) == var_idx(b); bool is_eq; switch (a.kind()) { case expr_kind::Var: lean_unreachable(); // LCOV_EXCL_LINE case expr_kind::Constant: case expr_kind::Sort: return a == b; case expr_kind::Meta: case expr_kind::Local: return mlocal_name(a) == mlocal_name(b) && is_equal(mlocal_type(a), mlocal_type(b)); case expr_kind::Lambda: case expr_kind::Pi: if (!is_equal(binding_domain(a), binding_domain(b))) return false; // see comment at abstract_expr_manager::hash m_locals.push_back(instantiate_rev(m_tctx.mk_tmp_local(binding_domain(a)), m_locals.size(), m_locals.data())); is_eq = is_equal(binding_body(a), binding_body(b)); m_locals.pop_back(); return is_eq; case expr_kind::Macro: if (macro_def(a) != macro_def(b) || macro_num_args(a) != macro_num_args(b)) return false; for (unsigned i = 0; i < macro_num_args(a); i++) { if (!is_equal(macro_arg(a, i), macro_arg(b, i))) return false; } return true; case expr_kind::App: buffer<expr> a_args, b_args; expr const & f_a = get_app_args(a, a_args); expr const & f_b = get_app_args(b, b_args); if (!is_equal(f_a, f_b)) return false; if (a_args.size() != b_args.size()) return false; unsigned prefix_sz = m_congr_lemma_manager.get_specialization_prefix_size(instantiate_rev(f_a, m_locals.size(), m_locals.data()), a_args.size()); for (unsigned i = 0; i < prefix_sz; i++) { if (!is_equal(a_args[i], b_args[i])) return false; } expr new_f_a = a; unsigned rest_sz = a_args.size() - prefix_sz; for (unsigned i = 0; i < rest_sz; i++) { new_f_a = app_fn(new_f_a); } new_f_a = instantiate_rev(new_f_a, m_locals.size(), m_locals.data()); optional<congr_lemma> congr = m_congr_lemma_manager.mk_congr(new_f_a, rest_sz); bool not_equal = false; if (!congr) { for (unsigned i = prefix_sz; i < a_args.size(); ++i) { if (!is_equal(a_args[i], b_args[i])) { not_equal = true; break; } } } else { lean_assert(length(congr->get_arg_kinds()) == rest_sz); unsigned i = prefix_sz; for_each(congr->get_arg_kinds(), [&](congr_arg_kind const & c_kind) { if (not_equal) return; if (c_kind != congr_arg_kind::Cast && !is_equal(a_args[i], b_args[i])) { not_equal = true; } i++; }); } return !not_equal; } lean_unreachable(); // LCOV_EXCL_LINE }
bool contains_untrusted_macro(unsigned trust_lvl, expr const & e) { return static_cast<bool>(find(e, [&](expr const & e, unsigned) { return is_macro(e) && macro_def(e).trust_level() >= trust_lvl; })); }
bool is_let_value(expr const & e) { return is_macro(e) && dynamic_cast<let_value_definition_cell const *>(macro_def(e).raw()); }
bool light_lt_manager::is_lt(expr const & a, expr const & b) { if (is_eqp(a, b)) return false; unsigned wa = get_weight(a); unsigned wb = get_weight(b); if (wa < wb) return true; if (wa > wb) return false; if (is_constant(get_app_fn(a))) { unsigned const * light_arg = m_lrs.find(const_name(get_app_fn(a))); if (light_arg) { buffer<expr> args; get_app_args(a, args); if (args.size() > *light_arg) return is_lt(args[*light_arg], b); } } if (is_constant(get_app_fn(b))) { unsigned const * light_arg = m_lrs.find(const_name(get_app_fn(b))); if (light_arg) { buffer<expr> args; get_app_args(b, args); if (args.size() > *light_arg) return !is_lt(args[*light_arg], a); } } if (a.kind() != b.kind()) return a.kind() < b.kind(); if (a == b) return false; switch (a.kind()) { case expr_kind::Var: return var_idx(a) < var_idx(b); case expr_kind::Constant: if (const_name(a) != const_name(b)) return const_name(a) < const_name(b); else return ::lean::is_lt(const_levels(a), const_levels(b), false); case expr_kind::App: if (app_fn(a) != app_fn(b)) return is_lt(app_fn(a), app_fn(b)); else return is_lt(app_arg(a), app_arg(b)); case expr_kind::Lambda: case expr_kind::Pi: if (binding_domain(a) != binding_domain(b)) return is_lt(binding_domain(a), binding_domain(b)); else return is_lt(binding_body(a), binding_body(b)); case expr_kind::Sort: return ::lean::is_lt(sort_level(a), sort_level(b), false); case expr_kind::Local: case expr_kind::Meta: if (mlocal_name(a) != mlocal_name(b)) return mlocal_name(a) < mlocal_name(b); else return is_lt(mlocal_type(a), mlocal_type(b)); case expr_kind::Macro: if (macro_def(a) != macro_def(b)) return macro_def(a) < macro_def(b); if (macro_num_args(a) != macro_num_args(b)) return macro_num_args(a) < macro_num_args(b); for (unsigned i = 0; i < macro_num_args(a); i++) { if (macro_arg(a, i) != macro_arg(b, i)) return is_lt(macro_arg(a, i), macro_arg(b, i)); } return false; } lean_unreachable(); // LCOV_EXCL_LINE }
bool is_nested_declaration(expr const & e) { return is_macro(e) && macro_def(e).get_name() == get_nested_decl_name(); }