feat(library/module): relative module path
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
8768197c24
commit
4b030c5d5f
7 changed files with 115 additions and 39 deletions
|
@ -1,5 +1,6 @@
|
||||||
TOP := $(dir $(lastword $(MAKEFILE_LIST)))
|
TOP := $(dir $(lastword $(MAKEFILE_LIST)))
|
||||||
LEAN_FILES = $(shell find . -type f -name '*.lean')
|
DIR = $(shell pwd)
|
||||||
|
LEAN_FILES = $(shell find $(DIR) -type f -name '*.lean')
|
||||||
OLEAN_FILES = $(LEAN_FILES:.lean=.olean)
|
OLEAN_FILES = $(LEAN_FILES:.lean=.olean)
|
||||||
DEP_FILES = $(LEAN_FILES:.lean=.d)
|
DEP_FILES = $(LEAN_FILES:.lean=.d)
|
||||||
|
|
||||||
|
|
|
@ -1033,7 +1033,7 @@ void parser::parse_script(bool as_expr) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static optional<std::string> find_file(name const & f, char const * ext) {
|
static optional<std::string> try_file(name const & f, char const * ext) {
|
||||||
try {
|
try {
|
||||||
return optional<std::string>(find_file(f, {ext}));
|
return optional<std::string>(find_file(f, {ext}));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
@ -1041,6 +1041,14 @@ static optional<std::string> find_file(name const & f, char const * ext) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static optional<std::string> try_file(std::string const & base, optional<unsigned> const & k, name const & f, char const * ext) {
|
||||||
|
try {
|
||||||
|
return optional<std::string>(find_file(base, k, f, ext));
|
||||||
|
} catch (...) {
|
||||||
|
return optional<std::string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static std::string g_lua_module_key("lua_module");
|
static std::string g_lua_module_key("lua_module");
|
||||||
static void lua_module_reader(deserializer & d, module_idx, shared_environment &,
|
static void lua_module_reader(deserializer & d, module_idx, shared_environment &,
|
||||||
std::function<void(asynch_update_fn const &)> &,
|
std::function<void(asynch_update_fn const &)> &,
|
||||||
|
@ -1056,17 +1064,31 @@ static void lua_module_reader(deserializer & d, module_idx, shared_environment &
|
||||||
register_module_object_reader_fn g_lua_module_reader(g_lua_module_key, lua_module_reader);
|
register_module_object_reader_fn g_lua_module_reader(g_lua_module_key, lua_module_reader);
|
||||||
|
|
||||||
void parser::parse_imports() {
|
void parser::parse_imports() {
|
||||||
buffer<name> olean_files;
|
buffer<module_name> olean_files;
|
||||||
buffer<name> lua_files;
|
buffer<name> lua_files;
|
||||||
|
std::string base = dirname(get_stream_name().c_str());
|
||||||
while (curr_is_token(g_import)) {
|
while (curr_is_token(g_import)) {
|
||||||
m_last_cmd_pos = pos();
|
m_last_cmd_pos = pos();
|
||||||
next();
|
next();
|
||||||
while (curr_is_identifier()) {
|
while (true) {
|
||||||
|
optional<unsigned> k;
|
||||||
|
while (curr_is_token(g_period)) {
|
||||||
|
next();
|
||||||
|
if (!k)
|
||||||
|
k = 0;
|
||||||
|
else
|
||||||
|
k = *k + 1;
|
||||||
|
}
|
||||||
|
if (!curr_is_identifier())
|
||||||
|
break;
|
||||||
name f = get_name_val();
|
name f = get_name_val();
|
||||||
if (auto it = find_file(f, ".lua")) {
|
if (auto it = try_file(f, ".lua")) {
|
||||||
|
if (k)
|
||||||
|
throw parser_error(sstream() << "invalid import, failed to import '" << f
|
||||||
|
<< "', relative paths are not supported for .lua files", pos());
|
||||||
lua_files.push_back(f);
|
lua_files.push_back(f);
|
||||||
} else if (auto it = find_file(f, ".olean")) {
|
} else if (auto it = try_file(base, k, f, ".olean")) {
|
||||||
olean_files.push_back(f);
|
olean_files.push_back(module_name(k, f));
|
||||||
} else {
|
} else {
|
||||||
m_found_errors = true;
|
m_found_errors = true;
|
||||||
if (!m_use_exceptions && m_show_errors) {
|
if (!m_use_exceptions && m_show_errors) {
|
||||||
|
@ -1083,7 +1105,7 @@ void parser::parse_imports() {
|
||||||
unsigned num_threads = 0;
|
unsigned num_threads = 0;
|
||||||
if (get_parser_parallel_import(m_ios.get_options()))
|
if (get_parser_parallel_import(m_ios.get_options()))
|
||||||
num_threads = m_num_threads;
|
num_threads = m_num_threads;
|
||||||
m_env = import_modules(m_env, olean_files.size(), olean_files.data(), num_threads, true, m_ios);
|
m_env = import_modules(m_env, base, olean_files.size(), olean_files.data(), num_threads, true, m_ios);
|
||||||
for (auto const & f : lua_files) {
|
for (auto const & f : lua_files) {
|
||||||
std::string rname = find_file(f, {".lua"});
|
std::string rname = find_file(f, {".lua"});
|
||||||
system_import(rname.c_str());
|
system_import(rname.c_str());
|
||||||
|
|
|
@ -1056,16 +1056,16 @@ static int environment_for_each_universe(lua_State * L) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void to_name_buffer(lua_State * L, int i, buffer<name> & r) {
|
static void to_module_name_buffer(lua_State * L, int i, buffer<module_name> & r) {
|
||||||
if (lua_isstring(L, i) || is_name(L, i)) {
|
if (lua_isstring(L, i) || is_name(L, i)) {
|
||||||
r.push_back(to_name_ext(L, i));
|
r.push_back(module_name(to_name_ext(L, i)));
|
||||||
} else {
|
} else {
|
||||||
luaL_checktype(L, i, LUA_TTABLE);
|
luaL_checktype(L, i, LUA_TTABLE);
|
||||||
lua_pushvalue(L, i);
|
lua_pushvalue(L, i);
|
||||||
int sz = objlen(L, -1);
|
int sz = objlen(L, -1);
|
||||||
for (int i = 1; i <= sz; i++) {
|
for (int i = 1; i <= sz; i++) {
|
||||||
lua_rawgeti(L, -1, i);
|
lua_rawgeti(L, -1, i);
|
||||||
r.push_back(to_name_ext(L, -1));
|
r.push_back(module_name(to_name_ext(L, -1)));
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1073,18 +1073,19 @@ static void to_name_buffer(lua_State * L, int i, buffer<name> & r) {
|
||||||
|
|
||||||
static int import_modules(environment const & env, lua_State * L, int s) {
|
static int import_modules(environment const & env, lua_State * L, int s) {
|
||||||
int nargs = lua_gettop(L);
|
int nargs = lua_gettop(L);
|
||||||
buffer<name> mnames;
|
buffer<module_name> mnames;
|
||||||
to_name_buffer(L, s, mnames);
|
to_module_name_buffer(L, s, mnames);
|
||||||
unsigned num_threads = 1;
|
unsigned num_threads = 1;
|
||||||
bool keep_proofs = false;
|
bool keep_proofs = false;
|
||||||
if (nargs > s) {
|
if (nargs > s) {
|
||||||
num_threads = get_uint_named_param(L, s+1, "num_threads", num_threads);
|
num_threads = get_uint_named_param(L, s+1, "num_threads", num_threads);
|
||||||
keep_proofs = get_bool_named_param(L, s+1, "keep_proofs", keep_proofs);
|
keep_proofs = get_bool_named_param(L, s+1, "keep_proofs", keep_proofs);
|
||||||
}
|
}
|
||||||
|
std::string base;
|
||||||
if (nargs > s+1 && is_io_state(L, s+2))
|
if (nargs > s+1 && is_io_state(L, s+2))
|
||||||
return push_environment(L, import_modules(env, mnames.size(), mnames.data(), num_threads, keep_proofs, to_io_state(L, s+2)));
|
return push_environment(L, import_modules(env, base, mnames.size(), mnames.data(), num_threads, keep_proofs, to_io_state(L, s+2)));
|
||||||
else
|
else
|
||||||
return push_environment(L, import_modules(env, mnames.size(), mnames.data(), num_threads, keep_proofs, get_io_state(L)));
|
return push_environment(L, import_modules(env, base, mnames.size(), mnames.data(), num_threads, keep_proofs, get_io_state(L)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int import_modules(lua_State * L) {
|
static int import_modules(lua_State * L) {
|
||||||
|
|
|
@ -31,8 +31,8 @@ namespace lean {
|
||||||
typedef std::pair<std::string, std::function<void(serializer &)>> writer;
|
typedef std::pair<std::string, std::function<void(serializer &)>> writer;
|
||||||
|
|
||||||
struct module_ext : public environment_extension {
|
struct module_ext : public environment_extension {
|
||||||
list<name> m_direct_imports;
|
list<module_name> m_direct_imports;
|
||||||
list<writer> m_writers;
|
list<writer> m_writers;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct module_ext_reg {
|
struct module_ext_reg {
|
||||||
|
@ -51,9 +51,29 @@ static environment update(environment const & env, module_ext const & ext) {
|
||||||
static char const * g_olean_end_file = "EndFile";
|
static char const * g_olean_end_file = "EndFile";
|
||||||
static char const * g_olean_header = "oleanfile";
|
static char const * g_olean_header = "oleanfile";
|
||||||
|
|
||||||
|
serializer & operator<<(serializer & s, module_name const & n) {
|
||||||
|
if (n.is_relative())
|
||||||
|
s << true << *n.get_k() << n.get_name();
|
||||||
|
else
|
||||||
|
s << false << n.get_name();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
module_name read_module_name(deserializer & d) {
|
||||||
|
if (d.read_bool()) {
|
||||||
|
unsigned k; name n;
|
||||||
|
d >> k >> n;
|
||||||
|
return module_name(k, n);
|
||||||
|
} else {
|
||||||
|
name n;
|
||||||
|
d >> n;
|
||||||
|
return module_name(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void export_module(std::ostream & out, environment const & env) {
|
void export_module(std::ostream & out, environment const & env) {
|
||||||
module_ext const & ext = get_extension(env);
|
module_ext const & ext = get_extension(env);
|
||||||
buffer<name> imports;
|
buffer<module_name> imports;
|
||||||
buffer<writer const *> writers;
|
buffer<writer const *> writers;
|
||||||
to_buffer(ext.m_direct_imports, imports);
|
to_buffer(ext.m_direct_imports, imports);
|
||||||
std::reverse(imports.begin(), imports.end());
|
std::reverse(imports.begin(), imports.end());
|
||||||
|
@ -171,7 +191,6 @@ struct import_modules_fn {
|
||||||
atomic<bool> m_all_modules_imported;
|
atomic<bool> m_all_modules_imported;
|
||||||
|
|
||||||
struct module_info {
|
struct module_info {
|
||||||
name m_name;
|
|
||||||
std::string m_fname;
|
std::string m_fname;
|
||||||
atomic<unsigned> m_counter; // number of dependencies to be processed
|
atomic<unsigned> m_counter; // number of dependencies to be processed
|
||||||
unsigned m_module_idx;
|
unsigned m_module_idx;
|
||||||
|
@ -198,11 +217,12 @@ struct import_modules_fn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module_info_ptr load_module_file(name const & mname) {
|
module_info_ptr load_module_file(std::string const & base, module_name const & mname) {
|
||||||
auto it = m_module_info.find(mname);
|
// TODO(Leo): support module_name
|
||||||
|
std::string fname = find_file(base, mname.get_k(), mname.get_name(), {".olean"});
|
||||||
|
auto it = m_module_info.find(fname);
|
||||||
if (it)
|
if (it)
|
||||||
return *it;
|
return *it;
|
||||||
std::string fname = find_file(mname, {".olean"});
|
|
||||||
if (m_visited.contains(fname))
|
if (m_visited.contains(fname))
|
||||||
throw exception(sstream() << "circular dependency detected at '" << fname << "'");
|
throw exception(sstream() << "circular dependency detected at '" << fname << "'");
|
||||||
m_visited.insert(fname);
|
m_visited.insert(fname);
|
||||||
|
@ -219,9 +239,9 @@ struct import_modules_fn {
|
||||||
// Enforce version?
|
// Enforce version?
|
||||||
|
|
||||||
unsigned num_imports = d1.read_unsigned();
|
unsigned num_imports = d1.read_unsigned();
|
||||||
buffer<name> imports;
|
buffer<module_name> imports;
|
||||||
for (unsigned i = 0; i < num_imports; i++)
|
for (unsigned i = 0; i < num_imports; i++)
|
||||||
imports.push_back(read_name(d1));
|
imports.push_back(read_module_name(d1));
|
||||||
|
|
||||||
unsigned code_size = d1.read_unsigned();
|
unsigned code_size = d1.read_unsigned();
|
||||||
std::vector<char> code(code_size);
|
std::vector<char> code(code_size);
|
||||||
|
@ -233,17 +253,17 @@ struct import_modules_fn {
|
||||||
throw exception(sstream() << "file '" << fname << "' has been corrupted, checksum mismatch");
|
throw exception(sstream() << "file '" << fname << "' has been corrupted, checksum mismatch");
|
||||||
|
|
||||||
module_info_ptr r = std::make_shared<module_info>();
|
module_info_ptr r = std::make_shared<module_info>();
|
||||||
r->m_name = mname;
|
|
||||||
r->m_fname = fname;
|
r->m_fname = fname;
|
||||||
r->m_counter = imports.size();
|
r->m_counter = imports.size();
|
||||||
r->m_module_idx = g_null_module_idx;
|
r->m_module_idx = g_null_module_idx;
|
||||||
m_import_counter++;
|
m_import_counter++;
|
||||||
|
std::string new_base = dirname(fname.c_str());
|
||||||
std::swap(r->m_obj_code, code);
|
std::swap(r->m_obj_code, code);
|
||||||
for (auto i : imports) {
|
for (auto i : imports) {
|
||||||
auto d = load_module_file(i);
|
auto d = load_module_file(new_base, i);
|
||||||
d->m_dependents.push_back(r);
|
d->m_dependents.push_back(r);
|
||||||
}
|
}
|
||||||
m_module_info.insert(mname, r);
|
m_module_info.insert(fname, r);
|
||||||
r->m_module_idx = m_next_module_idx++;
|
r->m_module_idx = m_next_module_idx++;
|
||||||
|
|
||||||
if (imports.empty())
|
if (imports.empty())
|
||||||
|
@ -425,31 +445,31 @@ struct import_modules_fn {
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
void store_direct_imports(unsigned num_modules, name const * modules) {
|
void store_direct_imports(unsigned num_modules, module_name const * modules) {
|
||||||
m_senv.update([&](environment const & env) -> environment {
|
m_senv.update([&](environment const & env) -> environment {
|
||||||
module_ext ext = get_extension(env);
|
module_ext ext = get_extension(env);
|
||||||
for (unsigned i = 0; i < num_modules; i++)
|
for (unsigned i = 0; i < num_modules; i++)
|
||||||
ext.m_direct_imports = list<name>(modules[i], ext.m_direct_imports);
|
ext.m_direct_imports = cons(modules[i], ext.m_direct_imports);
|
||||||
return update(env, ext);
|
return update(env, ext);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
environment operator()(unsigned num_modules, name const * modules) {
|
environment operator()(std::string const & base, unsigned num_modules, module_name const * modules) {
|
||||||
store_direct_imports(num_modules, modules);
|
store_direct_imports(num_modules, modules);
|
||||||
for (unsigned i = 0; i < num_modules; i++)
|
for (unsigned i = 0; i < num_modules; i++)
|
||||||
load_module_file(modules[i]);
|
load_module_file(base, modules[i]);
|
||||||
process_asynch_tasks();
|
process_asynch_tasks();
|
||||||
return process_delayed_tasks();
|
return process_delayed_tasks();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
environment import_modules(environment const & env, unsigned num_modules, name const * modules,
|
environment import_modules(environment const & env, std::string const & base, unsigned num_modules, module_name const * modules,
|
||||||
unsigned num_threads, bool keep_proofs, io_state const & ios) {
|
unsigned num_threads, bool keep_proofs, io_state const & ios) {
|
||||||
return import_modules_fn(env, num_threads, keep_proofs, ios)(num_modules, modules);
|
return import_modules_fn(env, num_threads, keep_proofs, ios)(base, num_modules, modules);
|
||||||
}
|
}
|
||||||
|
|
||||||
environment import_module(environment const & env, name const & module,
|
environment import_module(environment const & env, std::string const & base, module_name const & module,
|
||||||
unsigned num_threads, bool keep_proofs, io_state const & ios) {
|
unsigned num_threads, bool keep_proofs, io_state const & ios) {
|
||||||
return import_modules(env, 1, &module, num_threads, keep_proofs, ios);
|
return import_modules(env, base, 1, &module, num_threads, keep_proofs, ios);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,24 @@ Author: Leonardo de Moura
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "util/serializer.h"
|
#include "util/serializer.h"
|
||||||
|
#include "util/optional.h"
|
||||||
#include "kernel/inductive/inductive.h"
|
#include "kernel/inductive/inductive.h"
|
||||||
#include "library/shared_environment.h"
|
#include "library/shared_environment.h"
|
||||||
#include "library/io_state.h"
|
#include "library/io_state.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
|
class module_name {
|
||||||
|
optional<unsigned> m_relative;
|
||||||
|
name m_name;
|
||||||
|
public:
|
||||||
|
module_name(name const & n):m_name(n) {}
|
||||||
|
module_name(unsigned k, name const & n):m_relative(k), m_name(n) {}
|
||||||
|
module_name(optional<unsigned> const & k, name const & n):m_relative(k), m_name(n) {}
|
||||||
|
name const & get_name() const { return m_name; }
|
||||||
|
bool is_relative() const { return static_cast<bool>(m_relative); }
|
||||||
|
optional<unsigned> const & get_k() const { return m_relative; }
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Return an environment based on \c env, where all modules in \c modules are imported.
|
\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.
|
Modules included directly or indirectly by them are also imported.
|
||||||
|
@ -21,9 +34,9 @@ namespace lean {
|
||||||
If \c keep_proofs is false, then the proof of the imported theorems is discarded after being
|
If \c keep_proofs is false, then the proof of the imported theorems is discarded after being
|
||||||
checked. The idea is to save memory.
|
checked. The idea is to save memory.
|
||||||
*/
|
*/
|
||||||
environment import_modules(environment const & env, unsigned num_modules, name const * modules,
|
environment import_modules(environment const & env, std::string const & base, unsigned num_modules, module_name const * modules,
|
||||||
unsigned num_threads, bool keep_proofs, io_state const & ios);
|
unsigned num_threads, bool keep_proofs, io_state const & ios);
|
||||||
environment import_module(environment const & env, name const & module,
|
environment import_module(environment const & env, std::string const & base, module_name const & module,
|
||||||
unsigned num_threads, bool keep_proofs, io_state const & ios);
|
unsigned num_threads, bool keep_proofs, io_state const & ios);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,6 +14,7 @@ Author: Leonardo de Moura
|
||||||
#include "util/sstream.h"
|
#include "util/sstream.h"
|
||||||
#include "util/name.h"
|
#include "util/name.h"
|
||||||
#include "util/optional.h"
|
#include "util/optional.h"
|
||||||
|
#include "util/realpath.h"
|
||||||
|
|
||||||
#ifndef LEAN_DEFAULT_MODULE_FILE_NAME
|
#ifndef LEAN_DEFAULT_MODULE_FILE_NAME
|
||||||
#define LEAN_DEFAULT_MODULE_FILE_NAME "default"
|
#define LEAN_DEFAULT_MODULE_FILE_NAME "default"
|
||||||
|
@ -218,7 +219,7 @@ optional<std::string> check_file(std::string const & path, std::string const & f
|
||||||
file += ext;
|
file += ext;
|
||||||
std::ifstream ifile(file);
|
std::ifstream ifile(file);
|
||||||
if (ifile)
|
if (ifile)
|
||||||
return optional<std::string>(file);
|
return optional<std::string>(realpath(file.c_str()));
|
||||||
else
|
else
|
||||||
return optional<std::string>();
|
return optional<std::string>();
|
||||||
}
|
}
|
||||||
|
@ -244,6 +245,21 @@ std::string find_file(std::string fname, std::initializer_list<char const *> con
|
||||||
throw exception(sstream() << "file '" << fname << "' not found in the LEAN_PATH");
|
throw exception(sstream() << "file '" << fname << "' not found in the LEAN_PATH");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string find_file(std::string const & base, optional<unsigned> const & rel, name const & fname, char const * ext) {
|
||||||
|
if (!rel) {
|
||||||
|
return find_file(fname.to_string(g_sep_str.c_str()), {ext});
|
||||||
|
} else {
|
||||||
|
auto path = base;
|
||||||
|
for (unsigned i = 0; i < *rel; i++) {
|
||||||
|
path += g_sep;
|
||||||
|
path += "..";
|
||||||
|
}
|
||||||
|
if (auto r = check_file(path, fname.to_string(g_sep_str.c_str()), ext))
|
||||||
|
return *r;
|
||||||
|
throw exception(sstream() << "file '" << fname << "' not found at '" << path << "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string find_file(std::string fname) {
|
std::string find_file(std::string fname) {
|
||||||
return find_file(fname, {".olean", ".lean", ".lua"});
|
return find_file(fname, {".olean", ".lean", ".lua"});
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,9 @@ std::string find_file(std::string fname, std::initializer_list<char const *> con
|
||||||
std::string find_file(name const & fname);
|
std::string find_file(name const & fname);
|
||||||
std::string find_file(name const & fname, std::initializer_list<char const *> const & exts);
|
std::string find_file(name const & fname, std::initializer_list<char const *> const & exts);
|
||||||
|
|
||||||
|
/** \brief \brief Similar to previous find_file, but if k is not none then search at the k-th parent of base. */
|
||||||
|
std::string find_file(std::string const & base, optional<unsigned> const & k, name const & fname, char const * ext);
|
||||||
|
|
||||||
/** \brief Return true iff fname ends with ".lean" */
|
/** \brief Return true iff fname ends with ".lean" */
|
||||||
bool is_lean_file(std::string const & fname);
|
bool is_lean_file(std::string const & fname);
|
||||||
/** \brief Return true iff fname ends with ".olean" */
|
/** \brief Return true iff fname ends with ".olean" */
|
||||||
|
|
Loading…
Reference in a new issue