refactor(frontends/lean/info_manager): store environment+options in the info_manager, fixes #96

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2014-08-26 18:06:37 -07:00
parent 9bea23111f
commit dd99e60a00
9 changed files with 195 additions and 58 deletions

View file

@ -569,7 +569,8 @@ public:
if (!infom())
return;
m_pre_info_data.instantiate(s);
infom()->merge(m_pre_info_data);
bool overwrite = true;
infom()->merge(m_pre_info_data, overwrite);
m_pre_info_data.clear();
}

View file

@ -6,7 +6,9 @@ Author: Leonardo de Moura
*/
#include <algorithm>
#include <vector>
#include <set>
#include "util/thread.h"
#include "kernel/environment.h"
#include "library/choice.h"
#include "frontends/lean/info_manager.h"
#include "frontends/lean/pp_options.h"
@ -195,14 +197,36 @@ struct info_data_cmp {
struct info_manager::imp {
typedef rb_tree<info_data, info_data_cmp> info_data_set;
/** \brief Saved environment + options for a given line and iteration
Whenever "lean server" starts processing a file again, we bump the iteration.
*/
struct env_info {
unsigned m_line;
unsigned m_iteration;
environment m_env;
options m_options;
env_info():m_line(0), m_iteration(0) {}
env_info(unsigned l, unsigned i, environment const & env, options const & o):
m_line(l), m_iteration(i), m_env(env), m_options(o) {}
friend bool operator<(env_info const & i1, env_info const & i2) { return i1.m_line < i2.m_line; }
};
mutex m_mutex;
bool m_block_updates;
std::vector<info_data_set> m_line_data;
std::vector<bool> m_line_valid;
unsigned m_available_upto;
std::set<env_info> m_env_info;
unsigned m_iteration; // current interation
unsigned m_processed_upto;
imp():m_available_upto(0) {}
imp():m_block_updates(false), m_iteration(0), m_processed_upto(0) {}
void block_updates(bool f) {
lock_guard<mutex> lc(m_mutex);
m_block_updates = f;
}
void synch_line(unsigned l) {
lean_assert(!m_block_updates);
lean_assert(l > 0);
if (l >= m_line_data.size()) {
m_line_data.resize(l+1);
@ -210,38 +234,68 @@ struct info_manager::imp {
}
}
void save_environment_options(unsigned l, environment const & env, options const & o) {
lock_guard<mutex> lc(m_mutex);
if (m_block_updates)
return;
// erase all entries in m_env_info such that e.m_line <= l and e.m_iteration < m_iteration
auto it = m_env_info.begin();
auto end = m_env_info.end();
while (it != end) {
if (it->m_line > l)
break;
else if (it->m_line <= l && it->m_iteration < m_iteration)
it = m_env_info.erase(it);
else
++it;
}
m_env_info.insert(env_info(l, m_iteration, env, o));
}
void add_type_info(unsigned l, unsigned c, expr const & e) {
lock_guard<mutex> lc(m_mutex);
if (m_block_updates)
return;
synch_line(l);
m_line_data[l].insert(mk_type_info(c, e));
}
void add_synth_info(unsigned l, unsigned c, expr const & e) {
lock_guard<mutex> lc(m_mutex);
if (m_block_updates)
return;
synch_line(l);
m_line_data[l].insert(mk_synth_info(c, e));
}
void add_overload_info(unsigned l, unsigned c, expr const & e) {
lock_guard<mutex> lc(m_mutex);
if (m_block_updates)
return;
synch_line(l);
m_line_data[l].insert(mk_overload_info(c, e));
}
void add_coercion_info(unsigned l, unsigned c, expr const & e) {
lock_guard<mutex> lc(m_mutex);
if (m_block_updates)
return;
synch_line(l);
m_line_data[l].insert(mk_coercion_info(c, e));
}
void add_symbol_info(unsigned l, unsigned c, name const & s) {
lock_guard<mutex> lc(m_mutex);
if (m_block_updates)
return;
synch_line(l);
m_line_data[l].insert(mk_symbol_info(c, s));
}
void add_identifier_info(unsigned l, unsigned c, name const & full_id) {
lock_guard<mutex> lc(m_mutex);
if (m_block_updates)
return;
synch_line(l);
m_line_data[l].insert(mk_identifier_info(c, full_id));
}
@ -256,6 +310,8 @@ struct info_manager::imp {
void instantiate(substitution const & s) {
lock_guard<mutex> lc(m_mutex);
if (m_block_updates)
return;
substitution tmp_s = s;
unsigned sz = m_line_data.size();
for (unsigned i = 0; i < sz; i++) {
@ -263,25 +319,30 @@ struct info_manager::imp {
}
}
void merge(info_manager::imp const & m) {
void merge(info_manager::imp const & m, bool overwrite) {
if (m.m_line_data.empty())
return;
lock_guard<mutex> lc(m_mutex);
if (m_block_updates)
return;
unsigned sz = m.m_line_data.size();
for (unsigned i = 1; i < sz; i++) {
info_data_set const & s = m.m_line_data[i];
s.for_each([&](info_data const & d) {
synch_line(i);
m_line_data[i].insert(d);
if (overwrite || !m_line_data[i].contains(d))
m_line_data[i].insert(d);
});
}
}
void insert_line(unsigned l) {
lock_guard<mutex> lc(m_mutex);
if (m_block_updates)
return;
synch_line(l);
if (m_available_upto > l - 1)
m_available_upto = l - 1;
if (m_processed_upto > l - 1)
m_processed_upto = l - 1;
m_line_data.push_back(info_data_set());
unsigned i = m_line_data.size();
while (i > l) {
@ -294,6 +355,8 @@ struct info_manager::imp {
void remove_line(unsigned l) {
lock_guard<mutex> lc(m_mutex);
if (m_block_updates)
return;
lean_assert(l > 0);
if (l >= m_line_data.size())
return;
@ -303,29 +366,28 @@ struct info_manager::imp {
m_line_valid[i] = m_line_valid[i+1];
}
m_line_data.pop_back();
if (m_available_upto > l - 1)
m_available_upto = l - 1;
if (m_processed_upto > l - 1)
m_processed_upto = l - 1;
}
void invalidate_line(unsigned l) {
lock_guard<mutex> lc(m_mutex);
if (m_block_updates)
return;
synch_line(l);
if (m_available_upto > l - 1)
m_available_upto = l - 1;
if (m_processed_upto > l - 1)
m_processed_upto = l - 1;
m_line_data[l] = info_data_set();
m_line_valid[l] = false;
}
void commit_upto(unsigned l, bool valid) {
lock_guard<mutex> lc(m_mutex);
for (unsigned i = m_available_upto; i < l && i < m_line_valid.size(); i++)
if (m_block_updates)
return;
for (unsigned i = m_processed_upto; i < l && i < m_line_valid.size(); i++)
m_line_valid[i] = valid;
m_available_upto = l;
}
bool is_available(unsigned l) {
lock_guard<mutex> lc(m_mutex);
return l < m_available_upto;
m_processed_upto = l;
}
bool is_invalidated(unsigned l) {
@ -335,18 +397,60 @@ struct info_manager::imp {
return !m_line_valid[l];
}
void display(io_state_stream const & ios, unsigned l) {
lock_guard<mutex> lc(m_mutex);
if (l >= m_line_data.size())
return;
m_line_data[l].for_each([&](info_data const & d) {
d.display(ios, l);
void display_core(environment const & env, options const & o, io_state const & ios, unsigned line) {
io_state_stream out = regular(env, ios).update_options(o);
m_line_data[line].for_each([&](info_data const & d) {
d.display(out, line);
});
}
void display(environment const & env, io_state const & ios, unsigned line) {
lock_guard<mutex> lc(m_mutex);
if (line >= m_line_data.size() || m_line_data[line].empty()) {
regular(env, ios) << "-- NAY\n";
return;
}
if (m_env_info.empty()) {
display_core(env, ios.get_options(), ios, line);
return;
}
auto it = m_env_info.begin();
auto end = m_env_info.end();
lean_assert(it != end);
if (it->m_line > line) {
display_core(env, ios.get_options(), ios, line);
return;
}
while (true) {
lean_assert(it->m_line <= line);
lean_assert(it != end);
auto next = it;
++next;
if (next == end || next->m_line > line) {
display_core(it->m_env, it->m_options, ios, line);
return;
}
it = next;
}
}
optional<pair<environment, options>> get_final_env_opts() {
lock_guard<mutex> lc(m_mutex);
if (m_env_info.empty()) {
return optional<pair<environment, options>>();
} else {
auto it = m_env_info.end();
--it;
return optional<pair<environment, options>>(mk_pair(it->m_env, it->m_options));
}
}
void clear() {
lock_guard<mutex> lc(m_mutex);
if (m_block_updates)
return;
m_line_data.clear();
m_line_valid.clear();
}
};
@ -361,13 +465,20 @@ void info_manager::add_identifier_info(unsigned l, unsigned c, name const & full
m_ptr->add_identifier_info(l, c, full_id);
}
void info_manager::instantiate(substitution const & s) { m_ptr->instantiate(s); }
void info_manager::merge(info_manager const & m) { m_ptr->merge(*m.m_ptr); }
void info_manager::merge(info_manager const & m, bool overwrite) { m_ptr->merge(*m.m_ptr, overwrite); }
void info_manager::insert_line(unsigned l) { m_ptr->insert_line(l); }
void info_manager::remove_line(unsigned l) { m_ptr->remove_line(l); }
void info_manager::invalidate_line(unsigned l) { m_ptr->invalidate_line(l); }
void info_manager::commit_upto(unsigned l, bool valid) { m_ptr->commit_upto(l, valid); }
bool info_manager::is_available(unsigned l) const { return m_ptr->is_available(l); }
bool info_manager::is_invalidated(unsigned l) const { return m_ptr->is_invalidated(l); }
void info_manager::clear() { m_ptr->clear(); }
void info_manager::display(io_state_stream const & ios, unsigned line) { m_ptr->display(ios, line); }
void info_manager::save_environment_options(unsigned l, environment const & env, options const & o) {
m_ptr->save_environment_options(l, env, o);
}
void info_manager::clear() { m_ptr->clear(); }
optional<pair<environment, options>> info_manager::get_final_env_opts() const {
return m_ptr->get_final_env_opts();
}
void info_manager::display(environment const & env, io_state const & ios, unsigned line) {
m_ptr->display(env, ios, line);
}
}

View file

@ -25,14 +25,15 @@ public:
void add_symbol_info(unsigned l, unsigned c, name const & n);
void add_identifier_info(unsigned l, unsigned c, name const & full_id);
void instantiate(substitution const & s);
void merge(info_manager const & m);
void merge(info_manager const & m, bool overwrite);
void insert_line(unsigned l);
void remove_line(unsigned l);
void invalidate_line(unsigned l);
void commit_upto(unsigned l, bool valid);
bool is_available(unsigned l) const;
bool is_invalidated(unsigned l) const;
void save_environment_options(unsigned l, environment const & env, options const & o);
optional<pair<environment, options>> get_final_env_opts() const;
void clear();
void display(io_state_stream const & ios, unsigned line);
void display(environment const & env, io_state const & ios, unsigned line);
};
}

View file

@ -1209,6 +1209,14 @@ void parser::parse_imports() {
}
}
void parser::commit_info(unsigned line) {
save_snapshot();
if (m_info_manager) {
m_info_manager->save_environment_options(line, m_env, m_ios.get_options());
m_info_manager->commit_upto(line, true);
}
}
bool parser::parse_commands() {
// We disable hash-consing while parsing to make sure the pos-info are correct.
scoped_expr_caching disable(false);
@ -1230,9 +1238,7 @@ bool parser::parse_commands() {
switch (curr()) {
case scanner::token_kind::CommandKeyword:
parse_command();
save_snapshot();
if (m_info_manager)
m_info_manager->commit_upto(m_scanner.get_line(), true);
commit_info(m_scanner.get_line());
break;
case scanner::token_kind::ScriptBlock:
parse_script();
@ -1260,9 +1266,7 @@ bool parser::parse_commands() {
throw_parser_exception("invalid end of module, expecting 'end'", pos());
}
} catch (interrupt_parser) {}
save_snapshot();
if (m_info_manager)
m_info_manager->commit_upto(m_scanner.get_line()+1, true);
commit_info(m_scanner.get_line()+1);
for (certified_declaration const & thm : m_theorem_queue.join()) {
m_env.replace(thm);
}
@ -1299,7 +1303,8 @@ void parser::save_snapshot() {
void parser::save_pre_info_data() {
// if elaborator failed, then m_pre_info_data contains type information before elaboration.
if (m_info_manager) {
m_info_manager->merge(m_pre_info_manager);
bool overwrite = false;
m_info_manager->merge(m_pre_info_manager, overwrite);
m_pre_info_manager.clear();
}
}

View file

@ -170,6 +170,7 @@ class parser {
void save_type_info(expr const & e);
void save_pre_info_data();
void save_identifier_info(pos_info const & p, name const & full_id);
void commit_info(unsigned line);
elaborator_context mk_elaborator_context(pos_info_provider const & pp, bool check_unassigned = true);
elaborator_context mk_elaborator_context(environment const & env, pos_info_provider const & pp);

View file

@ -256,31 +256,17 @@ void server::set_option(std::string const & line) {
void server::show_info(unsigned linenum) {
check_file();
if (!m_file->m_info.is_available(linenum)) {
m_out << "-- BEGININFO\n-- NAY\n-- ENDINFO" << std::endl;
return;
}
unsigned i = m_file->find(linenum);
environment const & env = i == 0 ? m_env : m_file->m_snapshots[i-1].m_env;
options const & o = i == 0 ? m_ios.get_options() : m_file->m_snapshots[i-1].m_options;
scoped_updt_options updt(m_ios, o);
io_state_stream out(env, m_ios);
out << "-- BEGININFO" << endl;
m_file->m_info.display(out, linenum);
out << "-- ENDINFO" << endl;
m_out << "-- BEGININFO" << std::endl;
m_file->m_info.display(m_env, m_ios, linenum);
m_out << "-- ENDINFO" << std::endl;
}
void server::eval(std::string const & line) {
if (!m_file->m_info.is_available(m_file->m_lines.size())) {
m_out << "-- BEGINEVAL\n-- NAY\n-- ENDEVAL" << std::endl;
return;
}
snapshot & s = !m_file || m_file->m_snapshots.empty() ? m_empty_snapshot : m_file->m_snapshots.back();
void server::eval_core(environment const & env, options const & o, std::string const & line) {
std::istringstream strm(line);
scoped_updt_options updt(m_ios, s.m_options);
scoped_updt_options updt(m_ios, o);
m_out << "-- BEGINEVAL" << std::endl;
try {
parser p(s.m_env, m_ios, strm, "EVAL_command", true, 1, s.m_lds, s.m_eds, 1);
parser p(env, m_ios, strm, "EVAL_command", true);
p();
} catch (exception & ex) {
m_out << ex.what() << std::endl;
@ -288,6 +274,16 @@ void server::eval(std::string const & line) {
m_out << "-- ENDEVAL" << std::endl;
}
void server::eval(std::string const & line) {
if (!m_file) {
eval_core(m_env, m_ios.get_options(), line);
} else if (auto p = m_file->m_info.get_final_env_opts()) {
eval_core(p->first, p->second, line);
} else {
eval_core(m_env, m_ios.get_options(), line);
}
}
bool server::operator()(std::istream & in) {
for (std::string line; std::getline(in, line);) {
try {

View file

@ -53,6 +53,7 @@ class server {
void show_info(unsigned linenum);
void process_from(unsigned linenum);
void set_option(std::string const & line);
void eval_core(environment const & env, options const & o, std::string const & line);
void eval(std::string const & line);
unsigned find(unsigned linenum);
void read_line(std::istream & in, std::string & line);

View file

@ -0,0 +1,10 @@
EVAL
check Type.{1}
SET
pp.universes true
EVAL
check Type.{1}
VISIT simple.lean
WAIT
EVAL
check tst.foo

View file

@ -0,0 +1,11 @@
-- BEGINEVAL
Type : Type
-- ENDEVAL
-- BEGINSET
-- ENDSET
-- BEGINEVAL
Type.{1} : Type.{2}
-- ENDEVAL
-- BEGINEVAL
tst.foo.{l_1 l_2} : ?M_1 → ?M_2 → ?M_1
-- ENDEVAL