feat(library): export environment in textual format

closes #577
This commit is contained in:
Leonardo de Moura 2015-05-04 18:05:00 -07:00
parent 741fca1e7b
commit 701b0ae66f
9 changed files with 377 additions and 14 deletions

View file

@ -70,6 +70,9 @@ public:
bool operator==(level const & l1, level const & l2);
inline bool operator!=(level const & l1, level const & l2) { return !operator==(l1, l2); }
struct level_hash { unsigned operator()(level const & n) const { return n.hash(); } };
struct level_eq { bool operator()(level const & n1, level const & n2) const { return n1 == n2; } };
SPECIALIZE_OPTIONAL_FOR_SMART_PTR(level)
inline optional<level> none_level() { return optional<level>(); }

View file

@ -12,6 +12,7 @@ add_library(library deep_copy.cpp expr_lt.cpp io_state.cpp occurs.cpp
metavar_closure.cpp reducible.cpp init_module.cpp
generic_exception.cpp fingerprint.cpp flycheck.cpp hott_kernel.cpp
local_context.cpp choice_iterator.cpp pp_options.cpp unfold_macros.cpp
app_builder.cpp projection.cpp abbreviation.cpp equivalence_manager.cpp)
app_builder.cpp projection.cpp abbreviation.cpp equivalence_manager.cpp
export.cpp)
target_link_libraries(library ${LEAN_LIBS})

287
src/library/export.cpp Normal file
View file

