feat(frontends/lean): import error message for "unknown" tactics when parsing

This commit is contained in:
Leonardo de Moura 2015-05-02 18:57:58 -07:00
parent 118189eaac
commit 441f1f9fe2
7 changed files with 36 additions and 20 deletions

View file

@ -124,7 +124,6 @@ static expr parse_placeholder(parser & p, unsigned, expr const *, pos_info const
} }
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::undef_id_to_local_scope scope(p);
p.next(); p.next();
expr t = p.parse_tactic(); expr t = p.parse_tactic();
return p.mk_by(t, pos); return p.mk_by(t, pos);
@ -133,7 +132,6 @@ static expr parse_by(parser & p, unsigned, expr const *, pos_info const & pos) {
static expr parse_begin_end_core(parser & p, pos_info const & pos, name const & end_token, bool nested = false) { static expr parse_begin_end_core(parser & p, pos_info const & pos, name const & end_token, bool nested = false) {
if (!p.has_tactic_decls()) if (!p.has_tactic_decls())
throw parser_error("invalid 'begin-end' expression, tactic module has not been imported", pos); throw parser_error("invalid 'begin-end' expression, tactic module has not been imported", pos);
parser::undef_id_to_local_scope scope1(p);
p.next(); p.next();
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;
@ -171,7 +169,7 @@ static expr parse_begin_end_core(parser & p, pos_info const & pos, name const &
p.next(); p.next();
name id = p.check_id_next("invalid 'assert' tactic, identifier expected"); name id = p.check_id_next("invalid 'assert' tactic, identifier expected");
p.check_token_next(get_colon_tk(), "invalid 'assert' tactic, ':' expected"); p.check_token_next(get_colon_tk(), "invalid 'assert' tactic, ':' expected");
expr A = p.parse_expr(); expr A = p.parse_tactic_expr_arg();
expr assert_tac = p.save_pos(mk_assert_tactic_expr(id, A), pos); expr assert_tac = p.save_pos(mk_assert_tactic_expr(id, A), pos);
tacs.push_back(mk_begin_end_element_annotation(assert_tac)); tacs.push_back(mk_begin_end_element_annotation(assert_tac));
} else if (p.curr_is_token(get_have_tk())) { } else if (p.curr_is_token(get_have_tk())) {
@ -180,7 +178,7 @@ static expr parse_begin_end_core(parser & p, pos_info const & pos, name const &
auto id_pos = p.pos(); auto id_pos = p.pos();
name id = p.check_id_next("invalid 'have' tactic, identifier expected"); name id = p.check_id_next("invalid 'have' tactic, identifier expected");
p.check_token_next(get_colon_tk(), "invalid 'have' tactic, ':' expected"); p.check_token_next(get_colon_tk(), "invalid 'have' tactic, ':' expected");
expr A = p.parse_expr(); expr A = p.parse_tactic_expr_arg();
expr assert_tac = p.save_pos(mk_assert_tactic_expr(id, A), pos); expr assert_tac = p.save_pos(mk_assert_tactic_expr(id, A), pos);
tacs.push_back(mk_begin_end_element_annotation(assert_tac)); tacs.push_back(mk_begin_end_element_annotation(assert_tac));
if (p.curr_is_token(get_bar_tk())) { if (p.curr_is_token(get_bar_tk())) {
@ -196,7 +194,7 @@ static expr parse_begin_end_core(parser & p, pos_info const & pos, name const &
// parse: 'from' expr // parse: 'from' expr
p.next(); p.next();
auto pos = p.pos(); auto pos = p.pos();
expr t = p.parse_expr(); expr t = p.parse_tactic_expr_arg();
t = p.mk_app(get_rexact_tac_fn(), t, pos); t = p.mk_app(get_rexact_tac_fn(), t, pos);
t = p.save_pos(mk_begin_end_element_annotation(t), pos); t = p.save_pos(mk_begin_end_element_annotation(t), pos);
t = p.save_pos(mk_begin_end_annotation(t), pos); t = p.save_pos(mk_begin_end_annotation(t), pos);
@ -204,7 +202,7 @@ static expr parse_begin_end_core(parser & p, pos_info const & pos, name const &
} else if (p.curr_is_token(get_proof_tk())) { } else if (p.curr_is_token(get_proof_tk())) {
auto pos = p.pos(); auto pos = p.pos();
p.next(); p.next();
expr t = p.parse_expr(); expr t = p.parse_tactic_expr_arg();
p.check_token_next(get_qed_tk(), "invalid proof-qed, 'qed' expected"); p.check_token_next(get_qed_tk(), "invalid proof-qed, 'qed' expected");
t = p.mk_app(get_rexact_tac_fn(), t, pos); t = p.mk_app(get_rexact_tac_fn(), t, pos);
t = p.save_pos(mk_begin_end_element_annotation(t), pos); t = p.save_pos(mk_begin_end_element_annotation(t), pos);
@ -225,13 +223,13 @@ static expr parse_begin_end_core(parser & p, pos_info const & pos, name const &
} }
} else if (p.curr_is_token(get_show_tk())) { } else if (p.curr_is_token(get_show_tk())) {
auto pos = p.pos(); auto pos = p.pos();
expr t = p.parse_expr(); expr t = p.parse_tactic_expr_arg();
t = p.mk_app(get_rexact_tac_fn(), t, pos); t = p.mk_app(get_rexact_tac_fn(), t, pos);
add_tac(t, pos); add_tac(t, pos);
} else if (p.curr_is_token(get_match_tk()) || p.curr_is_token(get_assume_tk()) || } else if (p.curr_is_token(get_match_tk()) || p.curr_is_token(get_assume_tk()) ||
p.curr_is_token(get_take_tk()) || p.curr_is_token(get_fun_tk())) { p.curr_is_token(get_take_tk()) || p.curr_is_token(get_fun_tk())) {
auto pos = p.pos(); auto pos = p.pos();
expr t = p.parse_expr(); expr t = p.parse_tactic_expr_arg();
t = p.mk_app(get_exact_tac_fn(), t, pos); t = p.mk_app(get_exact_tac_fn(), t, pos);
add_tac(t, pos); add_tac(t, pos);
} else { } else {

View file

@ -35,12 +35,12 @@ static expr parse_rparen(parser &, unsigned, expr const * args, pos_info const &
static expr parse_let_tactic(parser & p, unsigned, expr const *, pos_info const & pos) { static expr parse_let_tactic(parser & p, unsigned, expr const *, pos_info const & pos) {
name id = p.check_atomic_id_next("invalid 'let' tactic, identifier expected"); name id = p.check_atomic_id_next("invalid 'let' tactic, identifier expected");
p.check_token_next(get_assign_tk(), "invalid 'let' tactic, ':=' expected"); p.check_token_next(get_assign_tk(), "invalid 'let' tactic, ':=' expected");
expr value = p.parse_expr(); expr value = p.parse_tactic_expr_arg();
return p.save_pos(mk_let_tactic_expr(id, value), pos); return p.save_pos(mk_let_tactic_expr(id, value), pos);
} }
static expr parse_generalize_tactic(parser & p, unsigned, expr const *, pos_info const & pos) { static expr parse_generalize_tactic(parser & p, unsigned, expr const *, pos_info const & pos) {
expr e = p.parse_expr(); expr e = p.parse_tactic_expr_arg();
name id; name id;
if (p.curr_is_token(get_as_tk())) { if (p.curr_is_token(get_as_tk())) {
p.next(); p.next();

View file

@ -13,7 +13,7 @@ namespace lean {
static optional<expr> parse_pattern(parser & p) { static optional<expr> parse_pattern(parser & p) {
if (p.curr_is_token(get_lcurly_tk())) { if (p.curr_is_token(get_lcurly_tk())) {
p.next(); p.next();
expr r = p.parse_expr(); expr r = p.parse_tactic_expr_arg();
p.check_token_next(get_rcurly_tk(), "invalid rewrite pattern, '}' expected"); p.check_token_next(get_rcurly_tk(), "invalid rewrite pattern, '}' expected");
return some_expr(r); return some_expr(r);
} else { } else {
@ -25,14 +25,14 @@ static expr parse_rule(parser & p, bool use_paren) {
if (use_paren) { if (use_paren) {
if (p.curr_is_token(get_lparen_tk())) { if (p.curr_is_token(get_lparen_tk())) {
p.next(); p.next();
expr r = p.parse_expr(); expr r = p.parse_tactic_expr_arg();
p.check_token_next(get_rparen_tk(), "invalid rewrite pattern, ')' expected"); p.check_token_next(get_rparen_tk(), "invalid rewrite pattern, ')' expected");
return r; return r;
} else { } else {
return p.parse_id(); return p.parse_tactic_id_arg();
} }
} else { } else {
return p.parse_expr(); return p.parse_tactic_expr_arg();
} }
} }
@ -66,7 +66,7 @@ static expr parse_rewrite_element(parser & p, bool use_paren) {
return parse_rewrite_unfold(p); return parse_rewrite_unfold(p);
if (p.curr_is_token(get_down_tk())) { if (p.curr_is_token(get_down_tk())) {
p.next(); p.next();
expr e = p.parse_expr(); expr e = p.parse_tactic_expr_arg();
location loc = parse_tactic_location(p); location loc = parse_tactic_location(p);
return mk_rewrite_fold(e, loc); return mk_rewrite_fold(e, loc);
} }
@ -108,7 +108,7 @@ static expr parse_rewrite_element(parser & p, bool use_paren) {
location loc = parse_tactic_location(p); location loc = parse_tactic_location(p);
return mk_rewrite_reduce(loc); return mk_rewrite_reduce(loc);
} else { } else {
expr e = p.parse_expr(); expr e = p.parse_tactic_expr_arg();
location loc = parse_tactic_location(p); location loc = parse_tactic_location(p);
return mk_rewrite_reduce_to(e, loc); return mk_rewrite_reduce_to(e, loc);
} }
@ -175,7 +175,7 @@ expr parse_fold_tactic(parser & p) {
p.next(); p.next();
while (true) { while (true) {
auto pos = p.pos(); auto pos = p.pos();
expr e = p.parse_expr(); expr e = p.parse_tactic_expr_arg();
location loc = parse_tactic_location(p); location loc = parse_tactic_location(p);
elems.push_back(p.save_pos(mk_rewrite_fold(e, loc), pos)); elems.push_back(p.save_pos(mk_rewrite_fold(e, loc), pos));
if (!p.curr_is_token(get_comma_tk())) if (!p.curr_is_token(get_comma_tk()))
@ -184,7 +184,7 @@ expr parse_fold_tactic(parser & p) {
} }
p.check_token_next(get_rbracket_tk(), "invalid 'fold' tactic, ',' or ']' expected"); p.check_token_next(get_rbracket_tk(), "invalid 'fold' tactic, ',' or ']' expected");
} else { } else {
expr e = p.parse_expr(); expr e = p.parse_tactic_expr_arg();
location loc = parse_tactic_location(p); location loc = parse_tactic_location(p);
elems.push_back(p.save_pos(mk_rewrite_fold(e, loc), pos));; elems.push_back(p.save_pos(mk_rewrite_fold(e, loc), pos));;
} }

View file

@ -1383,6 +1383,16 @@ static bool is_tactic_command_type(expr e) {
return is_tactic_type(e); return is_tactic_type(e);
} }
expr parser::parse_tactic_expr_arg(unsigned rbp) {
parser::undef_id_to_local_scope scope1(*this);
return parse_expr(rbp);
}
expr parser::parse_tactic_id_arg() {
parser::undef_id_to_local_scope scope1(*this);
return parse_id();
}
optional<expr> parser::is_tactic_command(name & id) { optional<expr> parser::is_tactic_command(name & id) {
if (id.is_atomic()) if (id.is_atomic())
id = get_tactic_name() + id; id = get_tactic_name() + id;
@ -1410,7 +1420,7 @@ expr parser::parse_tactic_expr_list() {
check_token_next(get_lbracket_tk(), "invalid tactic, '[' expected"); check_token_next(get_lbracket_tk(), "invalid tactic, '[' expected");
buffer<expr> args; buffer<expr> args;
while (true) { while (true) {
args.push_back(parse_expr()); args.push_back(parse_tactic_expr_arg());
if (!curr_is_token(get_comma_tk())) if (!curr_is_token(get_comma_tk()))
break; break;
next(); next();
@ -1510,7 +1520,7 @@ expr parser::parse_tactic_nud() {
rbp = 0; rbp = 0;
else else
rbp = get_max_prec(); rbp = get_max_prec();
r = mk_app(r, parse_expr(rbp), id_pos); r = mk_app(r, parse_tactic_expr_arg(rbp), id_pos);
} }
} }
return r; return r;

View file

@ -404,6 +404,8 @@ public:
expr parse_scoped_expr(buffer<expr> const & ps, unsigned rbp = 0) { return parse_scoped_expr(ps.size(), ps.data(), rbp); } expr parse_scoped_expr(buffer<expr> const & ps, unsigned rbp = 0) { return parse_scoped_expr(ps.size(), ps.data(), rbp); }
expr parse_tactic(unsigned rbp = 0); expr parse_tactic(unsigned rbp = 0);
expr parse_tactic_expr_arg(unsigned rbp = 0);
expr parse_tactic_id_arg();
struct local_scope { parser & m_p; environment m_env; struct local_scope { parser & m_p; environment m_env;
local_scope(parser & p, bool save_options = false); local_scope(parser & p, bool save_options = false);

View file

@ -0,0 +1,5 @@
example (a b : Prop) : a → b → a ∧ b :=
begin
intros,
splits
end

View file

@ -0,0 +1 @@
tactic_error_msg.lean:4:2: error: unknown identifier 'splits'