diff --git a/src/frontends/lean/builtin_exprs.cpp b/src/frontends/lean/builtin_exprs.cpp index 7bdcec0146..b9d49d50b1 100644 --- a/src/frontends/lean/builtin_exprs.cpp +++ b/src/frontends/lean/builtin_exprs.cpp @@ -242,17 +242,8 @@ static expr parse_begin_end_core(parser & p, pos_info const & pos, name const & } } } catch (exception & ex) { - if (end_token == get_end_tk()) { - // When the end_token is 'end', the default parser - // sync_command does not work well because it will - // interpret 'end' as a synchronization point because 'end' is also a command. - while (!p.curr_is_token(get_end_tk())) { - if (p.curr() == scanner::token_kind::Eof) - ex.rethrow(); - p.next(); - } - p.next(); // consume 'end' - } + if (end_token == get_end_tk()) + consume_until_end(p); ex.rethrow(); } auto end_pos = p.pos(); diff --git a/src/frontends/lean/decl_cmds.cpp b/src/frontends/lean/decl_cmds.cpp index bed54b9e23..901be56a22 100644 --- a/src/frontends/lean/decl_cmds.cpp +++ b/src/frontends/lean/decl_cmds.cpp @@ -698,47 +698,53 @@ expr parse_local_equations(parser & p, expr const & fn) { /** \brief Use equations compiler infrastructure to implement match-with */ expr parse_match(parser & p, unsigned, expr const *, pos_info const & pos) { - expr t = p.parse_expr(); buffer eqns; - p.check_token_next(get_with_tk(), "invalid 'match' expression, 'with' expected"); - expr fn = mk_local(p.mk_fresh_name(), "match", mk_expr_placeholder(), binder_info()); - if (p.curr_is_token(get_end_tk())) { - p.next(); - // empty match-with - eqns.push_back(Fun(fn, mk_no_equation())); - expr f = p.save_pos(mk_equations(1, eqns.size(), eqns.data()), pos); - return p.mk_app(f, t, pos); - } - if (is_eqn_prefix(p)) - p.next(); // optional '|' in the first case - while (true) { - expr lhs; - unsigned prev_num_undef_ids = p.get_num_undef_ids(); - buffer locals; - { - parser::undef_id_to_local_scope scope2(p); - auto lhs_pos = p.pos(); - lhs = p.parse_expr(); - lhs = p.mk_app(fn, lhs, lhs_pos); - unsigned num_undef_ids = p.get_num_undef_ids(); - for (unsigned i = prev_num_undef_ids; i < num_undef_ids; i++) { - locals.push_back(p.get_undef_id(i)); + expr t; + try { + t = p.parse_expr(); + p.check_token_next(get_with_tk(), "invalid 'match' expression, 'with' expected"); + expr fn = mk_local(p.mk_fresh_name(), "match", mk_expr_placeholder(), binder_info()); + if (p.curr_is_token(get_end_tk())) { + p.next(); + // empty match-with + eqns.push_back(Fun(fn, mk_no_equation())); + expr f = p.save_pos(mk_equations(1, eqns.size(), eqns.data()), pos); + return p.mk_app(f, t, pos); + } + if (is_eqn_prefix(p)) + p.next(); // optional '|' in the first case + while (true) { + expr lhs; + unsigned prev_num_undef_ids = p.get_num_undef_ids(); + buffer locals; + { + parser::undef_id_to_local_scope scope2(p); + auto lhs_pos = p.pos(); + lhs = p.parse_expr(); + lhs = p.mk_app(fn, lhs, lhs_pos); + unsigned num_undef_ids = p.get_num_undef_ids(); + for (unsigned i = prev_num_undef_ids; i < num_undef_ids; i++) { + locals.push_back(p.get_undef_id(i)); + } } + validate_equation_lhs(p, lhs, locals); + lhs = merge_equation_lhs_vars(lhs, locals); + auto assign_pos = p.pos(); + p.check_token_next(get_assign_tk(), "invalid 'match' expression, ':=' expected"); + { + parser::local_scope scope2(p); + for (expr const & local : locals) + p.add_local(local); + expr rhs = p.parse_expr(); + eqns.push_back(Fun(fn, Fun(locals, p.save_pos(mk_equation(lhs, rhs), assign_pos), p))); + } + if (!is_eqn_prefix(p)) + break; + p.next(); } - validate_equation_lhs(p, lhs, locals); - lhs = merge_equation_lhs_vars(lhs, locals); - auto assign_pos = p.pos(); - p.check_token_next(get_assign_tk(), "invalid 'match' expression, ':=' expected"); - { - parser::local_scope scope2(p); - for (expr const & local : locals) - p.add_local(local); - expr rhs = p.parse_expr(); - eqns.push_back(Fun(fn, Fun(locals, p.save_pos(mk_equation(lhs, rhs), assign_pos), p))); - } - if (!is_eqn_prefix(p)) - break; - p.next(); + } catch (exception & ex) { + consume_until_end(p); + ex.rethrow(); } p.check_token_next(get_end_tk(), "invalid 'match' expression, 'end' expected"); expr f = p.save_pos(mk_equations(1, eqns.size(), eqns.data()), pos); diff --git a/src/frontends/lean/util.cpp b/src/frontends/lean/util.cpp index 6456239592..816b842987 100644 --- a/src/frontends/lean/util.cpp +++ b/src/frontends/lean/util.cpp @@ -22,6 +22,15 @@ Author: Leonardo de Moura #include "frontends/lean/tokens.h" namespace lean { +void consume_until_end(parser & p) { + while (!p.curr_is_token(get_end_tk())) { + if (p.curr() == scanner::token_kind::Eof) + return; + p.next(); + } + p.next(); +} + bool parse_persistent(parser & p, bool & persistent) { if (p.curr_is_token_or_id(get_persistent_tk())) { p.next(); diff --git a/src/frontends/lean/util.h b/src/frontends/lean/util.h index 33cbfbf1a3..e0234df578 100644 --- a/src/frontends/lean/util.h +++ b/src/frontends/lean/util.h @@ -14,6 +14,9 @@ Author: Leonardo de Moura namespace lean { class parser; +/** \brief Consume tokes until 'end' token is consumed */ +void consume_until_end(parser & p); + /** \brief Parse optional '[persistent]' modifier. return true if it is was found, and paremeter \c persistent to true. */ diff --git a/tests/lean/errors2.lean b/tests/lean/errors2.lean new file mode 100644 index 0000000000..a4f45d1d3c --- /dev/null +++ b/tests/lean/errors2.lean @@ -0,0 +1,12 @@ +open nat + +namespace foo + +definition tst1 (a b : nat) : nat := +match a with +| 0 := 1 +| (n+1) := foo +end + + +end foo diff --git a/tests/lean/errors2.lean.expected.out b/tests/lean/errors2.lean.expected.out new file mode 100644 index 0000000000..d18b595b9a --- /dev/null +++ b/tests/lean/errors2.lean.expected.out @@ -0,0 +1 @@ +errors2.lean:8:11: error: unknown identifier 'foo'