@ -0,0 +1,287 @@
/*
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include <unordered_map>
#include "kernel/expr_maps.h"
#include "kernel/inductive/inductive.h"
#include "library/max_sharing.h"
#include "library/module.h"
#include "library/unfold_macros.h"
namespace lean {
template<typename T>
using level_map = typename std::unordered_map<level, T, level_hash, level_eq>;
template<typename T>
using name_hmap = typename std::unordered_map<name, T, name_hash, name_eq>;
class exporter {
std::ostream & m_out;
environment m_env;
max_sharing_fn m_max_sharing;
name_hmap<unsigned> m_name2idx;
level_map<unsigned> m_level2idx;
expr_bi_struct_map<unsigned> m_expr2idx;
unsigned export_name(name const & n) {
auto it = m_name2idx.find(n);
if (it != m_name2idx.end())
return it->second;
unsigned i;
if (n.is_anonymous()) {
i = m_name2idx.size();
m_out << i << " n\n";
} else if (n.is_string()) {
unsigned p = export_name(n.get_prefix());
i = m_name2idx.size();
m_out << i << " s " << p << " " << n.get_string() << "\n";
} else {
unsigned p = export_name(n.get_prefix());
i = m_name2idx.size();
m_out << i << " i " << p << " " << n.get_numeral() << "\n";
}
m_name2idx.insert(mk_pair(n, i));
return i;
}
unsigned export_level(level const & l) {
auto it = m_level2idx.find(l);
if (it != m_level2idx.end())
return it->second;
unsigned i = 0;
unsigned l1, l2, n;
switch (l.kind()) {
case level_kind::Zero:
i = m_level2idx.size();
m_out << i << " UZ\n";
break;
case level_kind::Succ:
l1 = export_level(succ_of(l));
i = m_level2idx.size();
m_out << i << " US " << l1 << "\n";
break;
case level_kind::Max:
l1 = export_level(max_lhs(l));
l2 = export_level(max_rhs(l));
i = m_level2idx.size();
m_out << i << " UM " << l1 << " " << l2 << "\n";
break;
case level_kind::IMax:
l1 = export_level(imax_lhs(l));
l2 = export_level(imax_rhs(l));
i = m_level2idx.size();
m_out << i << " UIM " << l1 << " " << l2 << "\n";
break;
case level_kind::Param:
n = export_name(param_id(l));
i = m_level2idx.size();
m_out << i << " UP " << n << "\n";
break;
case level_kind::Global:
n = export_name(global_id(l));
i = m_level2idx.size();
m_out << i << " UG " << n << "\n";
break;
case level_kind::Meta:
throw exception("invald 'export', universe meta-variables cannot be exported");
}
m_level2idx.insert(mk_pair(l, i));
return i;
}
void display_binder_info(binder_info const & bi) {
if (bi.is_implicit())
m_out << "I";
else if (bi.is_strict_implicit())
m_out << "S";
else if (bi.is_inst_implicit())
m_out << "C";
else
m_out << "D";
}
unsigned export_binding(expr const & e, char const * k) {
unsigned n = export_name(binding_name(e));
unsigned e1 = export_expr(binding_domain(e));
unsigned e2 = export_expr(binding_body(e));
unsigned i = m_expr2idx.size();
m_out << i << " " << k << " ";
display_binder_info(binding_info(e));
m_out << " " << n << " " << e1 << " " << e2 << "\n";
return i;
}
unsigned export_const(expr const & e) {
buffer<unsigned> ls;
unsigned n = export_name(const_name(e));
for (level const & l : const_levels(e))
ls.push_back(export_level(l));
unsigned i = m_expr2idx.size();
m_out << i << " C " << n;
for (unsigned l : ls)
m_out << " " << l;
m_out << "\n";
return i;
}
unsigned export_expr(expr const & e) {
auto it = m_expr2idx.find(e);
if (it != m_expr2idx.end())
return it->second;
unsigned i = 0;
unsigned l, e1, e2;
switch (e.kind()) {
case expr_kind::Var:
i = m_expr2idx.size();
m_out << i << " V " << var_idx(e) << "\n";
break;
case expr_kind::Sort:
l = export_level(sort_level(e));
i = m_expr2idx.size();
m_out << i << " S " << l << "\n";
break;
case expr_kind::Constant:
i = export_const(e);
break;
case expr_kind::App:
e1 = export_expr(app_fn(e));
e2 = export_expr(app_arg(e));
i = m_expr2idx.size();
m_out << i << " A " << e1 << " " << e2 << "\n";
break;
case expr_kind::Lambda:
i = export_binding(e, "L");
break;
case expr_kind::Pi:
i = export_binding(e, "P");
break;
case expr_kind::Meta:
throw exception("invald 'export', meta-variables cannot be exported");
case expr_kind::Local:
throw exception("invald 'export', local constants cannot be exported");
case expr_kind::Macro:
throw exception("invald 'export', macros cannot be exported");
}
m_expr2idx.insert(mk_pair(e, i));
return i;
}
unsigned export_root_expr(expr const & e) {
return export_expr(m_max_sharing(unfold_all_macros(m_env, e)));
}
void export_definition(declaration const & d) {
unsigned n = export_name(d.get_name());
buffer<unsigned> ps;
for (name const & p : d.get_univ_params())
ps.push_back(export_name(p));
unsigned t = export_root_expr(d.get_type());
unsigned v = export_root_expr(d.get_value());
m_out << "DEF " << n;
for (unsigned p : ps)
m_out << " " << p;
m_out << " | " << t << " " << v << "\n";
}
void export_axiom(declaration const & d) {
unsigned n = export_name(d.get_name());
buffer<unsigned> ps;
for (name const & p : d.get_univ_params())
ps.push_back(export_name(p));
unsigned t = export_root_expr(d.get_type());
m_out << "AX " << n;
for (unsigned p : ps)
m_out << " " << p;
m_out << " | " << t << "\n";
}
void export_inductive(name const & n) {
std::tuple<level_param_names, unsigned, list<inductive::inductive_decl>> decls =
*inductive::is_inductive_decl(m_env, n);
for (name const & p : std::get<0>(decls))
export_name(p);
for (inductive::inductive_decl const & d : std::get<2>(decls)) {
export_name(inductive::inductive_decl_name(d));
export_expr(inductive::inductive_decl_type(d));
for (inductive::intro_rule const & c : inductive::inductive_decl_intros(d)) {
export_name(inductive::intro_rule_name(c));
export_expr(inductive::intro_rule_type(c));
}
}
m_out << "BIND " << std::get<1>(decls) << " " << length(std::get<2>(decls));
for (name const & p : std::get<0>(decls))
m_out << " " << export_name(p);
m_out << "\n";
for (inductive::inductive_decl const & d : std::get<2>(decls)) {
m_out << "IND " << export_name(inductive::inductive_decl_name(d)) << " "
<< export_expr(inductive::inductive_decl_type(d)) << "\n";
for (inductive::intro_rule const & c : inductive::inductive_decl_intros(d)) {
m_out << "INTRO " << export_name(inductive::intro_rule_name(c)) << " "
<< export_expr(inductive::intro_rule_type(c)) << "\n";
}
}
m_out << "EIND\n";
}
void export_declaration(name const & n) {
if (inductive::is_inductive_decl(m_env, n)) {
export_inductive(n);
} else {
declaration const & d = m_env.get(n);
if (d.is_definition())
export_definition(d);
else
export_axiom(d);
}
}
void export_declarations() {
buffer<name> ns;
to_buffer(get_curr_module_decl_names(m_env), ns);
std::reverse(ns.begin(), ns.end());
for (name const & n : ns)
export_declaration(n);
}
void export_direct_imports() {
buffer<module_name> imports;
to_buffer(get_curr_module_imports(m_env), imports);
std::reverse(imports.begin(), imports.end());
for (module_name const & m : imports) {
unsigned n = export_name(m.get_name());
if (m.is_relative()) {
m_out << "RI " << *m.get_k() << " " << n << "\n";
} else {
m_out << "DI " << n << "\n";
}
}
}
void export_global_universes() {
buffer<name> ns;
to_buffer(get_curr_module_univ_names(m_env), ns);
std::reverse(ns.begin(), ns.end());
for (name const & u : ns) {
unsigned n = export_name(u);
m_out << "UNI " << n << "\n";
}
}
public:
exporter(std::ostream & out, environment const & env):m_out(out), m_env(env) {}
void operator()() {
export_direct_imports();
export_global_universes();
export_declarations();
}
};
void export_module_as_lowtext(std::ostream & out, environment const & env) {
exporter(out, env)();
}
}

11
src/library/export.h Normal file
View file

@ -0,0 +1,11 @@
/*
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include "kernel/environment.h"
namespace lean {
void export_module_as_lowtext(std::ostream & out, environment const & env);
}

View file

@ -1,5 +1,5 @@
/*
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Copyright (c) 2014-2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
@ -42,6 +42,8 @@ typedef pair<std::string, std::function<void(serializer &)>> writer;
struct module_ext : public environment_extension {
list<module_name> m_direct_imports;
list<writer> m_writers;
list<name> m_module_univs;
list<name> m_module_decls;
name_set m_module_defs;
// auxiliary information for detecting whether
// directly imported files have changed
@ -68,6 +70,18 @@ list<module_name> get_direct_imports(environment const & env) {
return get_extension(env).m_direct_imports;
}
list<name> const & get_curr_module_decl_names(environment const & env) {
return get_extension(env).m_module_decls;
}
list<name> const & get_curr_module_univ_names(environment const & env) {
return get_extension(env).m_module_univs;
}
list<module_name> const & get_curr_module_imports(environment const & env) {
return get_extension(env).m_direct_imports;
}
bool direct_imports_have_changed(environment const & env) {
module_ext const & ext = get_extension(env);
std::string const & base = ext.m_base;
@ -176,16 +190,22 @@ environment add(environment const & env, std::string const & k, std::function<vo
environment add_universe(environment const & env, name const & l) {
environment new_env = env.add_universe(l);
module_ext ext = get_extension(env);
ext.m_module_univs = cons(l, ext.m_module_univs);
new_env = update(new_env, ext);
return add(new_env, *g_glvl_key, [=](serializer & s) { s << l; });
}
environment update_module_defs(environment const & env, declaration const & d) {
if (d.is_definition() && !d.is_theorem()) {
module_ext ext = get_extension(env);
ext.m_module_decls = cons(d.get_name(), ext.m_module_decls);
ext.m_module_defs.insert(d.get_name());
return update(env, ext);
} else {
return env;
module_ext ext = get_extension(env);
ext.m_module_decls = cons(d.get_name(), ext.m_module_decls);
return update(env, ext);
}
}
@ -238,6 +258,9 @@ environment add_inductive(environment env,
unsigned num_params,
list<inductive::inductive_decl> const & decls) {
environment new_env = inductive::add_inductive(env, level_params, num_params, decls);
module_ext ext = get_extension(env);
ext.m_module_decls = cons(inductive::inductive_decl_name(head(decls)), ext.m_module_decls);
new_env = update(new_env, ext);
return add(new_env, *g_inductive, [=](serializer & s) {
s << inductive_decls(level_params, num_params, decls);
});

View file

@ -31,6 +31,13 @@ public:
optional<unsigned> const & get_k() const { return m_relative; }
};
/** \brief Return the list of declarations performed in the current module */
list<name> const & get_curr_module_decl_names(environment const & env);
/** \brief Return the list of universes declared in the current module */
list<name> const & get_curr_module_univ_names(environment const & env);
/** \brief Return the list of modules directly imported by the current module */
list<module_name> const & get_curr_module_imports(environment const & env);
/** \brief Return an environment based on \c env, where all modules in \c modules are imported.
Modules included directly or indirectly by them are also imported.
The environment \c env is usually an empty environment.

View file

@ -104,8 +104,8 @@ class unfold_untrusted_macros_fn {
}
public:
unfold_untrusted_macros_fn(environment const & env):
m_tc(env), m_trust_lvl(env.trust_lvl()) {}
unfold_untrusted_macros_fn(environment const & env, unsigned lvl):
m_tc(env), m_trust_lvl(lvl) {}
expr operator()(expr const & e) { return visit(e); }
};
@ -116,28 +116,36 @@ bool contains_untrusted_macro(unsigned trust_lvl, expr const & e) {
}));
}
expr unfold_untrusted_macros(environment const & env, expr const & e) {
if (contains_untrusted_macro(env.trust_lvl(), e)) {
return unfold_untrusted_macros_fn(env)(e);
expr unfold_untrusted_macros(environment const & env, expr const & e, unsigned trust_lvl) {
if (contains_untrusted_macro(trust_lvl, e)) {
return unfold_untrusted_macros_fn(env, trust_lvl)(e);
} else {
return e;
}
}
expr unfold_untrusted_macros(environment const & env, expr const & e) {
return unfold_untrusted_macros(env, e, env.trust_lvl());
}
expr unfold_all_macros(environment const & env, expr const & e) {
return unfold_untrusted_macros(env, e, 0);
}
bool contains_untrusted_macro(unsigned trust_lvl, declaration const & d) {
if (contains_untrusted_macro(trust_lvl, d.get_type()))
return true;
return (d.is_definition() || d.is_theorem()) && contains_untrusted_macro(trust_lvl, d.get_value());
}
declaration unfold_untrusted_macros(environment const & env, declaration const & d) {
if (contains_untrusted_macro(env.trust_lvl(), d)) {
expr new_t = unfold_untrusted_macros(env, d.get_type());
declaration unfold_untrusted_macros(environment const & env, declaration const & d, unsigned trust_lvl) {
if (contains_untrusted_macro(trust_lvl, d)) {
expr new_t = unfold_untrusted_macros(env, d.get_type(), trust_lvl);
if (d.is_theorem()) {
expr new_v = unfold_untrusted_macros(env, d.get_value());
expr new_v = unfold_untrusted_macros(env, d.get_value(), trust_lvl);
return mk_theorem(d.get_name(), d.get_univ_params(), new_t, new_v, d.get_module_idx());
} else if (d.is_definition()) {
expr new_v = unfold_untrusted_macros(env, d.get_value());
expr new_v = unfold_untrusted_macros(env, d.get_value(), trust_lvl);
return mk_definition(d.get_name(), d.get_univ_params(), new_t, new_v,
d.is_opaque(), d.get_weight(), d.get_module_idx(), d.use_conv_opt());
} else if (d.is_axiom()) {
@ -151,4 +159,12 @@ declaration unfold_untrusted_macros(environment const & env, declaration const &
return d;
}
}
declaration unfold_untrusted_macros(environment const & env, declaration const & d) {
return unfold_untrusted_macros(env, d, env.trust_lvl());
}
declaration unfold_all_macros(environment const & env, declaration const & d) {
return unfold_untrusted_macros(env, d, 0);
}
}

View file

@ -18,4 +18,8 @@ namespace lean {
expr unfold_untrusted_macros(environment const & env, expr const & e);
declaration unfold_untrusted_macros(environment const & env, declaration const & d);
expr unfold_all_macros(environment const & env, expr const & e);
declaration unfold_all_macros(environment const & env, declaration const & d);
}

View file

@ -32,6 +32,7 @@ Author: Leonardo de Moura
#include "library/io_state_stream.h"
#include "library/definition_cache.h"
#include "library/declaration_index.h"
#include "library/export.h"
#include "library/error_handling/error_handling.h"
#include "frontends/lean/parser.h"
#include "frontends/lean/pp.h"
@ -125,6 +126,7 @@ static void display_help(std::ostream & out) {
std::cout << " --line=value line number for query\n";
std::cout << " --col=value column number for query\n";
std::cout << " --goal display goal at close to given position\n";
std::cout << " --export=file -E export final environment as textual low-level file\n";
}
static char const * get_file_extension(char const * fname) {
@ -152,6 +154,7 @@ static struct option g_long_options[] = {
{"luahook", required_argument, 0, 'k'},
{"githash", no_argument, 0, 'g'},
{"output", required_argument, 0, 'o'},
{"export", required_argument, 0, 'E'},
{"memory", required_argument, 0, 'M'},
{"trust", required_argument, 0, 't'},
{"discard", no_argument, 0, 'r'},
@ -175,7 +178,7 @@ static struct option g_long_options[] = {
{0, 0, 0, 0}
};
#define OPT_STR "PHRXFdD:qrlupgvhk:012t:012o:c:i:L:012O:012G"
#define OPT_STR "PHRXFdD:qrlupgvhk:012t:012o:E:c:i:L:012O:012G"
#if defined(LEAN_TRACK_MEMORY)
#define OPT_STR2 OPT_STR "M:012"
@ -336,6 +339,7 @@ int main(int argc, char ** argv) {
std::string index_name;
optional<unsigned> line;
optional<unsigned> column;
optional<std::string> export_txt;
bool show_goal = false;
input_kind default_k = input_kind::Unspecified;
while (true) {
@ -435,6 +439,9 @@ int main(int argc, char ** argv) {
case 'G':
show_goal = true;
break;
case 'E':
export_txt = std::string(optarg);
break;
default:
std::cerr << "Unknown command line option\n";
display_help(std::cerr);
@ -574,6 +581,10 @@ int main(int argc, char ** argv) {
std::ofstream out(output, std::ofstream::binary);
export_module(out, env);
}
if (export_txt) {
std::ofstream out(*export_txt);
export_module_as_lowtext(out, env);
}
return ok ? 0 : 1;
} catch (lean::throwable & ex) {
lean::display_error(diagnostic(env, ios), nullptr, ex);