feat(frontends/lean): add "--info" command line option for extracting identifier/keyword information
see issue #756
This commit is contained in:
parent
d06c2b1ad3
commit
cc4f18c062
20 changed files with 278 additions and 53 deletions
|
@ -143,7 +143,7 @@ static void print_prefix(parser & p) {
|
||||||
p.regular_stream() << "no declaration starting with prefix '" << prefix << "'" << endl;
|
p.regular_stream() << "no declaration starting with prefix '" << prefix << "'" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_fields(parser & p, name const & S, pos_info const & pos) {
|
static void print_fields(parser const & p, name const & S, pos_info const & pos) {
|
||||||
environment const & env = p.env();
|
environment const & env = p.env();
|
||||||
if (!is_structure(env, S))
|
if (!is_structure(env, S))
|
||||||
throw parser_error(sstream() << "invalid 'print fields' command, '" << S << "' is not a structure", pos);
|
throw parser_error(sstream() << "invalid 'print fields' command, '" << S << "' is not a structure", pos);
|
||||||
|
@ -169,7 +169,7 @@ static bool uses_some_token(unsigned num, notation::transition const * ts, buffe
|
||||||
std::any_of(tokens.begin(), tokens.end(), [&](name const & token) { return uses_token(num, ts, token); });
|
std::any_of(tokens.begin(), tokens.end(), [&](name const & token) { return uses_token(num, ts, token); });
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool print_parse_table(parser & p, parse_table const & t, bool nud, buffer<name> const & tokens) {
|
static bool print_parse_table(parser const & p, parse_table const & t, bool nud, buffer<name> const & tokens) {
|
||||||
bool found = false;
|
bool found = false;
|
||||||
io_state ios = p.ios();
|
io_state ios = p.ios();
|
||||||
options os = ios.get_options();
|
options os = ios.get_options();
|
||||||
|
@ -203,7 +203,7 @@ static void print_notation(parser & p) {
|
||||||
p.regular_stream() << "no notation" << endl;
|
p.regular_stream() << "no notation" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_metaclasses(parser & p) {
|
static void print_metaclasses(parser const & p) {
|
||||||
buffer<name> c;
|
buffer<name> c;
|
||||||
get_metaclasses(c);
|
get_metaclasses(c);
|
||||||
for (name const & n : c)
|
for (name const & n : c)
|
||||||
|
@ -225,7 +225,7 @@ static void print_definition(parser const & p, name const & n, pos_info const &
|
||||||
new_out << d.get_value() << endl;
|
new_out << d.get_value() << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_attributes(parser & p, name const & n) {
|
static void print_attributes(parser const & p, name const & n) {
|
||||||
environment const & env = p.env();
|
environment const & env = p.env();
|
||||||
io_state_stream out = p.regular_stream();
|
io_state_stream out = p.regular_stream();
|
||||||
if (is_coercion(env, n))
|
if (is_coercion(env, n))
|
||||||
|
@ -246,7 +246,7 @@ void print_attributes(parser & p, name const & n) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_inductive(parser & p, name const & n, pos_info const & pos) {
|
static void print_inductive(parser const & p, name const & n, pos_info const & pos) {
|
||||||
environment const & env = p.env();
|
environment const & env = p.env();
|
||||||
io_state_stream out = p.regular_stream();
|
io_state_stream out = p.regular_stream();
|
||||||
if (auto idecls = inductive::is_inductive_decl(env, n)) {
|
if (auto idecls = inductive::is_inductive_decl(env, n)) {
|
||||||
|
@ -312,7 +312,7 @@ static void print_recursor_info(parser & p) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool print_constant(parser & p, char const * kind, declaration const & d, bool is_def = false) {
|
static bool print_constant(parser const & p, char const * kind, declaration const & d, bool is_def = false) {
|
||||||
io_state_stream out = p.regular_stream();
|
io_state_stream out = p.regular_stream();
|
||||||
if (d.is_definition() && is_marked_noncomputable(p.env(), d.get_name()))
|
if (d.is_definition() && is_marked_noncomputable(p.env(), d.get_name()))
|
||||||
out << "noncomputable ";
|
out << "noncomputable ";
|
||||||
|
@ -327,20 +327,21 @@ bool print_constant(parser & p, char const * kind, declaration const & d, bool i
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool print_polymorphic(parser & p) {
|
bool print_id_info(parser const & p, name const & id, bool show_value, pos_info const & pos) {
|
||||||
environment const & env = p.env();
|
// declarations
|
||||||
io_state_stream out = p.regular_stream();
|
|
||||||
auto pos = p.pos();
|
|
||||||
try {
|
try {
|
||||||
name id = p.check_id_next("");
|
environment const & env = p.env();
|
||||||
// declarations
|
io_state_stream out = p.regular_stream();
|
||||||
try {
|
try {
|
||||||
list<name> cs = p.to_constants(id, "", pos);
|
list<name> cs = p.to_constants(id, "", pos);
|
||||||
|
bool first = true;
|
||||||
for (name const & c : cs) {
|
for (name const & c : cs) {
|
||||||
|
if (first) first = false; else out << "\n";
|
||||||
declaration const & d = env.get(c);
|
declaration const & d = env.get(c);
|
||||||
if (d.is_theorem()) {
|
if (d.is_theorem()) {
|
||||||
print_constant(p, "theorem", d, true);
|
print_constant(p, "theorem", d, show_value);
|
||||||
print_definition(p, c, pos);
|
if (show_value)
|
||||||
|
print_definition(p, c, pos);
|
||||||
} else if (d.is_axiom() || d.is_constant_assumption()) {
|
} else if (d.is_axiom() || d.is_constant_assumption()) {
|
||||||
if (inductive::is_inductive_decl(env, c)) {
|
if (inductive::is_inductive_decl(env, c)) {
|
||||||
print_inductive(p, c, pos);
|
print_inductive(p, c, pos);
|
||||||
|
@ -355,8 +356,10 @@ bool print_polymorphic(parser & p) {
|
||||||
} else if (d.is_axiom()) {
|
} else if (d.is_axiom()) {
|
||||||
if (p.in_theorem_queue(d.get_name())) {
|
if (p.in_theorem_queue(d.get_name())) {
|
||||||
print_constant(p, "theorem", d);
|
print_constant(p, "theorem", d);
|
||||||
out << "'" << d.get_name() << "' is still in the theorem queue, use command 'reveal "
|
if (show_value) {
|
||||||
<< d.get_name() << "' to access its definition.\n";
|
out << "'" << d.get_name() << "' is still in the theorem queue, use command 'reveal "
|
||||||
|
<< d.get_name() << "' to access its definition.\n";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
print_constant(p, "axiom", d);
|
print_constant(p, "axiom", d);
|
||||||
}
|
}
|
||||||
|
@ -364,8 +367,9 @@ bool print_polymorphic(parser & p) {
|
||||||
print_constant(p, "constant", d);
|
print_constant(p, "constant", d);
|
||||||
}
|
}
|
||||||
} else if (d.is_definition()) {
|
} else if (d.is_definition()) {
|
||||||
print_constant(p, "definition", d, true);
|
print_constant(p, "definition", d, show_value);
|
||||||
print_definition(p, c, pos);
|
if (show_value)
|
||||||
|
print_definition(p, c, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -393,25 +397,39 @@ bool print_polymorphic(parser & p) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (exception &) {}
|
} catch (exception &) {}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool print_token_info(parser const & p, name const & tk) {
|
||||||
|
buffer<name> tokens;
|
||||||
|
tokens.push_back(tk);
|
||||||
|
bool found = false;
|
||||||
|
if (print_parse_table(p, get_nud_table(p.env()), true, tokens)) {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (print_parse_table(p, get_led_table(p.env()), false, tokens)) {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool print_polymorphic(parser & p) {
|
||||||
|
auto pos = p.pos();
|
||||||
|
try {
|
||||||
|
name id = p.check_id_next("");
|
||||||
|
bool show_value = true;
|
||||||
|
if (print_id_info(p, id, show_value, pos))
|
||||||
|
return true;
|
||||||
|
} catch (exception &) {}
|
||||||
|
|
||||||
// notation
|
// notation
|
||||||
if (p.curr_is_keyword()) {
|
if (p.curr_is_keyword()) {
|
||||||
buffer<name> tokens;
|
|
||||||
name tk = p.get_token_info().token();
|
name tk = p.get_token_info().token();
|
||||||
tokens.push_back(tk);
|
if (print_token_info(p, tk)) {
|
||||||
bool found = false;
|
|
||||||
if (print_parse_table(p, get_nud_table(p.env()), true, tokens)) {
|
|
||||||
p.next();
|
p.next();
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
if (print_parse_table(p, get_led_table(p.env()), false, tokens)) {
|
|
||||||
p.next();
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
if (found)
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,7 +504,12 @@ environment print_cmd(parser & p) {
|
||||||
auto pos = p.pos();
|
auto pos = p.pos();
|
||||||
name id = p.check_id_next("invalid 'print definition', constant expected");
|
name id = p.check_id_next("invalid 'print definition', constant expected");
|
||||||
list<name> cs = p.to_constants(id, "invalid 'print definition', constant expected", pos);
|
list<name> cs = p.to_constants(id, "invalid 'print definition', constant expected", pos);
|
||||||
|
bool first = true;
|
||||||
for (name const & c : cs) {
|
for (name const & c : cs) {
|
||||||
|
if (first)
|
||||||
|
first = false;
|
||||||
|
else
|
||||||
|
p.regular_stream() << "\n";
|
||||||
declaration const & d = p.env().get(c);
|
declaration const & d = p.env().get(c);
|
||||||
if (d.is_theorem()) {
|
if (d.is_theorem()) {
|
||||||
print_constant(p, "theorem", d);
|
print_constant(p, "theorem", d);
|
||||||
|
|
|
@ -7,6 +7,9 @@ Author: Leonardo de Moura
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "frontends/lean/cmd_table.h"
|
#include "frontends/lean/cmd_table.h"
|
||||||
namespace lean {
|
namespace lean {
|
||||||
|
bool print_id_info(parser const & p, name const & id, bool show_value, pos_info const & pos);
|
||||||
|
bool print_token_info(parser const & p, name const & tk);
|
||||||
|
|
||||||
cmd_table get_builtin_cmds();
|
cmd_table get_builtin_cmds();
|
||||||
void initialize_builtin_cmds();
|
void initialize_builtin_cmds();
|
||||||
void finalize_builtin_cmds();
|
void finalize_builtin_cmds();
|
||||||
|
|
|
@ -56,6 +56,7 @@ Author: Leonardo de Moura
|
||||||
#include "frontends/lean/nested_declaration.h"
|
#include "frontends/lean/nested_declaration.h"
|
||||||
#include "frontends/lean/calc.h"
|
#include "frontends/lean/calc.h"
|
||||||
#include "frontends/lean/decl_cmds.h"
|
#include "frontends/lean/decl_cmds.h"
|
||||||
|
#include "frontends/lean/opt_cmd.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
type_checker_ptr mk_coercion_from_type_checker(environment const & env, name_generator && ngen) {
|
type_checker_ptr mk_coercion_from_type_checker(environment const & env, name_generator && ngen) {
|
||||||
|
@ -264,9 +265,9 @@ void elaborator::instantiate_info(substitution s) {
|
||||||
goal g(meta, meta_type);
|
goal g(meta, meta_type);
|
||||||
proof_state ps(goals(g), s, m_ngen, constraints());
|
proof_state ps(goals(g), s, m_ngen, constraints());
|
||||||
auto out = regular(env(), ios());
|
auto out = regular(env(), ios());
|
||||||
out << "LEAN_INFORMATION\n";
|
print_lean_info_header(out.get_stream());
|
||||||
out << ps.pp(env(), ios()) << endl;
|
out << ps.pp(env(), ios()) << endl;
|
||||||
out << "END_LEAN_INFORMATION\n";
|
print_lean_info_footer(out.get_stream());
|
||||||
}
|
}
|
||||||
if (infom()) {
|
if (infom()) {
|
||||||
m_pre_info_data.instantiate(s);
|
m_pre_info_data.instantiate(s);
|
||||||
|
@ -1850,7 +1851,7 @@ void elaborator::show_goal(proof_state const & ps, expr const & start, expr cons
|
||||||
m_ctx.reset_show_goal_at();
|
m_ctx.reset_show_goal_at();
|
||||||
goals const & gs = ps.get_goals();
|
goals const & gs = ps.get_goals();
|
||||||
auto out = regular(env(), ios());
|
auto out = regular(env(), ios());
|
||||||
out << "LEAN_INFORMATION\n";
|
print_lean_info_header(out.get_stream());
|
||||||
out << "position " << curr_pos->first << ":" << curr_pos->second << "\n";
|
out << "position " << curr_pos->first << ":" << curr_pos->second << "\n";
|
||||||
if (empty(gs)) {
|
if (empty(gs)) {
|
||||||
out << "no goals\n";
|
out << "no goals\n";
|
||||||
|
@ -1859,7 +1860,7 @@ void elaborator::show_goal(proof_state const & ps, expr const & start, expr cons
|
||||||
g = g.instantiate(ps.get_subst());
|
g = g.instantiate(ps.get_subst());
|
||||||
out << g << "\n";
|
out << g << "\n";
|
||||||
}
|
}
|
||||||
out << "END_LEAN_INFORMATION\n";
|
print_lean_info_footer(out.get_stream());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool elaborator::try_using_begin_end(substitution & subst, expr const & mvar, proof_state ps, expr const & pre_tac) {
|
bool elaborator::try_using_begin_end(substitution & subst, expr const & mvar, proof_state ps, expr const & pre_tac) {
|
||||||
|
|
|
@ -39,4 +39,19 @@ options set_show_hole(options const & opts, unsigned line, unsigned col) {
|
||||||
bool has_show_hole(options const & opts, unsigned & line, unsigned & col) {
|
bool has_show_hole(options const & opts, unsigned & line, unsigned & col) {
|
||||||
return has_show(opts, "show_hole", line, col);
|
return has_show(opts, "show_hole", line, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
options set_show_info(options const & opts, unsigned line, unsigned col) {
|
||||||
|
return set_line_col(opts.update(name("show_info"), true), line, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_show_info(options const & opts, unsigned & line, unsigned & col) {
|
||||||
|
return has_show(opts, "show_info", line, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_lean_info_header(std::ostream & out) {
|
||||||
|
out << "LEAN_INFORMATION\n";
|
||||||
|
}
|
||||||
|
void print_lean_info_footer(std::ostream & out) {
|
||||||
|
out << "END_LEAN_INFORMATION\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,4 +15,10 @@ bool has_show_goal(options const & opts, unsigned & line, unsigned & col);
|
||||||
|
|
||||||
options set_show_hole(options const & _opts, unsigned line, unsigned col);
|
options set_show_hole(options const & _opts, unsigned line, unsigned col);
|
||||||
bool has_show_hole(options const & opts, unsigned & line, unsigned & col);
|
bool has_show_hole(options const & opts, unsigned & line, unsigned & col);
|
||||||
|
|
||||||
|
options set_show_info(options const & opts, unsigned line, unsigned col);
|
||||||
|
bool has_show_info(options const & opts, unsigned & line, unsigned & col);
|
||||||
|
|
||||||
|
void print_lean_info_header(std::ostream & out);
|
||||||
|
void print_lean_info_footer(std::ostream & out);
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ Author: Leonardo de Moura
|
||||||
#include "frontends/lean/update_environment_exception.h"
|
#include "frontends/lean/update_environment_exception.h"
|
||||||
#include "frontends/lean/local_ref_info.h"
|
#include "frontends/lean/local_ref_info.h"
|
||||||
#include "frontends/lean/opt_cmd.h"
|
#include "frontends/lean/opt_cmd.h"
|
||||||
|
#include "frontends/lean/builtin_cmds.h"
|
||||||
|
|
||||||
#ifndef LEAN_DEFAULT_PARSER_SHOW_ERRORS
|
#ifndef LEAN_DEFAULT_PARSER_SHOW_ERRORS
|
||||||
#define LEAN_DEFAULT_PARSER_SHOW_ERRORS true
|
#define LEAN_DEFAULT_PARSER_SHOW_ERRORS true
|
||||||
|
@ -105,12 +106,16 @@ static name * g_tmp_prefix = nullptr;
|
||||||
|
|
||||||
void parser::init_stop_at(options const & opts) {
|
void parser::init_stop_at(options const & opts) {
|
||||||
unsigned col;
|
unsigned col;
|
||||||
|
m_info_at = false;
|
||||||
|
m_stop_at = false;
|
||||||
if (has_show_goal(opts, m_stop_at_line, col)) {
|
if (has_show_goal(opts, m_stop_at_line, col)) {
|
||||||
m_stop_at = true;
|
m_stop_at = true;
|
||||||
} else if (has_show_hole(opts, m_stop_at_line, col)) {
|
} else if (has_show_hole(opts, m_stop_at_line, col)) {
|
||||||
m_stop_at = true;
|
m_stop_at = true;
|
||||||
} else {
|
} else if (has_show_info(opts, m_info_at_line, m_info_at_col)) {
|
||||||
m_stop_at = false;
|
m_info_at = true;
|
||||||
|
m_stop_at = true;
|
||||||
|
m_stop_at_line = m_info_at_line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,6 +167,39 @@ parser::~parser() {
|
||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void parser::scan() {
|
||||||
|
if (m_info_at) {
|
||||||
|
m_curr = m_scanner.scan(m_env);
|
||||||
|
pos_info p = pos();
|
||||||
|
if (p.first == m_info_at_line) {
|
||||||
|
if (curr_is_identifier()) {
|
||||||
|
name const & id = get_name_val();
|
||||||
|
if (p.second <= m_info_at_col && m_info_at_col < p.second + id.size()) {
|
||||||
|
print_lean_info_header(regular_stream().get_stream());
|
||||||
|
try {
|
||||||
|
bool show_value = false;
|
||||||
|
print_id_info(*this, id, show_value, p);
|
||||||
|
} catch (exception &) {}
|
||||||
|
print_lean_info_footer(regular_stream().get_stream());
|
||||||
|
m_info_at = false;
|
||||||
|
}
|
||||||
|
} else if (curr_is_keyword()) {
|
||||||
|
name const & tk = get_token_info().token();
|
||||||
|
if (p.second <= m_info_at_col && m_info_at_col < p.second + tk.size()) {
|
||||||
|
print_lean_info_header(regular_stream().get_stream());
|
||||||
|
try {
|
||||||
|
print_token_info(*this, tk);
|
||||||
|
} catch (exception &) {}
|
||||||
|
print_lean_info_footer(regular_stream().get_stream());
|
||||||
|
m_info_at = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_curr = m_scanner.scan(m_env);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void parser::cache_definition(name const & n, expr const & pre_type, expr const & pre_value,
|
void parser::cache_definition(name const & n, expr const & pre_type, expr const & pre_value,
|
||||||
level_param_names const & ls, expr const & type, expr const & value) {
|
level_param_names const & ls, expr const & type, expr const & value) {
|
||||||
if (m_cache)
|
if (m_cache)
|
||||||
|
@ -1278,25 +1316,59 @@ expr parser::id_to_expr(name const & id, pos_info const & p) {
|
||||||
return *r;
|
return *r;
|
||||||
}
|
}
|
||||||
|
|
||||||
list<name> parser::to_constants(name const & id, char const * msg, pos_info const & p) {
|
list<name> parser::to_constants(name const & id, char const * msg, pos_info const & p) const {
|
||||||
expr e = id_to_expr(id, p);
|
|
||||||
|
|
||||||
buffer<name> rs;
|
buffer<name> rs;
|
||||||
std::function<void(expr const & e)> visit = [&](expr const & e) {
|
|
||||||
|
std::function<void(expr const & e)> extract_names = [&](expr const & e) {
|
||||||
if (in_section(m_env) && is_as_atomic(e)) {
|
if (in_section(m_env) && is_as_atomic(e)) {
|
||||||
visit(get_app_fn(get_as_atomic_arg(e)));
|
extract_names(get_app_fn(get_as_atomic_arg(e)));
|
||||||
} else if (is_explicit(e)) {
|
} else if (is_explicit(e)) {
|
||||||
visit(get_explicit_arg(e));
|
extract_names(get_explicit_arg(e));
|
||||||
} else if (is_choice(e)) {
|
} else if (is_choice(e)) {
|
||||||
for (unsigned i = 0; i < get_num_choices(e); i++)
|
for (unsigned i = 0; i < get_num_choices(e); i++)
|
||||||
visit(get_choice(e, i));
|
extract_names(get_choice(e, i));
|
||||||
} else if (is_constant(e)) {
|
} else if (is_constant(e)) {
|
||||||
rs.push_back(const_name(e));
|
rs.push_back(const_name(e));
|
||||||
} else {
|
} else {
|
||||||
throw parser_error(msg, p);
|
throw parser_error(msg, p);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
visit(e);
|
|
||||||
|
// locals
|
||||||
|
if (auto it1 = m_local_decls.find(id)) {
|
||||||
|
extract_names(*it1);
|
||||||
|
return to_list(rs);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (name const & ns : get_namespaces(m_env)) {
|
||||||
|
auto new_id = ns + id;
|
||||||
|
if (!ns.is_anonymous() && m_env.find(new_id) &&
|
||||||
|
(!id.is_atomic() || !is_protected(m_env, new_id))) {
|
||||||
|
return to_list(new_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!id.is_atomic()) {
|
||||||
|
name new_id = id;
|
||||||
|
new_id = remove_root_prefix(new_id);
|
||||||
|
if (m_env.find(new_id))
|
||||||
|
return to_list(new_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer<expr> alts;
|
||||||
|
// globals
|
||||||
|
if (m_env.find(id))
|
||||||
|
rs.push_back(id);
|
||||||
|
// aliases
|
||||||
|
auto as = get_expr_aliases(m_env, id);
|
||||||
|
for (name const & n : as) {
|
||||||
|
rs.push_back(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rs.empty()) {
|
||||||
|
throw parser_error(sstream() << "unknown identifier '" << id << "'", p);
|
||||||
|
}
|
||||||
|
|
||||||
return to_list(rs);
|
return to_list(rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -147,9 +147,12 @@ class parser {
|
||||||
// auxiliary field used to record the size of m_local_decls before a command is executed.
|
// auxiliary field used to record the size of m_local_decls before a command is executed.
|
||||||
unsigned m_local_decls_size_at_beg_cmd;
|
unsigned m_local_decls_size_at_beg_cmd;
|
||||||
|
|
||||||
// stop at line/col
|
// stop/info at line/col
|
||||||
bool m_stop_at; // if true, then parser stops execution after the given line and column is reached
|
bool m_stop_at; // if true, then parser stops execution after the given line and column is reached
|
||||||
unsigned m_stop_at_line;
|
unsigned m_stop_at_line;
|
||||||
|
bool m_info_at;
|
||||||
|
unsigned m_info_at_line;
|
||||||
|
unsigned m_info_at_col;
|
||||||
|
|
||||||
// If the following flag is true we do not raise error messages
|
// If the following flag is true we do not raise error messages
|
||||||
// noncomputable definitions not tagged as noncomputable.
|
// noncomputable definitions not tagged as noncomputable.
|
||||||
|
@ -332,7 +335,7 @@ public:
|
||||||
bool in_theorem_queue(name const & n) const { return m_theorem_queue_set.contains(n); }
|
bool in_theorem_queue(name const & n) const { return m_theorem_queue_set.contains(n); }
|
||||||
|
|
||||||
/** \brief Read the next token. */
|
/** \brief Read the next token. */
|
||||||
void scan() { m_curr = m_scanner.scan(m_env); }
|
void scan();
|
||||||
/** \brief Return the current token */
|
/** \brief Return the current token */
|
||||||
scanner::token_kind curr() const { return m_curr; }
|
scanner::token_kind curr() const { return m_curr; }
|
||||||
/** \brief Return true iff the current token is an identifier */
|
/** \brief Return true iff the current token is an identifier */
|
||||||
|
@ -370,7 +373,7 @@ public:
|
||||||
/** \brief Check if the current token is an atomic identifier, if it is, return it and move to next token,
|
/** \brief Check if the current token is an atomic identifier, if it is, return it and move to next token,
|
||||||
otherwise throw an exception. */
|
otherwise throw an exception. */
|
||||||
name check_atomic_id_next(char const * msg);
|
name check_atomic_id_next(char const * msg);
|
||||||
list<name> to_constants(name const & id, char const * msg, pos_info const & p);
|
list<name> to_constants(name const & id, char const * msg, pos_info const & p) const;
|
||||||
name to_constant(name const & id, char const * msg, pos_info const & p);
|
name to_constant(name const & id, char const * msg, pos_info const & p);
|
||||||
/** \brief Check if the current token is a constant, if it is, return it and move to next token, otherwise throw an exception. */
|
/** \brief Check if the current token is a constant, if it is, return it and move to next token, otherwise throw an exception. */
|
||||||
name check_constant_next(char const * msg);
|
name check_constant_next(char const * msg);
|
||||||
|
|
|
@ -61,6 +61,9 @@ add_test(NAME "issue_755"
|
||||||
add_test(NAME "show_goal_bag"
|
add_test(NAME "show_goal_bag"
|
||||||
WORKING_DIRECTORY "${LEAN_SOURCE_DIR}/../tests/lean/extra"
|
WORKING_DIRECTORY "${LEAN_SOURCE_DIR}/../tests/lean/extra"
|
||||||
COMMAND bash "./show_goal_bag.sh" "${CMAKE_CURRENT_BINARY_DIR}/lean")
|
COMMAND bash "./show_goal_bag.sh" "${CMAKE_CURRENT_BINARY_DIR}/lean")
|
||||||
|
add_test(NAME "print_info"
|
||||||
|
WORKING_DIRECTORY "${LEAN_SOURCE_DIR}/../tests/lean/extra"
|
||||||
|
COMMAND bash "./print_info.sh" "${CMAKE_CURRENT_BINARY_DIR}/lean")
|
||||||
if (NOT(${CMAKE_SYSTEM_NAME} MATCHES "Windows"))
|
if (NOT(${CMAKE_SYSTEM_NAME} MATCHES "Windows"))
|
||||||
# The following test cannot be executed on Windows because of the
|
# The following test cannot be executed on Windows because of the
|
||||||
# bash script timeout.sh
|
# bash script timeout.sh
|
||||||
|
|
|
@ -131,6 +131,8 @@ static void display_help(std::ostream & out) {
|
||||||
std::cout << " --col=value column 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 << " --goal display goal at close to given position\n";
|
||||||
std::cout << " --hole display type of the \"hole\" in the given posivition\n";
|
std::cout << " --hole display type of the \"hole\" in the given posivition\n";
|
||||||
|
std::cout << " --info display information about identifier or token in the given posivition\n";
|
||||||
|
std::cout << "Exporting data:\n";
|
||||||
std::cout << " --export=file -E export final environment as textual low-level file\n";
|
std::cout << " --export=file -E export final environment as textual low-level file\n";
|
||||||
std::cout << " --export-all=file -A export final environment (and all dependencies) as textual low-level file\n";
|
std::cout << " --export-all=file -A export final environment (and all dependencies) as textual low-level file\n";
|
||||||
}
|
}
|
||||||
|
@ -183,10 +185,11 @@ static struct option g_long_options[] = {
|
||||||
{"col", required_argument, 0, 'O'},
|
{"col", required_argument, 0, 'O'},
|
||||||
{"goal", no_argument, 0, 'G'},
|
{"goal", no_argument, 0, 'G'},
|
||||||
{"hole", no_argument, 0, 'Z'},
|
{"hole", no_argument, 0, 'Z'},
|
||||||
|
{"info", no_argument, 0, 'I'},
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define OPT_STR "PHRXFdD:qrlupgvhk:012t:012o:E:c:i:L:012O:012GZA"
|
#define OPT_STR "PHRXFdD:qrlupgvhk:012t:012o:E:c:i:L:012O:012GZAI"
|
||||||
|
|
||||||
#if defined(LEAN_TRACK_MEMORY)
|
#if defined(LEAN_TRACK_MEMORY)
|
||||||
#define OPT_STR2 OPT_STR "M:012"
|
#define OPT_STR2 OPT_STR "M:012"
|
||||||
|
@ -266,6 +269,7 @@ int main(int argc, char ** argv) {
|
||||||
optional<std::string> export_all_txt;
|
optional<std::string> export_all_txt;
|
||||||
bool show_goal = false;
|
bool show_goal = false;
|
||||||
bool show_hole = false;
|
bool show_hole = false;
|
||||||
|
bool show_info = false;
|
||||||
input_kind default_k = input_kind::Unspecified;
|
input_kind default_k = input_kind::Unspecified;
|
||||||
while (true) {
|
while (true) {
|
||||||
int c = getopt_long(argc, argv, g_opt_str, g_long_options, NULL);
|
int c = getopt_long(argc, argv, g_opt_str, g_long_options, NULL);
|
||||||
|
@ -368,6 +372,9 @@ int main(int argc, char ** argv) {
|
||||||
case 'Z':
|
case 'Z':
|
||||||
show_hole = true;
|
show_hole = true;
|
||||||
break;
|
break;
|
||||||
|
case 'I':
|
||||||
|
show_info = true;
|
||||||
|
break;
|
||||||
case 'E':
|
case 'E':
|
||||||
export_txt = std::string(optarg);
|
export_txt = std::string(optarg);
|
||||||
break;
|
break;
|
||||||
|
@ -381,16 +388,18 @@ int main(int argc, char ** argv) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (show_hole && line && column) {
|
|
||||||
opts = set_show_hole(opts, *line, *column);
|
|
||||||
save_cache = false;
|
|
||||||
}
|
|
||||||
#if defined(__GNUC__) && !defined(__CLANG__)
|
#if defined(__GNUC__) && !defined(__CLANG__)
|
||||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||||
#endif
|
#endif
|
||||||
if (show_goal && line && column) {
|
if (show_hole && line && column) {
|
||||||
|
opts = set_show_hole(opts, *line, *column);
|
||||||
|
save_cache = false;
|
||||||
|
} else if (show_goal && line && column) {
|
||||||
opts = set_show_goal(opts, *line, *column);
|
opts = set_show_goal(opts, *line, *column);
|
||||||
save_cache = false;
|
save_cache = false;
|
||||||
|
} else if (show_info && line && column) {
|
||||||
|
opts = set_show_info(opts, *line, *column);
|
||||||
|
save_cache = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(LEAN_MULTI_THREAD)
|
#if !defined(LEAN_MULTI_THREAD)
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
definition category.id [reducible] : Π {ob : Type} [C : precategory ob] {a : ob}, hom a a :=
|
definition category.id [reducible] : Π {ob : Type} [C : precategory ob] {a : ob}, hom a a :=
|
||||||
ID
|
ID
|
||||||
|
|
||||||
definition function.id [reducible] : Π {A : Type}, A → A :=
|
definition function.id [reducible] : Π {A : Type}, A → A :=
|
||||||
λ (A : Type) (a : A), a
|
λ (A : Type) (a : A), a
|
||||||
-----------
|
-----------
|
||||||
definition category.id [reducible] : Π {ob : Type} [C : precategory ob] {a : ob}, hom a a
|
definition category.id [reducible] : Π {ob : Type} [C : precategory ob] {a : ob}, hom a a
|
||||||
ID
|
ID
|
||||||
|
|
||||||
definition function.id [reducible] : Π {A : Type}, A → A
|
definition function.id [reducible] : Π {A : Type}, A → A
|
||||||
λ (A : Type) (a : A), a
|
λ (A : Type) (a : A), a
|
||||||
|
|
6
tests/lean/extra/print_info.12.19.expected.out
Normal file
6
tests/lean/extra/print_info.12.19.expected.out
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
LEAN_INFORMATION
|
||||||
|
definition int.mul : ℤ → ℤ → ℤ
|
||||||
|
|
||||||
|
definition nat.mul : ℕ → ℕ → ℕ
|
||||||
|
END_LEAN_INFORMATION
|
||||||
|
print_info.lean:13:8: warning: using 'sorry'
|
6
tests/lean/extra/print_info.12.20.expected.out
Normal file
6
tests/lean/extra/print_info.12.20.expected.out
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
LEAN_INFORMATION
|
||||||
|
definition int.mul : ℤ → ℤ → ℤ
|
||||||
|
|
||||||
|
definition nat.mul : ℕ → ℕ → ℕ
|
||||||
|
END_LEAN_INFORMATION
|
||||||
|
print_info.lean:13:8: warning: using 'sorry'
|
1
tests/lean/extra/print_info.12.30.expected.out
Normal file
1
tests/lean/extra/print_info.12.30.expected.out
Normal file
|
@ -0,0 +1 @@
|
||||||
|
print_info.lean:13:8: warning: using 'sorry'
|
4
tests/lean/extra/print_info.17.0.expected.out
Normal file
4
tests/lean/extra/print_info.17.0.expected.out
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
print_info.lean:13:8: warning: using 'sorry'
|
||||||
|
LEAN_INFORMATION
|
||||||
|
definition rfl : ∀ {A : Type} {a : A}, a = a
|
||||||
|
END_LEAN_INFORMATION
|
4
tests/lean/extra/print_info.17.2.expected.out
Normal file
4
tests/lean/extra/print_info.17.2.expected.out
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
print_info.lean:13:8: warning: using 'sorry'
|
||||||
|
LEAN_INFORMATION
|
||||||
|
definition rfl : ∀ {A : Type} {a : A}, a = a
|
||||||
|
END_LEAN_INFORMATION
|
6
tests/lean/extra/print_info.4.16.expected.out
Normal file
6
tests/lean/extra/print_info.4.16.expected.out
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
LEAN_INFORMATION
|
||||||
|
inductive nat : Type₁
|
||||||
|
constructors:
|
||||||
|
nat.zero : ℕ
|
||||||
|
nat.succ : ℕ → ℕ
|
||||||
|
END_LEAN_INFORMATION
|
5
tests/lean/extra/print_info.7.18.expected.out
Normal file
5
tests/lean/extra/print_info.7.18.expected.out
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
LEAN_INFORMATION
|
||||||
|
definition int.add : ℤ → ℤ → ℤ
|
||||||
|
|
||||||
|
definition nat.add : ℕ → ℕ → ℕ
|
||||||
|
END_LEAN_INFORMATION
|
5
tests/lean/extra/print_info.8.19.expected.out
Normal file
5
tests/lean/extra/print_info.8.19.expected.out
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
LEAN_INFORMATION
|
||||||
|
_ `+`:65 _:65 :=
|
||||||
|
| nat.add #1 #0
|
||||||
|
| [priority 999] int.add #1 #0
|
||||||
|
END_LEAN_INFORMATION
|
17
tests/lean/extra/print_info.lean
Normal file
17
tests/lean/extra/print_info.lean
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import data.int
|
||||||
|
open nat int
|
||||||
|
|
||||||
|
variables a b : nat
|
||||||
|
variables i j : int
|
||||||
|
|
||||||
|
definition foo := add a i
|
||||||
|
definition f₁ := a + i
|
||||||
|
|
||||||
|
example (n : nat) : n + n = 2 * n :=
|
||||||
|
begin
|
||||||
|
unfold [nat.add,mul],
|
||||||
|
apply sorry
|
||||||
|
end
|
||||||
|
|
||||||
|
example (n : nat) : n + n = n + n :=
|
||||||
|
rfl
|
34
tests/lean/extra/print_info.sh
Executable file
34
tests/lean/extra/print_info.sh
Executable file
|
@ -0,0 +1,34 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
echo "Usage: print_info.sh [lean-executable-path]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
LEAN=$1
|
||||||
|
export LEAN_PATH=../../../library:.
|
||||||
|
|
||||||
|
lines=('4' '7' '8' '12' '12' '12' '17' '17');
|
||||||
|
cols=('16' '18' '19' '19' '20' '30' '0' '2');
|
||||||
|
size=${#lines[@]}
|
||||||
|
|
||||||
|
i=0
|
||||||
|
while [ $i -lt $size ]; do
|
||||||
|
line=${lines[$i]}
|
||||||
|
col=${cols[$i]}
|
||||||
|
let i=i+1
|
||||||
|
produced=print_info.$line.$col.produced.out
|
||||||
|
expected=print_info.$line.$col.expected.out
|
||||||
|
$LEAN --line=$line --col=$col --info print_info.lean &> $produced
|
||||||
|
if test -f $expected; then
|
||||||
|
if diff --ignore-all-space -I "executing external script" "$produced" "$expected"; then
|
||||||
|
echo "-- checked"
|
||||||
|
else
|
||||||
|
echo "ERROR: file $produced does not match $expected"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "ERROR: file $expected does not exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "done"
|
Loading…
Reference in a new issue