feat(kernel/environment): track which modules were already imported

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-11-17 18:11:44 -08:00
parent 5f651d46e6
commit 69be5f6c94
21 changed files with 130 additions and 20 deletions

View file

@ -9,6 +9,7 @@ Author: Leonardo de Moura
#include "kernel/environment.h" #include "kernel/environment.h"
#include "kernel/formatter.h" #include "kernel/formatter.h"
#include "library/type_inferer.h" #include "library/type_inferer.h"
#include "frontends/lean/frontend.h"
#include "bindings/lua/util.h" #include "bindings/lua/util.h"
#include "bindings/lua/name.h" #include "bindings/lua/name.h"
#include "bindings/lua/options.h" #include "bindings/lua/options.h"
@ -40,10 +41,15 @@ rw_environment::rw_environment(lua_State * L):
read_write_environment(get_global_environment(L)) { read_write_environment(get_global_environment(L)) {
} }
static int mk_environment(lua_State * L) { static int mk_empty_environment(lua_State * L) {
return push_environment(L, environment()); return push_environment(L, environment());
} }
static int mk_environment(lua_State * L) {
frontend f;
return push_environment(L, f.get_environment());
}
static int environment_has_parent(lua_State * L) { static int environment_has_parent(lua_State * L) {
ro_environment env(L, 1); ro_environment env(L, 1);
lua_pushboolean(L, env->has_parent()); lua_pushboolean(L, env->has_parent());
@ -263,9 +269,10 @@ void open_environment(lua_State * L) {
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
setfuncs(L, environment_m, 0); setfuncs(L, environment_m, 0);
SET_GLOBAL_FUN(mk_environment, "environment"); SET_GLOBAL_FUN(mk_empty_environment, "empty_environment");
SET_GLOBAL_FUN(environment_pred, "is_environment"); SET_GLOBAL_FUN(mk_environment, "environment");
SET_GLOBAL_FUN(get_environment, "get_environment"); SET_GLOBAL_FUN(environment_pred, "is_environment");
SET_GLOBAL_FUN(get_environment, "get_env"); SET_GLOBAL_FUN(get_environment, "get_environment");
SET_GLOBAL_FUN(get_environment, "get_env");
} }
} }

View file

@ -95,6 +95,10 @@ void set_global_formatter(lua_State * L, formatter const & fmt) {
} }
} }
int get_formatter(lua_State * L) {
return push_formatter(L, get_global_formatter(L));
}
void open_formatter(lua_State * L) { void open_formatter(lua_State * L) {
luaL_newmetatable(L, formatter_mt); luaL_newmetatable(L, formatter_mt);
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
@ -102,5 +106,6 @@ void open_formatter(lua_State * L) {
setfuncs(L, formatter_m, 0); setfuncs(L, formatter_m, 0);
SET_GLOBAL_FUN(formatter_pred, "is_formatter"); SET_GLOBAL_FUN(formatter_pred, "is_formatter");
SET_GLOBAL_FUN(get_formatter, "get_formatter");
} }
} }

View file

