2015-02-03 01:02:14 +00:00
|
|
|
/*
|
|
|
|
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
|
|
|
*/
|
|
|
|
#include "library/tactic/rewrite_tactic.h"
|
|
|
|
#include "frontends/lean/parser.h"
|
|
|
|
#include "frontends/lean/tokens.h"
|
|
|
|
#include "frontends/lean/parse_tactic_location.h"
|
|
|
|
|
|
|
|
namespace lean {
|
2015-02-03 03:20:24 +00:00
|
|
|
static optional<expr> parse_pattern(parser & p) {
|
2015-02-05 04:16:24 +00:00
|
|
|
if (p.curr_is_token(get_lcurly_tk())) {
|
2015-02-03 03:20:24 +00:00
|
|
|
p.next();
|
2015-05-03 01:57:58 +00:00
|
|
|
expr r = p.parse_tactic_expr_arg();
|
2015-02-05 04:16:24 +00:00
|
|
|
p.check_token_next(get_rcurly_tk(), "invalid rewrite pattern, '}' expected");
|
2015-02-03 03:20:24 +00:00
|
|
|
return some_expr(r);
|
|
|
|
} else {
|
|
|
|
return none_expr();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-24 03:40:03 +00:00
|
|
|
static expr parse_rule(parser & p, bool use_paren) {
|
|
|
|
if (use_paren) {
|
|
|
|
if (p.curr_is_token(get_lparen_tk())) {
|
|
|
|
p.next();
|
2015-05-03 01:57:58 +00:00
|
|
|
expr r = p.parse_tactic_expr_arg();
|
2015-02-24 03:40:03 +00:00
|
|
|
p.check_token_next(get_rparen_tk(), "invalid rewrite pattern, ')' expected");
|
|
|
|
return r;
|
|
|
|
} else {
|
2015-05-03 01:57:58 +00:00
|
|
|
return p.parse_tactic_id_arg();
|
2015-02-24 03:40:03 +00:00
|
|
|
}
|
2015-02-03 03:20:24 +00:00
|
|
|
} else {
|
2015-05-03 01:57:58 +00:00
|
|
|
return p.parse_tactic_expr_arg();
|
2015-02-03 03:20:24 +00:00
|
|
|
}
|
2015-02-03 01:02:14 +00:00
|
|
|
}
|
|
|
|
|
2015-06-28 18:28:05 +00:00
|
|
|
static void check_not_in_theorem_queue(parser & p, name const & n, pos_info const & pos) {
|
|
|
|
if (p.in_theorem_queue(n)) {
|
|
|
|
throw parser_error(sstream() << "invalid 'rewrite' tactic, cannot unfold '" << n << "' "
|
|
|
|
<< "which is still in the theorem queue. Use command 'reveal " << n << "' "
|
|
|
|
<< "to access its definition.", pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-09 01:08:24 +00:00
|
|
|
static expr parse_rewrite_unfold_core(parser & p, bool force_unfold) {
|
2015-02-06 22:13:32 +00:00
|
|
|
buffer<name> to_unfold;
|
2015-03-28 00:26:06 +00:00
|
|
|
if (p.curr_is_token(get_lbracket_tk())) {
|
2015-02-03 01:02:14 +00:00
|
|
|
p.next();
|
2015-02-06 22:13:32 +00:00
|
|
|
while (true) {
|
2015-06-28 18:28:05 +00:00
|
|
|
auto pos = p.pos();
|
2015-02-06 22:13:32 +00:00
|
|
|
to_unfold.push_back(p.check_constant_next("invalid unfold rewrite step, identifier expected"));
|
2015-06-28 18:28:05 +00:00
|
|
|
check_not_in_theorem_queue(p, to_unfold.back(), pos);
|
2015-02-06 22:13:32 +00:00
|
|
|
if (!p.curr_is_token(get_comma_tk()))
|
|
|
|
break;
|
2015-02-06 19:03:36 +00:00
|
|
|
p.next();
|
|
|
|
}
|
2015-03-28 00:26:06 +00:00
|
|
|
p.check_token_next(get_rbracket_tk(), "invalid unfold rewrite step, ',' or ']' expected");
|
2015-02-06 22:13:32 +00:00
|
|
|
} else {
|
2015-06-28 18:28:05 +00:00
|
|
|
auto pos = p.pos();
|
2015-03-28 00:26:06 +00:00
|
|
|
to_unfold.push_back(p.check_constant_next("invalid unfold rewrite step, identifier or '[' expected"));
|
2015-06-28 18:28:05 +00:00
|
|
|
check_not_in_theorem_queue(p, to_unfold.back(), pos);
|
2015-02-03 01:02:14 +00:00
|
|
|
}
|
2015-02-06 22:13:32 +00:00
|
|
|
location loc = parse_tactic_location(p);
|
2015-07-09 01:08:24 +00:00
|
|
|
return mk_rewrite_unfold(to_list(to_unfold), force_unfold, loc);
|
2015-02-06 22:13:32 +00:00
|
|
|
}
|
|
|
|
|
2015-07-09 01:08:24 +00:00
|
|
|
static expr parse_rewrite_unfold(parser & p, bool force_unfold) {
|
2015-02-13 20:22:17 +00:00
|
|
|
lean_assert(p.curr_is_token(get_up_tk()) || p.curr_is_token(get_caret_tk()));
|
|
|
|
p.next();
|
2015-07-09 01:08:24 +00:00
|
|
|
return parse_rewrite_unfold_core(p, force_unfold);
|
2015-02-13 20:22:17 +00:00
|
|
|
}
|
|
|
|
|
2015-02-24 03:40:03 +00:00
|
|
|
// If use_paren is true, then lemmas must be identifiers or be wrapped with parenthesis
|
|
|
|
static expr parse_rewrite_element(parser & p, bool use_paren) {
|
2015-07-09 01:08:24 +00:00
|
|
|
if (p.curr_is_token(get_up_tk()) || p.curr_is_token(get_caret_tk())) {
|
2015-07-12 17:17:22 +00:00
|
|
|
bool force_unfold = true;
|
2015-07-09 01:08:24 +00:00
|
|
|
return parse_rewrite_unfold(p, force_unfold);
|
|
|
|
}
|
2015-02-06 23:22:34 +00:00
|
|
|
if (p.curr_is_token(get_down_tk())) {
|
|
|
|
p.next();
|
2015-05-03 01:57:58 +00:00
|
|
|
expr e = p.parse_tactic_expr_arg();
|
2015-02-06 23:22:34 +00:00
|
|
|
location loc = parse_tactic_location(p);
|
|
|
|
return mk_rewrite_fold(e, loc);
|
|
|
|
}
|
2015-02-03 01:02:14 +00:00
|
|
|
bool symm = false;
|
|
|
|
if (p.curr_is_token(get_sub_tk())) {
|
|
|
|
p.next();
|
|
|
|
symm = true;
|
|
|
|
}
|
|
|
|
if (p.curr_is_numeral()) {
|
|
|
|
unsigned n = p.parse_small_nat();
|
2015-02-05 03:19:19 +00:00
|
|
|
if (p.curr_is_token(get_greater_tk())) {
|
2015-02-03 01:02:14 +00:00
|
|
|
p.next();
|
2015-02-03 03:20:24 +00:00
|
|
|
optional<expr> pat = parse_pattern(p);
|
2015-02-24 03:40:03 +00:00
|
|
|
expr H = parse_rule(p, use_paren);
|
2015-02-03 01:37:11 +00:00
|
|
|
location loc = parse_tactic_location(p);
|
2015-02-03 20:01:27 +00:00
|
|
|
return mk_rewrite_at_most_n(pat, H, symm, n, loc);
|
2015-02-03 01:02:14 +00:00
|
|
|
} else {
|
2015-02-03 03:20:24 +00:00
|
|
|
optional<expr> pat = parse_pattern(p);
|
2015-02-24 03:40:03 +00:00
|
|
|
expr H = parse_rule(p, use_paren);
|
2015-02-03 01:37:11 +00:00
|
|
|
location loc = parse_tactic_location(p);
|
2015-02-03 20:01:27 +00:00
|
|
|
return mk_rewrite_exactly_n(pat, H, symm, n, loc);
|
2015-02-03 01:02:14 +00:00
|
|
|
}
|
2015-02-05 03:19:19 +00:00
|
|
|
} else if (p.curr_is_token(get_star_tk())) {
|
2015-02-03 01:02:14 +00:00
|
|
|
p.next();
|
2015-02-03 03:20:24 +00:00
|
|
|
optional<expr> pat = parse_pattern(p);
|
2015-02-24 03:40:03 +00:00
|
|
|
expr H = parse_rule(p, use_paren);
|
2015-02-03 01:37:11 +00:00
|
|
|
location loc = parse_tactic_location(p);
|
2015-02-03 03:20:24 +00:00
|
|
|
return mk_rewrite_zero_or_more(pat, H, symm, loc);
|
2015-02-05 03:19:19 +00:00
|
|
|
} else if (p.curr_is_token(get_plus_tk())) {
|
2015-02-03 01:02:14 +00:00
|
|
|
p.next();
|
2015-02-03 03:20:24 +00:00
|
|
|
optional<expr> pat = parse_pattern(p);
|
2015-02-24 03:40:03 +00:00
|
|
|
expr H = parse_rule(p, use_paren);
|
2015-02-03 01:37:11 +00:00
|
|
|
location loc = parse_tactic_location(p);
|
2015-02-03 03:20:24 +00:00
|
|
|
return mk_rewrite_one_or_more(pat, H, symm, loc);
|
2015-02-05 21:23:52 +00:00
|
|
|
} else if (p.curr_is_token(get_triangle_tk()) || p.curr_is_token(get_greater_tk())) {
|
|
|
|
p.next();
|
|
|
|
if (p.curr_is_token(get_star_tk())) {
|
|
|
|
p.next();
|
|
|
|
location loc = parse_tactic_location(p);
|
|
|
|
return mk_rewrite_reduce(loc);
|
|
|
|
} else {
|
2015-05-03 01:57:58 +00:00
|
|
|
expr e = p.parse_tactic_expr_arg();
|
2015-02-05 21:23:52 +00:00
|
|
|
location loc = parse_tactic_location(p);
|
|
|
|
return mk_rewrite_reduce_to(e, loc);
|
|
|
|
}
|
2015-02-03 01:02:14 +00:00
|
|
|
} else {
|
2015-02-03 03:20:24 +00:00
|
|
|
optional<expr> pat = parse_pattern(p);
|
2015-02-24 03:40:03 +00:00
|
|
|
expr H = parse_rule(p, use_paren);
|
2015-02-03 01:37:11 +00:00
|
|
|
location loc = parse_tactic_location(p);
|
2015-02-03 03:20:24 +00:00
|
|
|
return mk_rewrite_once(pat, H, symm, loc);
|
2015-02-03 01:02:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-27 23:32:43 +00:00
|
|
|
void parse_rewrite_tactic_elems(parser & p, buffer<expr> & elems) {
|
2015-03-28 00:26:06 +00:00
|
|
|
if (p.curr_is_token(get_lbracket_tk())) {
|
2015-02-05 04:16:24 +00:00
|
|
|
p.next();
|
2015-06-28 18:45:30 +00:00
|
|
|
while (!p.curr_is_token(get_rbracket_tk())) {
|
2015-02-05 04:16:24 +00:00
|
|
|
auto pos = p.pos();
|
2015-02-24 03:40:03 +00:00
|
|
|
elems.push_back(p.save_pos(parse_rewrite_element(p, false), pos));
|
2015-02-05 04:16:24 +00:00
|
|
|
if (!p.curr_is_token(get_comma_tk()))
|
|
|
|
break;
|
|
|
|
p.next();
|
|
|
|
}
|
2015-06-28 18:45:30 +00:00
|
|
|
p.next();
|
2015-02-05 04:16:24 +00:00
|
|
|
} else {
|
2015-02-03 20:01:27 +00:00
|
|
|
auto pos = p.pos();
|
2015-02-24 03:40:03 +00:00
|
|
|
elems.push_back(p.save_pos(parse_rewrite_element(p, true), pos));
|
2015-02-03 01:02:14 +00:00
|
|
|
}
|
2015-05-27 23:32:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
expr parse_rewrite_tactic(parser & p) {
|
|
|
|
buffer<expr> elems;
|
|
|
|
parse_rewrite_tactic_elems(p, elems);
|
2015-02-03 01:37:11 +00:00
|
|
|
return mk_rewrite_tactic_expr(elems);
|
2015-02-03 01:02:14 +00:00
|
|
|
}
|
2015-02-06 22:13:32 +00:00
|
|
|
|
2015-05-27 23:32:43 +00:00
|
|
|
expr parse_xrewrite_tactic(parser & p) {
|
|
|
|
buffer<expr> elems;
|
|
|
|
parse_rewrite_tactic_elems(p, elems);
|
|
|
|
return mk_xrewrite_tactic_expr(elems);
|
|
|
|
}
|
|
|
|
|
|
|
|
expr parse_krewrite_tactic(parser & p) {
|
|
|
|
buffer<expr> elems;
|
|
|
|
parse_rewrite_tactic_elems(p, elems);
|
|
|
|
return mk_krewrite_tactic_expr(elems);
|
|
|
|
}
|
|
|
|
|
2015-02-06 22:13:32 +00:00
|
|
|
expr parse_esimp_tactic(parser & p) {
|
|
|
|
buffer<expr> elems;
|
2015-03-13 00:05:41 +00:00
|
|
|
auto pos = p.pos();
|
2015-07-09 01:08:24 +00:00
|
|
|
bool force_unfold = false;
|
2015-02-06 22:13:32 +00:00
|
|
|
if (p.curr_is_token(get_up_tk()) || p.curr_is_token(get_caret_tk())) {
|
2015-07-09 01:08:24 +00:00
|
|
|
elems.push_back(p.save_pos(parse_rewrite_unfold(p, force_unfold), pos));
|
2015-03-28 00:26:06 +00:00
|
|
|
} else if (p.curr_is_token(get_lbracket_tk())) {
|
2015-07-09 01:08:24 +00:00
|
|
|
elems.push_back(p.save_pos(parse_rewrite_unfold_core(p, force_unfold), pos));
|
2015-02-06 22:13:32 +00:00
|
|
|
} else {
|
|
|
|
location loc = parse_tactic_location(p);
|
2015-03-13 00:05:41 +00:00
|
|
|
elems.push_back(p.save_pos(mk_rewrite_reduce(loc), pos));
|
2015-02-06 22:13:32 +00:00
|
|
|
}
|
|
|
|
return mk_rewrite_tactic_expr(elems);
|
|
|
|
}
|
2015-03-26 01:22:20 +00:00
|
|
|
|
2015-04-25 00:21:08 +00:00
|
|
|
expr parse_unfold_tactic(parser & p) {
|
|
|
|
buffer<expr> elems;
|
|
|
|
auto pos = p.pos();
|
2015-07-09 01:08:24 +00:00
|
|
|
bool force_unfold = true;
|
2015-04-25 00:21:08 +00:00
|
|
|
if (p.curr_is_identifier()) {
|
|
|
|
name c = p.check_constant_next("invalid unfold tactic, identifier expected");
|
2015-06-28 18:28:05 +00:00
|
|
|
check_not_in_theorem_queue(p, c, pos);
|
2015-04-25 00:21:08 +00:00
|
|
|
location loc = parse_tactic_location(p);
|
2015-07-09 01:08:24 +00:00
|
|
|
elems.push_back(p.save_pos(mk_rewrite_unfold(to_list(c), force_unfold, loc), pos));
|
2015-04-25 00:21:08 +00:00
|
|
|
} else if (p.curr_is_token(get_lbracket_tk())) {
|
2015-07-09 01:08:24 +00:00
|
|
|
elems.push_back(p.save_pos(parse_rewrite_unfold_core(p, force_unfold), pos));
|
2015-04-25 00:21:08 +00:00
|
|
|
} else {
|
|
|
|
throw parser_error("invalid unfold tactic, identifier or `[` expected", pos);
|
|
|
|
}
|
|
|
|
return mk_rewrite_tactic_expr(elems);
|
|
|
|
}
|
|
|
|
|
2015-03-26 01:22:20 +00:00
|
|
|
expr parse_fold_tactic(parser & p) {
|
|
|
|
buffer<expr> elems;
|
|
|
|
auto pos = p.pos();
|
2015-03-28 00:26:06 +00:00
|
|
|
if (p.curr_is_token(get_lbracket_tk())) {
|
2015-03-26 01:22:20 +00:00
|
|
|
p.next();
|
|
|
|
while (true) {
|
|
|
|
auto pos = p.pos();
|
2015-05-03 01:57:58 +00:00
|
|
|
expr e = p.parse_tactic_expr_arg();
|
2015-03-26 01:22:20 +00:00
|
|
|
location loc = parse_tactic_location(p);
|
|
|
|
elems.push_back(p.save_pos(mk_rewrite_fold(e, loc), pos));
|
|
|
|
if (!p.curr_is_token(get_comma_tk()))
|
|
|
|
break;
|
|
|
|
p.next();
|
|
|
|
}
|
2015-03-28 00:26:06 +00:00
|
|
|
p.check_token_next(get_rbracket_tk(), "invalid 'fold' tactic, ',' or ']' expected");
|
2015-03-26 01:22:20 +00:00
|
|
|
} else {
|
2015-05-03 01:57:58 +00:00
|
|
|
expr e = p.parse_tactic_expr_arg();
|
2015-03-26 01:22:20 +00:00
|
|
|
location loc = parse_tactic_location(p);
|
|
|
|
elems.push_back(p.save_pos(mk_rewrite_fold(e, loc), pos));;
|
|
|
|
}
|
|
|
|
return mk_rewrite_tactic_expr(elems);
|
|
|
|
}
|
2015-02-03 01:02:14 +00:00
|
|
|
}
|