refactor(frontends/lean/builtin_cmds): move declaration commands to new file
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
3bb53810c5
commit
461689f758
7 changed files with 367 additions and 300 deletions
|
@ -1,6 +1,7 @@
|
||||||
add_library(lean_frontend register_module.cpp token_table.cpp
|
add_library(lean_frontend register_module.cpp token_table.cpp
|
||||||
scanner.cpp parse_table.cpp parser_config.cpp parser.cpp
|
scanner.cpp parse_table.cpp parser_config.cpp parser.cpp
|
||||||
parser_pos_provider.cpp builtin_cmds.cpp builtin_tactic_cmds.cpp
|
parser_pos_provider.cpp builtin_cmds.cpp builtin_tactic_cmds.cpp
|
||||||
builtin_exprs.cpp interactive.cpp notation_cmd.cpp calc.cpp)
|
builtin_exprs.cpp interactive.cpp notation_cmd.cpp calc.cpp
|
||||||
|
decl_cmds.cpp util.cpp)
|
||||||
|
|
||||||
target_link_libraries(lean_frontend ${LEAN_LIBS})
|
target_link_libraries(lean_frontend ${LEAN_LIBS})
|
||||||
|
|
|
@ -11,20 +11,15 @@ Author: Leonardo de Moura
|
||||||
#include "library/io_state_stream.h"
|
#include "library/io_state_stream.h"
|
||||||
#include "library/scoped_ext.h"
|
#include "library/scoped_ext.h"
|
||||||
#include "library/aliases.h"
|
#include "library/aliases.h"
|
||||||
#include "library/private.h"
|
|
||||||
#include "library/locals.h"
|
#include "library/locals.h"
|
||||||
|
#include "frontends/lean/util.h"
|
||||||
#include "frontends/lean/parser.h"
|
#include "frontends/lean/parser.h"
|
||||||
#include "frontends/lean/calc.h"
|
#include "frontends/lean/calc.h"
|
||||||
#include "frontends/lean/notation_cmd.h"
|
#include "frontends/lean/notation_cmd.h"
|
||||||
|
#include "frontends/lean/decl_cmds.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
static name g_raw("raw");
|
static name g_raw("raw");
|
||||||
static name g_llevel_curly(".{");
|
|
||||||
static name g_rcurly("}");
|
|
||||||
static name g_colon(":");
|
|
||||||
static name g_assign(":=");
|
|
||||||
static name g_private("[private]");
|
|
||||||
static name g_inline("[inline]");
|
|
||||||
static name g_true("true");
|
static name g_true("true");
|
||||||
static name g_false("false");
|
static name g_false("false");
|
||||||
static name g_options("options");
|
static name g_options("options");
|
||||||
|
@ -38,285 +33,6 @@ static name g_decls("decls");
|
||||||
static name g_hiding("hiding");
|
static name g_hiding("hiding");
|
||||||
static name g_renaming("renaming");
|
static name g_renaming("renaming");
|
||||||
|
|
||||||
static void check_atomic(name const & n) {
|
|
||||||
if (!n.is_atomic())
|
|
||||||
throw exception(sstream() << "invalid declaration name '" << n << "', identifier must be atomic");
|
|
||||||
}
|
|
||||||
|
|
||||||
environment universe_cmd(parser & p) {
|
|
||||||
name n = p.check_id_next("invalid universe declaration, identifier expected");
|
|
||||||
check_atomic(n);
|
|
||||||
environment env = p.env();
|
|
||||||
if (in_section(env)) {
|
|
||||||
p.add_local_level(n, mk_param_univ(n));
|
|
||||||
} else {
|
|
||||||
name const & ns = get_namespace(env);
|
|
||||||
name full_n = ns + n;
|
|
||||||
env = module::add_universe(env, full_n);
|
|
||||||
if (!ns.is_anonymous())
|
|
||||||
env = add_alias(env, n, mk_global_univ(full_n));
|
|
||||||
}
|
|
||||||
return env;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void check_in_section(parser const & p) {
|
|
||||||
if (!in_section(p.env()))
|
|
||||||
throw exception(sstream() << "invalid command, it must be used in a section");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void parse_univ_params(parser & p, buffer<name> & ps) {
|
|
||||||
if (p.curr_is_token(g_llevel_curly)) {
|
|
||||||
p.next();
|
|
||||||
while (!p.curr_is_token(g_rcurly)) {
|
|
||||||
name l = p.check_id_next("invalid universe parameter, identifier expected");
|
|
||||||
p.add_local_level(l, mk_param_univ(l));
|
|
||||||
ps.push_back(l);
|
|
||||||
}
|
|
||||||
p.next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void update_parameters(buffer<name> & ls_buffer, name_set const & found, parser const & p) {
|
|
||||||
unsigned old_sz = ls_buffer.size();
|
|
||||||
found.for_each([&](name const & n) {
|
|
||||||
if (std::find(ls_buffer.begin(), ls_buffer.begin() + old_sz, n) == ls_buffer.begin() + old_sz)
|
|
||||||
ls_buffer.push_back(n);
|
|
||||||
});
|
|
||||||
std::sort(ls_buffer.begin(), ls_buffer.end(), [&](name const & n1, name const & n2) {
|
|
||||||
return p.get_local_level_index(n1) < p.get_local_level_index(n2);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static environment declare_var(parser & p, environment env,
|
|
||||||
name const & n, level_param_names const & ls, expr const & type,
|
|
||||||
bool is_axiom, binder_info const & bi, pos_info const & pos) {
|
|
||||||
if (in_section(p.env())) {
|
|
||||||
p.add_local_expr(n, p.save_pos(mk_local(n, type), pos), bi);
|
|
||||||
return env;
|
|
||||||
} else {
|
|
||||||
name const & ns = get_namespace(env);
|
|
||||||
name full_n = ns + n;
|
|
||||||
if (is_axiom)
|
|
||||||
env = module::add(env, check(env, mk_axiom(full_n, ls, type)));
|
|
||||||
else
|
|
||||||
env = module::add(env, check(env, mk_var_decl(full_n, ls, type)));
|
|
||||||
if (!ns.is_anonymous())
|
|
||||||
env = add_alias(env, n, mk_constant(full_n));
|
|
||||||
return env;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static environment variable_cmd_core(parser & p, bool is_axiom, binder_info const & bi) {
|
|
||||||
auto pos = p.pos();
|
|
||||||
name n = p.check_id_next("invalid declaration, identifier expected");
|
|
||||||
check_atomic(n);
|
|
||||||
buffer<name> ls_buffer;
|
|
||||||
if (p.curr_is_token(g_llevel_curly) && in_section(p.env()))
|
|
||||||
throw parser_error("invalid declaration, axioms/parameters occurring in sections cannot be universe polymorphic", p.pos());
|
|
||||||
optional<parser::local_scope> scope1;
|
|
||||||
if (!in_section(p.env()))
|
|
||||||
scope1.emplace(p);
|
|
||||||
parse_univ_params(p, ls_buffer);
|
|
||||||
parser::param_universe_scope scope2(p);
|
|
||||||
expr type;
|
|
||||||
if (!p.curr_is_token(g_colon)) {
|
|
||||||
buffer<parameter> ps;
|
|
||||||
auto lenv = p.parse_binders(ps);
|
|
||||||
p.check_token_next(g_colon, "invalid declaration, ':' expected");
|
|
||||||
type = p.parse_scoped_expr(ps, lenv);
|
|
||||||
type = p.pi_abstract(ps, type);
|
|
||||||
} else {
|
|
||||||
p.next();
|
|
||||||
type = p.parse_expr();
|
|
||||||
}
|
|
||||||
level_param_names ls;
|
|
||||||
if (in_section(p.env())) {
|
|
||||||
ls = to_level_param_names(collect_univ_params(type));
|
|
||||||
} else {
|
|
||||||
update_parameters(ls_buffer, collect_univ_params(type), p);
|
|
||||||
ls = to_list(ls_buffer.begin(), ls_buffer.end());
|
|
||||||
}
|
|
||||||
type = p.elaborate(type, ls);
|
|
||||||
return declare_var(p, p.env(), n, ls, type, is_axiom, bi, pos);
|
|
||||||
}
|
|
||||||
environment variable_cmd(parser & p) {
|
|
||||||
return variable_cmd_core(p, false, binder_info());
|
|
||||||
}
|
|
||||||
environment axiom_cmd(parser & p) {
|
|
||||||
return variable_cmd_core(p, true, binder_info());
|
|
||||||
}
|
|
||||||
environment implicit_variable_cmd(parser & p) {
|
|
||||||
check_in_section(p);
|
|
||||||
return variable_cmd_core(p, false, mk_implicit_binder_info());
|
|
||||||
}
|
|
||||||
environment implicit_axiom_cmd(parser & p) {
|
|
||||||
check_in_section(p);
|
|
||||||
return variable_cmd_core(p, true, mk_implicit_binder_info());
|
|
||||||
}
|
|
||||||
environment cast_variable_cmd(parser & p) {
|
|
||||||
check_in_section(p);
|
|
||||||
return variable_cmd_core(p, false, mk_cast_binder_info());
|
|
||||||
}
|
|
||||||
|
|
||||||
static environment variables_cmd_core(parser & p, bool is_axiom, binder_info const & bi) {
|
|
||||||
auto pos = p.pos();
|
|
||||||
buffer<name> ids;
|
|
||||||
while (!p.curr_is_token(g_colon)) {
|
|
||||||
name id = p.check_id_next("invalid parameters declaration, identifier expected");
|
|
||||||
check_atomic(id);
|
|
||||||
ids.push_back(id);
|
|
||||||
}
|
|
||||||
p.next();
|
|
||||||
optional<parser::local_scope> scope1;
|
|
||||||
if (!in_section(p.env()))
|
|
||||||
scope1.emplace(p);
|
|
||||||
parser::param_universe_scope scope2(p);
|
|
||||||
expr type = p.parse_expr();
|
|
||||||
level_param_names ls = to_level_param_names(collect_univ_params(type));
|
|
||||||
type = p.elaborate(type, ls);
|
|
||||||
environment env = p.env();
|
|
||||||
for (auto id : ids)
|
|
||||||
env = declare_var(p, env, id, ls, type, is_axiom, bi, pos);
|
|
||||||
return env;
|
|
||||||
}
|
|
||||||
environment variables_cmd(parser & p) {
|
|
||||||
return variables_cmd_core(p, false, binder_info());
|
|
||||||
}
|
|
||||||
environment implicit_variables_cmd(parser & p) {
|
|
||||||
check_in_section(p);
|
|
||||||
return variables_cmd_core(p, false, mk_implicit_binder_info());
|
|
||||||
}
|
|
||||||
environment cast_variables_cmd(parser & p) {
|
|
||||||
check_in_section(p);
|
|
||||||
return variables_cmd_core(p, false, mk_cast_binder_info());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect local (section) constants occurring in type and value, sort them, and store in section_ps
|
|
||||||
static void collect_section_locals(expr const & type, expr const & value, parser const & p, buffer<parameter> & section_ps) {
|
|
||||||
name_set ls = collect_locals(type, collect_locals(value));
|
|
||||||
ls.for_each([&](name const & n) {
|
|
||||||
section_ps.push_back(*p.get_local(n));
|
|
||||||
});
|
|
||||||
std::sort(section_ps.begin(), section_ps.end(), [&](parameter const & p1, parameter const & p2) {
|
|
||||||
return p.get_local_index(mlocal_name(p1.m_local)) < p.get_local_index(mlocal_name(p2.m_local));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static void parse_modifiers(parser & p, bool & is_private, bool & is_opaque) {
|
|
||||||
while (true) {
|
|
||||||
if (p.curr_is_token(g_private)) {
|
|
||||||
is_private = true;
|
|
||||||
p.next();
|
|
||||||
} else if (p.curr_is_token(g_inline)) {
|
|
||||||
is_opaque = false;
|
|
||||||
p.next();
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrap \c e with the "explicit macro", the idea is to inform the elaborator
|
|
||||||
// preprocessor, that we do not need create metavariables for implicit arguments
|
|
||||||
static expr mark_explicit(expr const & e) {
|
|
||||||
// TODO(Leo)
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
environment definition_cmd_core(parser & p, bool is_theorem, bool is_opaque) {
|
|
||||||
bool is_private = false;
|
|
||||||
parse_modifiers(p, is_private, is_opaque);
|
|
||||||
if (is_theorem && !is_opaque)
|
|
||||||
throw exception("invalid theorem declaration, theorems cannot be transparent");
|
|
||||||
name n = p.check_id_next("invalid declaration, identifier expected");
|
|
||||||
check_atomic(n);
|
|
||||||
environment env = p.env();
|
|
||||||
name real_n; // real name for this declaration
|
|
||||||
if (is_private) {
|
|
||||||
auto env_n = add_private_name(env, n, optional<unsigned>(hash(p.pos().first, p.pos().second)));
|
|
||||||
env = env_n.first;
|
|
||||||
real_n = env_n.second;
|
|
||||||
} else {
|
|
||||||
name const & ns = get_namespace(env);
|
|
||||||
real_n = ns + n;
|
|
||||||
}
|
|
||||||
buffer<name> ls_buffer;
|
|
||||||
expr type, value;
|
|
||||||
level_param_names ls;
|
|
||||||
{
|
|
||||||
parser::local_scope scope1(p);
|
|
||||||
parse_univ_params(p, ls_buffer);
|
|
||||||
if (!p.curr_is_token(g_colon)) {
|
|
||||||
buffer<parameter> ps;
|
|
||||||
optional<local_environment> lenv;
|
|
||||||
{
|
|
||||||
parser::param_universe_scope scope2(p);
|
|
||||||
lenv = p.parse_binders(ps);
|
|
||||||
p.check_token_next(g_colon, "invalid declaration, ':' expected");
|
|
||||||
type = p.parse_scoped_expr(ps, *lenv);
|
|
||||||
}
|
|
||||||
p.check_token_next(g_assign, "invalid declaration, ':=' expected");
|
|
||||||
value = p.parse_scoped_expr(ps, *lenv);
|
|
||||||
type = p.pi_abstract(ps, type);
|
|
||||||
value = p.lambda_abstract(ps, value);
|
|
||||||
} else {
|
|
||||||
p.next();
|
|
||||||
{
|
|
||||||
parser::param_universe_scope scope2(p);
|
|
||||||
type = p.parse_expr();
|
|
||||||
}
|
|
||||||
p.check_token_next(g_assign, "invalid declaration, ':=' expected");
|
|
||||||
value = p.parse_expr();
|
|
||||||
}
|
|
||||||
update_parameters(ls_buffer, collect_univ_params(value, collect_univ_params(type)), p);
|
|
||||||
ls = to_list(ls_buffer.begin(), ls_buffer.end());
|
|
||||||
}
|
|
||||||
if (in_section(env)) {
|
|
||||||
buffer<parameter> section_ps;
|
|
||||||
collect_section_locals(type, value, p, section_ps);
|
|
||||||
type = p.pi_abstract(section_ps, type);
|
|
||||||
value = p.lambda_abstract(section_ps, value);
|
|
||||||
buffer<level> section_ls_buffer;
|
|
||||||
for (name const & l : ls) {
|
|
||||||
if (p.get_local_level_index(l))
|
|
||||||
section_ls_buffer.push_back(mk_param_univ(l));
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
levels section_ls = to_list(section_ls_buffer.begin(), section_ls_buffer.end());
|
|
||||||
buffer<expr> section_args;
|
|
||||||
for (auto const & p : section_ps)
|
|
||||||
section_args.push_back(p.m_local);
|
|
||||||
expr ref = mk_app(mark_explicit(mk_constant(real_n, section_ls)), section_args);
|
|
||||||
p.add_local_expr(n, ref);
|
|
||||||
} else {
|
|
||||||
if (real_n != n)
|
|
||||||
env = add_alias(env, n, mk_constant(real_n));
|
|
||||||
}
|
|
||||||
if (is_theorem) {
|
|
||||||
// TODO(Leo): delay theorems
|
|
||||||
auto type_value = p.elaborate(type, value, ls);
|
|
||||||
type = type_value.first;
|
|
||||||
value = type_value.second;
|
|
||||||
env = module::add(env, check(env, mk_theorem(real_n, ls, type, value)));
|
|
||||||
} else {
|
|
||||||
auto type_value = p.elaborate(type, value, ls);
|
|
||||||
type = type_value.first;
|
|
||||||
value = type_value.second;
|
|
||||||
env = module::add(env, check(env, mk_definition(env, real_n, ls, type, value, is_opaque)));
|
|
||||||
}
|
|
||||||
return env;
|
|
||||||
}
|
|
||||||
environment definition_cmd(parser & p) {
|
|
||||||
return definition_cmd_core(p, false, true);
|
|
||||||
}
|
|
||||||
environment abbreviation_cmd(parser & p) {
|
|
||||||
return definition_cmd_core(p, false, false);
|
|
||||||
}
|
|
||||||
environment theorem_cmd(parser & p) {
|
|
||||||
return definition_cmd_core(p, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
environment print_cmd(parser & p) {
|
environment print_cmd(parser & p) {
|
||||||
if (p.curr() == scanner::token_kind::String) {
|
if (p.curr() == scanner::token_kind::String) {
|
||||||
p.regular_stream() << p.get_str_val() << endl;
|
p.regular_stream() << p.get_str_val() << endl;
|
||||||
|
@ -495,23 +211,12 @@ cmd_table init_cmd_table() {
|
||||||
add_cmd(r, cmd_info("set_option", "set configuration option", set_option_cmd));
|
add_cmd(r, cmd_info("set_option", "set configuration option", set_option_cmd));
|
||||||
add_cmd(r, cmd_info("exit", "exit", exit_cmd));
|
add_cmd(r, cmd_info("exit", "exit", exit_cmd));
|
||||||
add_cmd(r, cmd_info("print", "print a string", print_cmd));
|
add_cmd(r, cmd_info("print", "print a string", print_cmd));
|
||||||
add_cmd(r, cmd_info("universe", "declare a global universe level", universe_cmd));
|
|
||||||
add_cmd(r, cmd_info("section", "open a new section", section_cmd));
|
add_cmd(r, cmd_info("section", "open a new section", section_cmd));
|
||||||
add_cmd(r, cmd_info("namespace", "open a new namespace", namespace_cmd));
|
add_cmd(r, cmd_info("namespace", "open a new namespace", namespace_cmd));
|
||||||
add_cmd(r, cmd_info("end", "close the current namespace/section", end_scoped_cmd));
|
add_cmd(r, cmd_info("end", "close the current namespace/section", end_scoped_cmd));
|
||||||
add_cmd(r, cmd_info("variable", "declare a new parameter", variable_cmd));
|
|
||||||
add_cmd(r, cmd_info("{variable}", "declare a new implict parameter", implicit_variable_cmd));
|
|
||||||
add_cmd(r, cmd_info("[variable]", "declare a new cast parameter", cast_variable_cmd));
|
|
||||||
add_cmd(r, cmd_info("axiom", "declare a new axiom", axiom_cmd));
|
|
||||||
add_cmd(r, cmd_info("{axiom}", "declare a new implicit axiom", implicit_axiom_cmd));
|
|
||||||
add_cmd(r, cmd_info("variables", "declare new parameters", variables_cmd));
|
|
||||||
add_cmd(r, cmd_info("{variables}", "declare new implict parameters", implicit_variables_cmd));
|
|
||||||
add_cmd(r, cmd_info("[variables]", "declare new cast parameters", cast_variables_cmd));
|
|
||||||
add_cmd(r, cmd_info("definition", "add new definition", definition_cmd));
|
|
||||||
add_cmd(r, cmd_info("abbreviation", "add new abbreviation (aka transparent definition)", abbreviation_cmd));
|
|
||||||
add_cmd(r, cmd_info("theorem", "add new theorem", theorem_cmd));
|
|
||||||
add_cmd(r, cmd_info("check", "type check given expression, and display its type", check_cmd));
|
add_cmd(r, cmd_info("check", "type check given expression, and display its type", check_cmd));
|
||||||
add_cmd(r, cmd_info("#setline", "modify the current line number, it only affects error/report messages", set_line_cmd));
|
add_cmd(r, cmd_info("#setline", "modify the current line number, it only affects error/report messages", set_line_cmd));
|
||||||
|
register_decl_cmds(r);
|
||||||
register_notation_cmds(r);
|
register_notation_cmds(r);
|
||||||
register_calc_cmds(r);
|
register_calc_cmds(r);
|
||||||
return r;
|
return r;
|
||||||
|
|
|
@ -18,6 +18,7 @@ Author: Leonardo de Moura
|
||||||
#include "library/choice.h"
|
#include "library/choice.h"
|
||||||
#include "library/placeholder.h"
|
#include "library/placeholder.h"
|
||||||
#include "frontends/lean/parser.h"
|
#include "frontends/lean/parser.h"
|
||||||
|
#include "frontends/lean/util.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
struct calc_ext : public environment_extension {
|
struct calc_ext : public environment_extension {
|
||||||
|
@ -211,7 +212,7 @@ static void decode_expr(expr const & e, buffer<calc_pred> & preds, pos_info cons
|
||||||
|
|
||||||
// Create (op _ _ ... _)
|
// Create (op _ _ ... _)
|
||||||
static expr mk_op_fn(parser & p, name const & op, unsigned num_placeholders, pos_info const & pos) {
|
static expr mk_op_fn(parser & p, name const & op, unsigned num_placeholders, pos_info const & pos) {
|
||||||
expr r = p.save_pos(mk_constant(op), pos);
|
expr r = p.save_pos(mark_explicit(mk_constant(op)), pos);
|
||||||
while (num_placeholders > 0) {
|
while (num_placeholders > 0) {
|
||||||
num_placeholders--;
|
num_placeholders--;
|
||||||
r = p.mk_app(r, p.save_pos(mk_expr_placeholder(), pos), pos);
|
r = p.mk_app(r, p.save_pos(mk_expr_placeholder(), pos), pos);
|
||||||
|
|
301
src/frontends/lean/decl_cmds.cpp
Normal file
301
src/frontends/lean/decl_cmds.cpp
Normal file
|
@ -0,0 +1,301 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
||||||
|
Released under Apache 2.0 license as described in the file LICENSE.
|
||||||
|
|
||||||
|
Author: Leonardo de Moura
|
||||||
|
*/
|
||||||
|
#include <algorithm>
|
||||||
|
#include "util/sstream.h"
|
||||||
|
#include "kernel/type_checker.h"
|
||||||
|
#include "library/scoped_ext.h"
|
||||||
|
#include "library/aliases.h"
|
||||||
|
#include "library/private.h"
|
||||||
|
#include "library/locals.h"
|
||||||
|
#include "frontends/lean/parser.h"
|
||||||
|
#include "frontends/lean/util.h"
|
||||||
|
|
||||||
|
namespace lean {
|
||||||
|
static name g_llevel_curly(".{");
|
||||||
|
static name g_rcurly("}");
|
||||||
|
static name g_colon(":");
|
||||||
|
static name g_assign(":=");
|
||||||
|
static name g_private("[private]");
|
||||||
|
static name g_inline("[inline]");
|
||||||
|
|
||||||
|
environment universe_cmd(parser & p) {
|
||||||
|
name n = p.check_id_next("invalid universe declaration, identifier expected");
|
||||||
|
check_atomic(n);
|
||||||
|
environment env = p.env();
|
||||||
|
if (in_section(env)) {
|
||||||
|
p.add_local_level(n, mk_param_univ(n));
|
||||||
|
} else {
|
||||||
|
name const & ns = get_namespace(env);
|
||||||
|
name full_n = ns + n;
|
||||||
|
env = module::add_universe(env, full_n);
|
||||||
|
if (!ns.is_anonymous())
|
||||||
|
env = add_alias(env, n, mk_global_univ(full_n));
|
||||||
|
}
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_univ_params(parser & p, buffer<name> & ps) {
|
||||||
|
if (p.curr_is_token(g_llevel_curly)) {
|
||||||
|
p.next();
|
||||||
|
while (!p.curr_is_token(g_rcurly)) {
|
||||||
|
name l = p.check_id_next("invalid universe parameter, identifier expected");
|
||||||
|
p.add_local_level(l, mk_param_univ(l));
|
||||||
|
ps.push_back(l);
|
||||||
|
}
|
||||||
|
p.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_parameters(buffer<name> & ls_buffer, name_set const & found, parser const & p) {
|
||||||
|
unsigned old_sz = ls_buffer.size();
|
||||||
|
found.for_each([&](name const & n) {
|
||||||
|
if (std::find(ls_buffer.begin(), ls_buffer.begin() + old_sz, n) == ls_buffer.begin() + old_sz)
|
||||||
|
ls_buffer.push_back(n);
|
||||||
|
});
|
||||||
|
std::sort(ls_buffer.begin(), ls_buffer.end(), [&](name const & n1, name const & n2) {
|
||||||
|
return p.get_local_level_index(n1) < p.get_local_level_index(n2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static environment declare_var(parser & p, environment env,
|
||||||
|
name const & n, level_param_names const & ls, expr const & type,
|
||||||
|
bool is_axiom, binder_info const & bi, pos_info const & pos) {
|
||||||
|
if (in_section(p.env())) {
|
||||||
|
p.add_local_expr(n, p.save_pos(mk_local(n, type), pos), bi);
|
||||||
|
return env;
|
||||||
|
} else {
|
||||||
|
name const & ns = get_namespace(env);
|
||||||
|
name full_n = ns + n;
|
||||||
|
if (is_axiom)
|
||||||
|
env = module::add(env, check(env, mk_axiom(full_n, ls, type)));
|
||||||
|
else
|
||||||
|
env = module::add(env, check(env, mk_var_decl(full_n, ls, type)));
|
||||||
|
if (!ns.is_anonymous())
|
||||||
|
env = add_alias(env, n, mk_constant(full_n));
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
environment variable_cmd_core(parser & p, bool is_axiom, binder_info const & bi) {
|
||||||
|
auto pos = p.pos();
|
||||||
|
name n = p.check_id_next("invalid declaration, identifier expected");
|
||||||
|
check_atomic(n);
|
||||||
|
buffer<name> ls_buffer;
|
||||||
|
if (p.curr_is_token(g_llevel_curly) && in_section(p.env()))
|
||||||
|
throw parser_error("invalid declaration, axioms/parameters occurring in sections cannot be universe polymorphic", p.pos());
|
||||||
|
optional<parser::local_scope> scope1;
|
||||||
|
if (!in_section(p.env()))
|
||||||
|
scope1.emplace(p);
|
||||||
|
parse_univ_params(p, ls_buffer);
|
||||||
|
parser::param_universe_scope scope2(p);
|
||||||
|
expr type;
|
||||||
|
if (!p.curr_is_token(g_colon)) {
|
||||||
|
buffer<parameter> ps;
|
||||||
|
auto lenv = p.parse_binders(ps);
|
||||||
|
p.check_token_next(g_colon, "invalid declaration, ':' expected");
|
||||||
|
type = p.parse_scoped_expr(ps, lenv);
|
||||||
|
type = p.pi_abstract(ps, type);
|
||||||
|
} else {
|
||||||
|
p.next();
|
||||||
|
type = p.parse_expr();
|
||||||
|
}
|
||||||
|
level_param_names ls;
|
||||||
|
if (in_section(p.env())) {
|
||||||
|
ls = to_level_param_names(collect_univ_params(type));
|
||||||
|
} else {
|
||||||
|
update_parameters(ls_buffer, collect_univ_params(type), p);
|
||||||
|
ls = to_list(ls_buffer.begin(), ls_buffer.end());
|
||||||
|
}
|
||||||
|
type = p.elaborate(type, ls);
|
||||||
|
return declare_var(p, p.env(), n, ls, type, is_axiom, bi, pos);
|
||||||
|
}
|
||||||
|
environment variable_cmd(parser & p) {
|
||||||
|
return variable_cmd_core(p, false, binder_info());
|
||||||
|
}
|
||||||
|
environment axiom_cmd(parser & p) {
|
||||||
|
return variable_cmd_core(p, true, binder_info());
|
||||||
|
}
|
||||||
|
environment implicit_variable_cmd(parser & p) {
|
||||||
|
check_in_section(p);
|
||||||
|
return variable_cmd_core(p, false, mk_implicit_binder_info());
|
||||||
|
}
|
||||||
|
environment implicit_axiom_cmd(parser & p) {
|
||||||
|
check_in_section(p);
|
||||||
|
return variable_cmd_core(p, true, mk_implicit_binder_info());
|
||||||
|
}
|
||||||
|
environment cast_variable_cmd(parser & p) {
|
||||||
|
check_in_section(p);
|
||||||
|
return variable_cmd_core(p, false, mk_cast_binder_info());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect local (section) constants occurring in type and value, sort them, and store in section_ps
|
||||||
|
void collect_section_locals(expr const & type, expr const & value, parser const & p, buffer<parameter> & section_ps) {
|
||||||
|
name_set ls = collect_locals(type, collect_locals(value));
|
||||||
|
ls.for_each([&](name const & n) {
|
||||||
|
section_ps.push_back(*p.get_local(n));
|
||||||
|
});
|
||||||
|
std::sort(section_ps.begin(), section_ps.end(), [&](parameter const & p1, parameter const & p2) {
|
||||||
|
return p.get_local_index(mlocal_name(p1.m_local)) < p.get_local_index(mlocal_name(p2.m_local));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_modifiers(parser & p, bool & is_private, bool & is_opaque) {
|
||||||
|
while (true) {
|
||||||
|
if (p.curr_is_token(g_private)) {
|
||||||
|
is_private = true;
|
||||||
|
p.next();
|
||||||
|
} else if (p.curr_is_token(g_inline)) {
|
||||||
|
is_opaque = false;
|
||||||
|
p.next();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
environment definition_cmd_core(parser & p, bool is_theorem, bool is_opaque) {
|
||||||
|
bool is_private = false;
|
||||||
|
parse_modifiers(p, is_private, is_opaque);
|
||||||
|
if (is_theorem && !is_opaque)
|
||||||
|
throw exception("invalid theorem declaration, theorems cannot be transparent");
|
||||||
|
name n = p.check_id_next("invalid declaration, identifier expected");
|
||||||
|
check_atomic(n);
|
||||||
|
environment env = p.env();
|
||||||
|
name real_n; // real name for this declaration
|
||||||
|
if (is_private) {
|
||||||
|
auto env_n = add_private_name(env, n, optional<unsigned>(hash(p.pos().first, p.pos().second)));
|
||||||
|
env = env_n.first;
|
||||||
|
real_n = env_n.second;
|
||||||
|
} else {
|
||||||
|
name const & ns = get_namespace(env);
|
||||||
|
real_n = ns + n;
|
||||||
|
}
|
||||||
|
buffer<name> ls_buffer;
|
||||||
|
expr type, value;
|
||||||
|
level_param_names ls;
|
||||||
|
{
|
||||||
|
parser::local_scope scope1(p);
|
||||||
|
parse_univ_params(p, ls_buffer);
|
||||||
|
if (!p.curr_is_token(g_colon)) {
|
||||||
|
buffer<parameter> ps;
|
||||||
|
optional<local_environment> lenv;
|
||||||
|
{
|
||||||
|
parser::param_universe_scope scope2(p);
|
||||||
|
lenv = p.parse_binders(ps);
|
||||||
|
p.check_token_next(g_colon, "invalid declaration, ':' expected");
|
||||||
|
type = p.parse_scoped_expr(ps, *lenv);
|
||||||
|
}
|
||||||
|
p.check_token_next(g_assign, "invalid declaration, ':=' expected");
|
||||||
|
value = p.parse_scoped_expr(ps, *lenv);
|
||||||
|
type = p.pi_abstract(ps, type);
|
||||||
|
value = p.lambda_abstract(ps, value);
|
||||||
|
} else {
|
||||||
|
p.next();
|
||||||
|
{
|
||||||
|
parser::param_universe_scope scope2(p);
|
||||||
|
type = p.parse_expr();
|
||||||
|
}
|
||||||
|
p.check_token_next(g_assign, "invalid declaration, ':=' expected");
|
||||||
|
value = p.parse_expr();
|
||||||
|
}
|
||||||
|
update_parameters(ls_buffer, collect_univ_params(value, collect_univ_params(type)), p);
|
||||||
|
ls = to_list(ls_buffer.begin(), ls_buffer.end());
|
||||||
|
}
|
||||||
|
if (in_section(env)) {
|
||||||
|
buffer<parameter> section_ps;
|
||||||
|
collect_section_locals(type, value, p, section_ps);
|
||||||
|
type = p.pi_abstract(section_ps, type);
|
||||||
|
value = p.lambda_abstract(section_ps, value);
|
||||||
|
buffer<level> section_ls_buffer;
|
||||||
|
for (name const & l : ls) {
|
||||||
|
if (p.get_local_level_index(l))
|
||||||
|
section_ls_buffer.push_back(mk_param_univ(l));
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
levels section_ls = to_list(section_ls_buffer.begin(), section_ls_buffer.end());
|
||||||
|
buffer<expr> section_args;
|
||||||
|
for (auto const & p : section_ps)
|
||||||
|
section_args.push_back(p.m_local);
|
||||||
|
expr ref = mk_app(mark_explicit(mk_constant(real_n, section_ls)), section_args);
|
||||||
|
p.add_local_expr(n, ref);
|
||||||
|
} else {
|
||||||
|
if (real_n != n)
|
||||||
|
env = add_alias(env, n, mk_constant(real_n));
|
||||||
|
}
|
||||||
|
if (is_theorem) {
|
||||||
|
// TODO(Leo): delay theorems
|
||||||
|
auto type_value = p.elaborate(type, value, ls);
|
||||||
|
type = type_value.first;
|
||||||
|
value = type_value.second;
|
||||||
|
env = module::add(env, check(env, mk_theorem(real_n, ls, type, value)));
|
||||||
|
} else {
|
||||||
|
auto type_value = p.elaborate(type, value, ls);
|
||||||
|
type = type_value.first;
|
||||||
|
value = type_value.second;
|
||||||
|
env = module::add(env, check(env, mk_definition(env, real_n, ls, type, value, is_opaque)));
|
||||||
|
}
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
environment definition_cmd(parser & p) {
|
||||||
|
return definition_cmd_core(p, false, true);
|
||||||
|
}
|
||||||
|
environment abbreviation_cmd(parser & p) {
|
||||||
|
return definition_cmd_core(p, false, false);
|
||||||
|
}
|
||||||
|
environment theorem_cmd(parser & p) {
|
||||||
|
return definition_cmd_core(p, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static environment variables_cmd_core(parser & p, bool is_axiom, binder_info const & bi) {
|
||||||
|
auto pos = p.pos();
|
||||||
|
buffer<name> ids;
|
||||||
|
while (!p.curr_is_token(g_colon)) {
|
||||||
|
name id = p.check_id_next("invalid parameters declaration, identifier expected");
|
||||||
|
check_atomic(id);
|
||||||
|
ids.push_back(id);
|
||||||
|
}
|
||||||
|
p.next();
|
||||||
|
optional<parser::local_scope> scope1;
|
||||||
|
if (!in_section(p.env()))
|
||||||
|
scope1.emplace(p);
|
||||||
|
parser::param_universe_scope scope2(p);
|
||||||
|
expr type = p.parse_expr();
|
||||||
|
level_param_names ls = to_level_param_names(collect_univ_params(type));
|
||||||
|
type = p.elaborate(type, ls);
|
||||||
|
environment env = p.env();
|
||||||
|
for (auto id : ids)
|
||||||
|
env = declare_var(p, env, id, ls, type, is_axiom, bi, pos);
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
environment variables_cmd(parser & p) {
|
||||||
|
return variables_cmd_core(p, false, binder_info());
|
||||||
|
}
|
||||||
|
environment implicit_variables_cmd(parser & p) {
|
||||||
|
check_in_section(p);
|
||||||
|
return variables_cmd_core(p, false, mk_implicit_binder_info());
|
||||||
|
}
|
||||||
|
environment cast_variables_cmd(parser & p) {
|
||||||
|
check_in_section(p);
|
||||||
|
return variables_cmd_core(p, false, mk_cast_binder_info());
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_decl_cmds(cmd_table & r) {
|
||||||
|
add_cmd(r, cmd_info("universe", "declare a global universe level", universe_cmd));
|
||||||
|
add_cmd(r, cmd_info("variable", "declare a new parameter", variable_cmd));
|
||||||
|
add_cmd(r, cmd_info("{variable}", "declare a new implict parameter", implicit_variable_cmd));
|
||||||
|
add_cmd(r, cmd_info("[variable]", "declare a new cast parameter", cast_variable_cmd));
|
||||||
|
add_cmd(r, cmd_info("axiom", "declare a new axiom", axiom_cmd));
|
||||||
|
add_cmd(r, cmd_info("{axiom}", "declare a new implicit axiom", implicit_axiom_cmd));
|
||||||
|
add_cmd(r, cmd_info("definition", "add new definition", definition_cmd));
|
||||||
|
add_cmd(r, cmd_info("abbreviation", "add new abbreviation (aka transparent definition)", abbreviation_cmd));
|
||||||
|
add_cmd(r, cmd_info("theorem", "add new theorem", theorem_cmd));
|
||||||
|
add_cmd(r, cmd_info("variables", "declare new parameters", variables_cmd));
|
||||||
|
add_cmd(r, cmd_info("{variables}", "declare new implict parameters", implicit_variables_cmd));
|
||||||
|
add_cmd(r, cmd_info("[variables]", "declare new cast parameters", cast_variables_cmd));
|
||||||
|
}
|
||||||
|
}
|
17
src/frontends/lean/decl_cmds.h
Normal file
17
src/frontends/lean/decl_cmds.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
||||||
|
Released under Apache 2.0 license as described in the file LICENSE.
|
||||||
|
|
||||||
|
Author: Leonardo de Moura
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "util/buffer.h"
|
||||||
|
#include "kernel/expr.h"
|
||||||
|
#include "frontends/lean/cmd_table.h"
|
||||||
|
namespace lean {
|
||||||
|
class parser;
|
||||||
|
void parse_univ_params(parser & p, buffer<name> & ps);
|
||||||
|
void update_parameters(buffer<name> & ls_buffer, name_set const & found, parser const & p);
|
||||||
|
void collect_section_locals(expr const & type, expr const & value, parser const & p, buffer<parameter> & section_ps);
|
||||||
|
void register_decl_cmds(cmd_table & r);
|
||||||
|
}
|
28
src/frontends/lean/util.cpp
Normal file
28
src/frontends/lean/util.cpp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
||||||
|
Released under Apache 2.0 license as described in the file LICENSE.
|
||||||
|
|
||||||
|
Author: Leonardo de Moura
|
||||||
|
*/
|
||||||
|
#include "util/sstream.h"
|
||||||
|
#include "library/scoped_ext.h"
|
||||||
|
#include "frontends/lean/parser.h"
|
||||||
|
|
||||||
|
namespace lean {
|
||||||
|
void check_atomic(name const & n) {
|
||||||
|
if (!n.is_atomic())
|
||||||
|
throw exception(sstream() << "invalid declaration name '" << n << "', identifier must be atomic");
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_in_section(parser const & p) {
|
||||||
|
if (!in_section(p.env()))
|
||||||
|
throw exception(sstream() << "invalid command, it must be used in a section");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap \c e with the "explicit macro", the idea is to inform the elaborator
|
||||||
|
// preprocessor, that we do not need create metavariables for implicit arguments
|
||||||
|
expr mark_explicit(expr const & e) {
|
||||||
|
// TODO(Leo)
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
14
src/frontends/lean/util.h
Normal file
14
src/frontends/lean/util.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2014 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/expr.h"
|
||||||
|
namespace lean {
|
||||||
|
class parser;
|
||||||
|
void check_atomic(name const & n);
|
||||||
|
void check_in_section(parser const & p);
|
||||||
|
expr mark_explicit(expr const & e);
|
||||||
|
}
|
Loading…
Reference in a new issue