@ -366,6 +366,8 @@ frontend::frontend() {
m_state.set_formatter(mk_pp_formatter(*this)); m_state.set_formatter(mk_pp_formatter(*this));
} }
frontend::frontend(environment const & env, state const & s):m_env(env), m_state(s) { frontend::frontend(environment const & env, state const & s):m_env(env), m_state(s) {
import_all(m_env);
init_builtin_notation(*this);
} }
void frontend::add_infix(name const & opn, unsigned p, expr const & d) { void frontend::add_infix(name const & opn, unsigned p, expr const & d) {

View file

@ -20,6 +20,8 @@ void add_alias(frontend & f, name const & n, name const & m) {
\brief Initialize builtin notation. \brief Initialize builtin notation.
*/ */
void init_builtin_notation(frontend & f) { void init_builtin_notation(frontend & f) {
if (!f.get_environment().mark_builtin_imported("lean_notation"))
return;
f.add_infix("=", 50, mk_homo_eq_fn()); f.add_infix("=", 50, mk_homo_eq_fn());
f.mark_implicit_arguments(mk_homo_eq_fn(), {true, false, false}); f.mark_implicit_arguments(mk_homo_eq_fn(), {true, false, false});
f.mark_implicit_arguments(mk_if_fn(), {true, false, false, false}); f.mark_implicit_arguments(mk_if_fn(), {true, false, false, false});

View file

@ -1391,10 +1391,14 @@ class parser::imp {
void parse_import() { void parse_import() {
next(); next();
std::string fname = check_string_next("invalid import command, string (i.e., file name) expected"); std::string fname = check_string_next("invalid import command, string (i.e., file name) expected");
std::ifstream in(fname); std::ifstream in(fname);
if (!in.is_open()) if (!in.is_open())
throw parser_error(sstream() << "invalid import command, failed to open file '" << fname << "'", m_last_cmd_pos); throw parser_error(sstream() << "invalid import command, failed to open file '" << fname << "'", m_last_cmd_pos);
if (!m_frontend.get_environment().mark_imported(fname.c_str())) {
diagnostic(m_frontend) << "Module '" << fname << "' has already been imported" << endl;
return;
}
try { try {
if (m_verbose) if (m_verbose)
regular(m_frontend) << "Importing file '" << fname << "'" << endl; regular(m_frontend) << "Importing file '" << fname << "'" << endl;

View file

@ -168,6 +168,8 @@ MK_CONSTANT(eta_fn, name("Eta"));
MK_CONSTANT(imp_antisym_fn, name("ImpAntisym")); MK_CONSTANT(imp_antisym_fn, name("ImpAntisym"));
void import_basic(environment & env) { void import_basic(environment & env) {
if (!env.mark_builtin_imported("basic"))
return;
env.add_uvar(uvar_name(m_lvl), level() + LEAN_DEFAULT_LEVEL_SEPARATION); env.add_uvar(uvar_name(m_lvl), level() + LEAN_DEFAULT_LEVEL_SEPARATION);
env.add_uvar(uvar_name(u_lvl), m_lvl + LEAN_DEFAULT_LEVEL_SEPARATION); env.add_uvar(uvar_name(u_lvl), m_lvl + LEAN_DEFAULT_LEVEL_SEPARATION);

View file

@ -4,10 +4,12 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura Author: Leonardo de Moura
*/ */
#include <cstdlib>
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
#include <atomic> #include <atomic>
#include <tuple> #include <tuple>
#include <set>
#include <unordered_map> #include <unordered_map>
#include <mutex> #include <mutex>
#include "util/safe_arith.h" #include "util/safe_arith.h"
@ -19,7 +21,7 @@ Author: Leonardo de Moura
#include "kernel/normalizer.h" #include "kernel/normalizer.h"
namespace lean { namespace lean {
static name g_builtin_module("builtin_module");
class extension_factory { class extension_factory {
std::vector<environment::mk_extension> m_makers; std::vector<environment::mk_extension> m_makers;
std::mutex m_makers_mutex; std::mutex m_makers_mutex;
@ -67,6 +69,7 @@ struct environment::imp {
std::vector<object> m_objects; std::vector<object> m_objects;
object_dictionary m_object_dictionary; object_dictionary m_object_dictionary;
std::unique_ptr<type_checker> m_type_checker; std::unique_ptr<type_checker> m_type_checker;
std::set<name> m_imported_modules; // set of imported files and builtin modules
std::vector<std::unique_ptr<extension>> m_extensions; std::vector<std::unique_ptr<extension>> m_extensions;
friend class extension; friend class extension;
@ -402,6 +405,34 @@ struct environment::imp {
} }
} }
bool already_imported(name const & n) const {
if (m_imported_modules.find(n) != m_imported_modules.end())
return true;
else if (has_parent())
return m_parent->already_imported(n);
else
return false;
}
bool mark_imported_core(name n, environment const & env) {
if (already_imported(n)) {
return false;
} else if (has_children()) {
throw read_only_environment_exception(env);
} else {
m_imported_modules.insert(n);
return true;
}
}
bool mark_imported(char const * fname, environment const & env) {
return mark_imported_core(name(realpath(fname, nullptr)), env);
}
bool mark_builtin_imported(char const * id, environment const & env) {
return mark_imported_core(name(g_builtin_module, id), env);
}
imp(): imp():
m_num_children(0) { m_num_children(0) {
init_uvars(); init_uvars();
@ -533,6 +564,14 @@ void environment::display(std::ostream & out) const {
m_ptr->display(out, *this); m_ptr->display(out, *this);
} }
bool environment::mark_imported(char const * fname) {
return m_ptr->mark_imported(fname, *this);
}
bool environment::mark_builtin_imported(char const * id) {
return m_ptr->mark_builtin_imported(id, *this);
}
environment::extension const & environment::get_extension_core(unsigned extid) const { environment::extension const & environment::get_extension_core(unsigned extid) const {
return m_ptr->get_extension_core(extid); return m_ptr->get_extension_core(extid);
} }

View file

@ -26,8 +26,13 @@ private:
friend class read_only_environment; friend class read_only_environment;
friend class read_write_environment; friend class read_write_environment;
public: public:
typedef std::weak_ptr<imp> weak_ref;
environment(); environment();
~environment(); ~environment();
environment(weak_ref const & r);
weak_ref to_weak_ref() const { return weak_ref(m_ptr); }
friend bool is_eqp(environment const & env1, environment const & env2) { return env1.m_ptr.get() == env2.m_ptr.get(); } friend bool is_eqp(environment const & env1, environment const & env2) { return env1.m_ptr.get() == env2.m_ptr.get(); }
// ======================================= // =======================================
@ -281,9 +286,15 @@ public:
return static_cast<Ext&>(ext); return static_cast<Ext&>(ext);
} }
public: /**
typedef std::weak_ptr<imp> weak_ref; \brief Return true iff the given file was not already marked as imported.
weak_ref to_weak_ref() const { return weak_ref(m_ptr); } It will also mark the file as imported.
environment(weak_ref const & r); */
bool mark_imported(char const * fname);
/**
\brief Return true iff the given builtin id was not already marked as imported.
It will also mark the id as imported.
*/
bool mark_builtin_imported(char const * id);
}; };
} }

View file

@ -145,7 +145,7 @@ MK_CONSTANT(nat_sub_fn, name({"Nat", "sub"}));
MK_CONSTANT(nat_neg_fn, name({"Nat", "neg"})); MK_CONSTANT(nat_neg_fn, name({"Nat", "neg"}));
void import_int(environment & env) { void import_int(environment & env) {
if (env.find_object(to_value(Int).get_name())) if (!env.mark_builtin_imported("int"))
return; return;
import_nat(env); import_nat(env);
expr i_i = Int >> Int; expr i_i = Int >> Int;

View file

@ -109,7 +109,7 @@ MK_CONSTANT(nat_gt_fn, name({"Nat", "gt"}));
MK_CONSTANT(nat_id_fn, name({"Nat", "id"})); MK_CONSTANT(nat_id_fn, name({"Nat", "id"}));
void import_nat(environment & env) { void import_nat(environment & env) {
if (env.find_object(to_value(Nat).get_name())) if (!env.mark_builtin_imported("nat"))
return; return;
expr nn_b = Nat >> (Nat >> Bool); expr nn_b = Nat >> (Nat >> Bool);
expr x = Const("x"); expr x = Const("x");

View file

@ -133,7 +133,7 @@ MK_CONSTANT(real_lt_fn, name({"Real", "lt"}));
MK_CONSTANT(real_gt_fn, name({"Real", "gt"})); MK_CONSTANT(real_gt_fn, name({"Real", "gt"}));
void import_real(environment & env) { void import_real(environment & env) {
if (env.find_object(to_value(Real).get_name())) if (!env.mark_builtin_imported("real"))
return; return;
expr rr_b = Real >> (Real >> Bool); expr rr_b = Real >> (Real >> Bool);
expr rr_r = Real >> (Real >> Real); expr rr_r = Real >> (Real >> Real);
@ -172,7 +172,7 @@ MK_BUILTIN(int_to_real_fn, int_to_real_value);
MK_CONSTANT(nat_to_real_fn, name("nat_to_real")); MK_CONSTANT(nat_to_real_fn, name("nat_to_real"));
void import_int_to_real_coercions(environment & env) { void import_int_to_real_coercions(environment & env) {
if (env.find_object(to_value(mk_int_to_real_fn()).get_name())) if (!env.mark_builtin_imported("real_coercions"))
return; return;
import_int(env); import_int(env);
import_real(env); import_real(env);

View file

@ -29,7 +29,7 @@ MK_CONSTANT(sech_fn, name("sech"));
MK_CONSTANT(csch_fn, name("csch")); MK_CONSTANT(csch_fn, name("csch"));
void import_special_fn(environment & env) { void import_special_fn(environment & env) {
if (env.find_object(const_name(mk_exp_fn()))) if (!env.mark_builtin_imported("special_fn"))
return; return;
import_real(env); import_real(env);

View file

@ -47,6 +47,8 @@ MK_CONSTANT(range_inj_fn, name("range_inj"));
#endif #endif
void import_basic_thms(environment & env) { void import_basic_thms(environment & env) {
if (!env.mark_builtin_imported("basic_thms"))
return;
expr A = Const("A"); expr A = Const("A");
expr a = Const("a"); expr a = Const("a");
expr b = Const("b"); expr b = Const("b");

View file

@ -105,7 +105,7 @@ MK_CONSTANT(dom_inj_fn, name("DomInj"));
MK_CONSTANT(ran_inj_fn, name("RanInj")); MK_CONSTANT(ran_inj_fn, name("RanInj"));
void import_cast(environment & env) { void import_cast(environment & env) {
if (env.find_object(to_value(mk_Cast_fn()).get_name())) if (!env.mark_builtin_imported("cast"))
return; return;
expr x = Const("x"); expr x = Const("x");
expr A = Const("A"); expr A = Const("A");

14
tests/lean/mod1.lean Normal file
View file

@ -0,0 +1,14 @@
Import "simple.lean"
Import "simple.lean"
(**
local env = environment() -- create new environment
parse_lean_cmds([[
Import "simple.lean"
Import "simple.lean"
Check x + y
Variable z : Int
Check z
]], env)
-- Remark: z is not defined in the main environment
**)
Check z

View file

@ -0,0 +1,12 @@
Set: pp::colors
Set: pp::unicode
Importing file 'simple.lean'
Assumed: x
Assumed: y
Importing file 'simple.lean'
Assumed: x
Assumed: y
x + y :
Assumed: z
z :
Error (line: 14, pos: 6) unknown identifier 'z'

2
tests/lean/simple.lean Normal file
View file

@ -0,0 +1,2 @@
Variable x : Int
Variable y : Int

View file

@ -0,0 +1,4 @@
Set: pp::colors
Set: pp::unicode
Assumed: x
Assumed: y

View file

@ -1,7 +1,7 @@
e = environment() e = environment()
assert(is_environment(e)) assert(is_environment(e))
e:add_uvar("M") e:add_uvar("M1")
print(e:get_uvar("M")) print(e:get_uvar("M1"))
e:add_var("N", Type()) e:add_var("N", Type())
N, M = Consts("N M") N, M = Consts("N M")
e:add_var("a", N) e:add_var("a", N)

View file

@ -2,7 +2,9 @@ env = environment()
env:add_var("N", Type()) env:add_var("N", Type())
env:add_var("x", Const("N")) env:add_var("x", Const("N"))
for v in env:objects() do for v in env:objects() do
print(v:get_name()) if v:has_name() then
print(v:get_name())
end
end end
assert(not env:find_object("N"):is_null()) assert(not env:find_object("N"):is_null())
assert(env:find_object("Z"):is_null()) assert(env:find_object("Z"):is_null())

2
tests/lua/fmt1.lua Normal file
View file

@ -0,0 +1,2 @@
fmt = get_formatter()
print(fmt(Const("a"), options()))