fix(frontends/lean/parser): add two kinds of no_undef_id behavior: to (global) constant; to local constant

This commit is contained in:
Leonardo de Moura 2014-10-26 09:47:11 -07:00
parent 50948be66b
commit 8e6de93394
5 changed files with 108 additions and 17 deletions

View file

@ -128,7 +128,7 @@ static environment open_tactic_namespace(parser & p) {
} }
static expr parse_by(parser & p, unsigned, expr const *, pos_info const & pos) { static expr parse_by(parser & p, unsigned, expr const *, pos_info const & pos) {
parser::no_undef_id_error_scope scope(p); parser::undef_id_to_local_scope scope(p);
environment env = open_tactic_namespace(p); environment env = open_tactic_namespace(p);
expr t = p.parse_scoped_expr(0, nullptr, env); expr t = p.parse_scoped_expr(0, nullptr, env);
return p.mk_by(t, pos); return p.mk_by(t, pos);
@ -140,7 +140,7 @@ static expr parse_begin_end_core(parser & p, pos_info const & pos) {
optional<expr> pre_tac = get_begin_end_pre_tactic(p.env()); optional<expr> pre_tac = get_begin_end_pre_tactic(p.env());
buffer<expr> tacs; buffer<expr> tacs;
bool first = true; bool first = true;
parser::no_undef_id_error_scope scope(p); parser::undef_id_to_local_scope scope(p);
environment env = open_tactic_namespace(p); environment env = open_tactic_namespace(p);
while (!p.curr_is_token(get_end_tk())) { while (!p.curr_is_token(get_end_tk())) {
if (first) { if (first) {

View file

@ -698,7 +698,7 @@ struct inductive_cmd_fn {
} }
environment operator()() { environment operator()() {
parser::no_undef_id_error_scope err_scope(m_p); parser::undef_id_to_const_scope err_scope(m_p);
buffer<inductive_decl> decls; buffer<inductive_decl> decls;
{ {
parser::local_scope scope(m_p); parser::local_scope scope(m_p);

View file

@ -75,12 +75,10 @@ parser::local_scope::~local_scope() {
m_p.m_env = m_env; m_p.m_env = m_env;
} }
parser::no_undef_id_error_scope::no_undef_id_error_scope(parser & p):m_p(p), m_old(m_p.m_no_undef_id_error) { parser::undef_id_to_const_scope::undef_id_to_const_scope(parser & p):
m_p.m_no_undef_id_error = true; flet<undef_id_behavior>(p.m_undef_id_behavior, undef_id_behavior::AssumeConstant) {}
} parser::undef_id_to_local_scope::undef_id_to_local_scope(parser & p):
parser::no_undef_id_error_scope::~no_undef_id_error_scope() { flet<undef_id_behavior>(p.m_undef_id_behavior, undef_id_behavior::AssumeLocal) {}
m_p.m_no_undef_id_error = m_old;
}
static name * g_tmp_prefix = nullptr; static name * g_tmp_prefix = nullptr;
@ -104,7 +102,7 @@ parser::parser(environment const & env, io_state const & ios,
m_parser_scope_stack = s->m_parser_scope_stack; m_parser_scope_stack = s->m_parser_scope_stack;
} }
m_num_threads = num_threads; m_num_threads = num_threads;
m_no_undef_id_error = false; m_undef_id_behavior = undef_id_behavior::Error;
m_found_errors = false; m_found_errors = false;
m_used_sorry = false; m_used_sorry = false;
updt_options(); updt_options();
@ -1067,8 +1065,12 @@ expr parser::id_to_expr(name const & id, pos_info const & p) {
r = save_pos(mk_choice(new_as.size(), new_as.data()), p); r = save_pos(mk_choice(new_as.size(), new_as.data()), p);
save_overload(*r); save_overload(*r);
} }
if (!r && m_no_undef_id_error) if (!r) {
r = save_pos(mk_constant(get_namespace(m_env) + id, ls), p); if (m_undef_id_behavior == undef_id_behavior::AssumeConstant)
r = save_pos(mk_constant(get_namespace(m_env) + id, ls), p);
else if (m_undef_id_behavior == undef_id_behavior::AssumeLocal)
r = save_pos(mk_local(id, mk_expr_placeholder()), p);
}
if (!r) if (!r)
throw parser_error(sstream() << "unknown identifier '" << id << "'", p); throw parser_error(sstream() << "unknown identifier '" << id << "'", p);
save_type_info(*r); save_type_info(*r);

View file

@ -8,6 +8,7 @@ Author: Leonardo de Moura
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "util/flet.h"
#include "util/script_state.h" #include "util/script_state.h"
#include "util/name_map.h" #include "util/name_map.h"
#include "util/exception.h" #include "util/exception.h"
@ -80,6 +81,8 @@ typedef std::vector<snapshot> snapshot_vector;
enum class keep_theorem_mode { All, DiscardImported, DiscardAll }; enum class keep_theorem_mode { All, DiscardImported, DiscardAll };
enum class undef_id_behavior { Error, AssumeConstant, AssumeLocal };
class parser { class parser {
environment m_env; environment m_env;
io_state m_ios; io_state m_ios;
@ -105,7 +108,7 @@ class parser {
// By default, when the parser finds a unknown identifier, it signs an error. // By default, when the parser finds a unknown identifier, it signs an error.
// When the following flag is true, it creates a constant. // When the following flag is true, it creates a constant.
// This flag is when we are trying to parse mutually recursive declarations. // This flag is when we are trying to parse mutually recursive declarations.
bool m_no_undef_id_error; undef_id_behavior m_undef_id_behavior;
optional<bool> m_has_num; optional<bool> m_has_num;
optional<bool> m_has_string; optional<bool> m_has_string;
optional<bool> m_has_tactic_decls; optional<bool> m_has_tactic_decls;
@ -371,11 +374,13 @@ public:
/** \brief Return all local level declarations */ /** \brief Return all local level declarations */
list<pair<name, level>> const & get_local_level_entries() const { return m_local_level_decls.get_entries(); } list<pair<name, level>> const & get_local_level_entries() const { return m_local_level_decls.get_entries(); }
/** \brief By default, when the parser finds a unknown identifier, it signs an error. /** \brief By default, when the parser finds a unknown identifier, it signs an error.
This scope object temporarily changes this behavior. In any scope where this object These scope objects temporarily change this behavior. In any scope where this object
is declared, the parse creates a constant even when the identifier is unknown. is declared, the parse creates a constant/local even when the identifier is unknown.
This behavior is useful when we are trying to parse mutually recursive declarations. This behavior is useful when we are trying to parse mutually recursive declarations and
tactics.
*/ */
struct no_undef_id_error_scope { parser & m_p; bool m_old; no_undef_id_error_scope(parser &); ~no_undef_id_error_scope(); }; struct undef_id_to_const_scope : public flet<undef_id_behavior> { undef_id_to_const_scope(parser & p); };
struct undef_id_to_local_scope : public flet<undef_id_behavior> { undef_id_to_local_scope(parser &); };
/** \brief Elaborate \c e, and tolerate metavariables in the result. */ /** \brief Elaborate \c e, and tolerate metavariables in the result. */
std::tuple<expr, level_param_names> elaborate_relaxed(expr const & e, list<expr> const & ctx = list<expr>()); std::tuple<expr, level_param_names> elaborate_relaxed(expr const & e, list<expr> const & ctx = list<expr>());

84
tests/lean/run/tree2.lean Normal file
View file

@ -0,0 +1,84 @@
import logic data.prod
open eq.ops prod tactic
inductive tree (A : Type) :=
leaf : A → tree A,
node : tree A → tree A → tree A
inductive one.{l} : Type.{max 1 l} :=
star : one
set_option pp.universes true
namespace tree
section
universe variables l₁ l₂
variable {A : Type.{l₁}}
variable (C : tree A → Type.{l₂})
definition below (t : tree A) : Type :=
rec_on t (λ a, one.{l₂}) (λ t₁ t₂ r₁ r₂, C t₁ × C t₂ × r₁ × r₂)
end
section
universe variables l₁ l₂
variable {A : Type.{l₁}}
variable {C : tree A → Type.{l₂}}
definition below_rec_on (t : tree A) (H : Π (n : tree A), below C n → C n) : C t
:= have general : C t × below C t, from
rec_on t
(λa, (H (leaf a) one.star, one.star))
(λ (l r : tree A) (Hl : C l × below C l) (Hr : C r × below C r),
have b : below C (node l r), from
(pr₁ Hl, pr₁ Hr, pr₂ Hl, pr₂ Hr),
have c : C (node l r), from
H (node l r) b,
(c, b)),
pr₁ general
end
definition no_confusion_type {A : Type} (P : Type) (t₁ t₂ : tree A) : Type :=
cases_on t₁
(λ a₁, cases_on t₂
(λ a₂, (a₁ = a₂ → P) → P)
(λ l₂ r₂, P))
(λ l₁ r₁, cases_on t₂
(λ a₂, P)
(λ l₂ r₂, (l₁ = l₂ → r₁ = r₂ → P) → P))
set_option pp.universes true
check no_confusion_type
definition no_confusion {A : Type} {P : Type} {t₁ t₂ : tree A} : t₁ = t₂ → no_confusion_type P t₁ t₂ :=
assume e₁ : t₁ = t₂,
have aux₁ : t₁ = t₁ → no_confusion_type P t₁ t₁, from
take h, cases_on t₁
(λ a, assume h : a = a → P, h (eq.refl a))
(λ l r, assume h : l = l → r = r → P, h (eq.refl l) (eq.refl r)),
eq.rec aux₁ e₁ e₁
check no_confusion
theorem leaf_ne_tree {A : Type} (a : A) (l r : tree A) : leaf a ≠ node l r :=
assume h : leaf a = node l r,
no_confusion h
constant A : Type₁
constants l₁ l₂ r₁ r₂ : tree A
axiom node_eq : node l₁ r₁ = node l₂ r₂
check no_confusion node_eq
definition tst : (l₁ = l₂ → r₁ = r₂ → l₁ = l₂) → l₁ = l₂ := no_confusion node_eq
check tst (λ e₁ e₂, e₁)
theorem node.inj1 {A : Type} (l₁ l₂ r₁ r₂ : tree A) : node l₁ r₁ = node l₂ r₂ → l₁ = l₂ :=
assume h,
have trivial : (l₁ = l₂ → r₁ = r₂ → l₁ = l₂) → l₁ = l₂, from no_confusion h,
trivial (λ e₁ e₂, e₁)
theorem node.inj2 {A : Type} (l₁ l₂ r₁ r₂ : tree A) : node l₁ r₁ = node l₂ r₂ → l₁ = l₂ :=
begin
intro h,
apply (no_confusion h),
intros, assumption
end
end tree