diff --git a/src/frontends/lean/builtin_tactic_cmds.cpp b/src/frontends/lean/builtin_tactic_cmds.cpp index 3b110f3c8..9dfc89ccf 100644 --- a/src/frontends/lean/builtin_tactic_cmds.cpp +++ b/src/frontends/lean/builtin_tactic_cmds.cpp @@ -8,20 +8,42 @@ Author: Leonardo de Moura #include "frontends/lean/parser.h" namespace lean { +static name g_comma(","); +static name g_rbracket("]"); + tactic parse_fail_tactic(parser &) { return fail_tactic(); } tactic parse_id_tactic(parser &) { return id_tactic(); } tactic parse_assumption_tactic(parser &) { return assumption_tactic(); } +tactic parse_echo_tactic(parser & p) { + if (!p.curr_is_string()) + throw parser_error("invalid 'echo' tactic, string expected", p.pos()); + tactic r = trace_tactic(p.get_str_val()); + p.next(); + return r; +} +tactic parse_tactic_seq(parser & p) { + tactic r = p.parse_tactic(); + while (p.curr_is_token(g_comma)) { + p.next(); + r = then(r, p.parse_tactic()); + } + p.check_token_next(g_rbracket, "invalid tactic sequence, ']' expected"); + return r; +} void add_tactic(tactic_cmd_table & t, tactic_cmd_info && info) { t.insert(info.get_name(), info); } tactic_cmd_table get_builtin_tactic_cmds() { tactic_cmd_table t; add_tactic(t, tactic_cmd_info("fail", "always fail tactic", parse_fail_tactic)); + add_tactic(t, tactic_cmd_info("echo", "trace tactic: display message", parse_echo_tactic)); add_tactic(t, tactic_cmd_info("id", "do nothing tactic", parse_id_tactic)); add_tactic(t, tactic_cmd_info("assumption", "solve goal if there is an assumption that is identical to the conclusion", parse_assumption_tactic)); add_tactic(t, tactic_cmd_info("exact", "solve goal if there is an assumption that is identical to the conclusion", parse_assumption_tactic)); + add_tactic(t, tactic_cmd_info("[", "tactic command sequence", + parse_tactic_seq)); return t; } } diff --git a/src/frontends/lean/parser.cpp b/src/frontends/lean/parser.cpp index 6c6b917b3..a7a40da12 100644 --- a/src/frontends/lean/parser.cpp +++ b/src/frontends/lean/parser.cpp @@ -961,17 +961,23 @@ tactic parser::parse_tactic(unsigned /* rbp */) { auto r = parse_tactic(); check_token_next(g_rparen, "invalid tactic, ')' expected"); return r; - } else if (curr_is_identifier()) { - auto p = pos(); - name id = get_name_val(); - next(); + } else { + name id; + auto p = pos(); + if (curr_is_identifier()) { + id = get_name_val(); + next(); + } else if (curr_is_keyword()) { + id = get_token_info().value(); + next(); + } else { + throw parser_error("invalid tactic, '(' or tactic command expected", p); + } if (auto it = tactic_cmds().find(id)) { return it->get_fn()(*this); } else { - throw parser_error(sstream() << "unknown tactic '" << id << "'", p); + throw parser_error(sstream() << "unknown tactic command '" << id << "'", p); } - } else { - throw parser_error("invalid tactic, '(' or tactic name expected", pos()); } } diff --git a/src/library/tactic/tactic.cpp b/src/library/tactic/tactic.cpp index 1759ae2b1..0e82d7373 100644 --- a/src/library/tactic/tactic.cpp +++ b/src/library/tactic/tactic.cpp @@ -56,7 +56,7 @@ tactic now_tactic() { }); } -tactic cond(proof_state_pred const & p, tactic const & t1, tactic const & t2) { +tactic cond(proof_state_pred p, tactic const & t1, tactic const & t2) { return tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq { return mk_proof_state_seq([=]() { if (p(env, ios, s)) { diff --git a/tests/lean/run/tactic2.lean b/tests/lean/run/tactic2.lean new file mode 100644 index 000000000..d033435bf --- /dev/null +++ b/tests/lean/run/tactic2.lean @@ -0,0 +1,4 @@ +import logic + +theorem tst {A B : Bool} (H1 : A) (H2 : B) : A +:= by [echo "executing simple tactic", assumption]