static expr parse_struct_expr_core(parser & p, pos_info const & pos, bool curly_bar) { expr t = p.parse_expr(); buffer<name> field_names; buffer<expr> field_values; buffer<expr> using_exprs; while (p.curr_is_token(get_comma_tk())) { p.next(); pair<optional<name>, expr> id_e = p.parse_optional_assignment(); if (id_e.first) { field_names.push_back(*id_e.first); field_values.push_back(id_e.second); } else { using_exprs.push_back(id_e.second); } } if (curly_bar) p.check_token_next(get_rcurlybar_tk(), "invalid structure expression, '|}' expected"); else p.check_token_next(get_rdcurly_tk(), "invalid structure expression, '⦄' expected"); buffer<expr> args; args.push_back(t); args.append(field_values); args.append(using_exprs); return p.save_pos(mk_structure_instance(to_list(field_names), args.size(), args.data()), pos); }
implicit_infer_kind parse_implicit_infer_modifier(parser & p) { if (p.curr_is_token(get_lcurly_tk())) { p.next(); p.check_token_next(get_rcurly_tk(), "invalid introduction rule, '}' expected"); return implicit_infer_kind::RelaxedImplicit; } else if (p.curr_is_token(get_lparen_tk())) { p.next(); p.check_token_next(get_rparen_tk(), "invalid introduction rule, ')' expected"); return implicit_infer_kind::None; } else { return implicit_infer_kind::Implicit; } }
static name parse_class(parser & p) { if (p.curr_is_token(g_lbracket)) { p.next(); name n; if (p.curr_is_identifier()) n = p.get_name_val(); else if (p.curr_is_keyword() || p.curr_is_command()) n = p.get_token_info().value(); else throw parser_error("invalid 'using' command, identifier or symbol expected", p.pos()); p.next(); p.check_token_next(g_rbracket, "invalid 'using' command, ']' expected"); return n; } else { return name(); } }
expr parse_nested_declaration(parser & p, unsigned, expr const *, pos_info const & pos) { try { optional<name> n; decl_attributes attrs; if (!g_allow_nested_declarations) throw parser_error("invalid 'abstract' expression, it is only allowed inside definitions", pos); if (p.curr_is_token(get_as_tk())) { p.next(); n = p.check_id_next("invalid 'abstract' expression, identifier expected"); } attrs.parse(p); expr e = p.parse_expr(); p.check_token_next(get_end_tk(), "invalid 'abstract' expression, 'end' expected"); return p.save_pos(mk_nested_declaration(n, attrs, e), pos); } catch (exception & ex) { consume_until_end(p); ex.rethrow(); lean_unreachable(); } }
void decl_attributes::parse(parser & p) { buffer<char const *> attr_tokens; get_attribute_tokens(attr_tokens); while (true) { auto pos = p.pos(); if (auto it = parse_priority(p)) { m_prio = *it; bool has_prio_attr = false; for (auto const & entry : m_entries) { if (get_attribute_kind(entry.m_attr.c_str()) == attribute_kind::Prioritized) { has_prio_attr = true; break; } } if (!has_prio_attr) { throw parser_error("invalid '[priority]' attribute, declaration has not been marked with a prioritized attribute", pos); } } else if (p.curr_is_token(get_parsing_only_tk())) { if (!m_is_abbrev) throw parser_error("invalid '[parsing_only]' attribute, only abbreviations can be " "marked as '[parsing_only]'", pos); m_parsing_only = true; p.next(); } else { bool found = false; for (char const * tk : attr_tokens) { if (p.curr_is_token(tk)) { p.next(); char const * attr = get_attribute_from_token(tk); for (auto const & entry : m_entries) { if (are_incompatible(entry.m_attr.c_str(), attr)) { throw parser_error(sstream() << "invalid attribute [" << attr << "], declaration was already marked with [" << entry.m_attr << "]", pos); } } switch (get_attribute_kind(attr)) { case attribute_kind::Default: case attribute_kind::Prioritized: m_entries = cons(entry(attr), m_entries); break; case attribute_kind::Parametric: { unsigned v = p.parse_small_nat(); if (v == 0) throw parser_error("invalid attribute parameter, value must be positive", pos); p.check_token_next(get_rbracket_tk(), "invalid attribute, ']' expected"); m_entries = cons(entry(attr, v-1), m_entries); break; } case attribute_kind::OptParametric: if (!p.curr_is_token(get_rbracket_tk())) { unsigned v = p.parse_small_nat(); if (v == 0) throw parser_error("invalid attribute parameter, value must be positive", pos); p.check_token_next(get_rbracket_tk(), "invalid attribute, ']' expected"); m_entries = cons(entry(attr, v-1), m_entries); } else { p.check_token_next(get_rbracket_tk(), "invalid attribute, ']' expected"); m_entries = cons(entry(attr), m_entries); } break; case attribute_kind::MultiParametric: { buffer<unsigned> vs; while (true) { unsigned v = p.parse_small_nat(); if (v == 0) throw parser_error("invalid attribute parameter, value must be positive", pos); vs.push_back(v-1); if (p.curr_is_token(get_rbracket_tk())) break; } p.next(); m_entries = cons(entry(attr, to_list(vs)), m_entries); break; } } found = true; break; } } if (!found) break; } } }
static environment precedence_cmd(parser & p) { std::string tk = parse_symbol(p, "invalid precedence declaration, quoted symbol or identifier expected"); p.check_token_next(get_colon_tk(), "invalid precedence declaration, ':' expected"); unsigned prec = parse_precedence(p); return add_user_token(p.env(), tk.c_str(), prec); }
static notation_entry parse_notation_core(parser & p, bool overload, notation_entry_group grp, buffer<token_entry> & new_tokens, bool parse_only, unsigned priority) { buffer<expr> locals; buffer<transition> ts; parser::local_scope scope(p); bool is_nud = true; optional<parse_table> pt; optional<parse_table> reserved_pt; if (p.curr_is_numeral()) { lean_assert(p.curr_is_numeral()); mpz num = p.get_num_val().get_numerator(); p.next(); p.check_token_next(get_assign_tk(), "invalid numeral notation, `:=` expected"); auto e_pos = p.pos(); expr e = p.parse_expr(); check_notation_expr(e, e_pos); return notation_entry(num, e, overload, parse_only); } else if (p.curr_is_identifier()) { parse_notation_local(p, locals); is_nud = false; pt = get_led_table(p.env()); if (grp != notation_entry_group::Reserve) reserved_pt = get_reserved_led_table(p.env()); } else { pt = get_nud_table(p.env()); if (grp != notation_entry_group::Reserve) reserved_pt = get_reserved_nud_table(p.env()); } bool used_default = false; while ((grp != notation_entry_group::Reserve && !p.curr_is_token(get_assign_tk())) || (grp == notation_entry_group::Reserve && !p.curr_is_command() && !p.curr_is_eof())) { name pp_tk = parse_quoted_symbol_or_token(p, new_tokens, used_default, grp).to_string(); name tk = utf8_trim(pp_tk.to_string()); if (auto at = find_next(reserved_pt, tk)) { // Remark: we are ignoring multiple actions in the reserved notation table transition const & trans = head(at).first; action const & a = trans.get_action(); reserved_pt = head(at).second; if (!p.curr_is_quoted_symbol()) pp_tk = trans.get_pp_token(); switch (a.kind()) { case notation::action_kind::Skip: if (!p.curr_is_quoted_symbol() && !p.curr_is_keyword() && !p.curr_is_token(get_assign_tk())) { if (g_allow_local && !p.curr_is_token_or_id(get_binders_tk())) { ts.push_back(parse_transition(p, pt, tk, locals, new_tokens, grp, pp_tk)); break; } p.check_token_or_id_next(get_binders_tk(), "invalid notation declaration, quoted-symbol, keyword or `:=` expected " "(declaration prefix matches reserved notation)"); } ts.push_back(transition(tk, a, pp_tk)); break; case notation::action_kind::Binder: if (g_allow_local && !p.curr_is_token_or_id(get_binder_tk())) { ts.push_back(parse_transition(p, pt, tk, locals, new_tokens, grp, pp_tk)); break; } p.check_token_or_id_next(get_binder_tk(), "invalid notation declaration, 'binder' expected " "(declaration prefix matches reserved notation)"); ts.push_back(transition(tk, a, pp_tk)); break; case notation::action_kind::Binders: if (g_allow_local && !p.curr_is_token_or_id(get_binders_tk())) { ts.push_back(parse_transition(p, pt, tk, locals, new_tokens, grp, pp_tk)); break; } p.check_token_or_id_next(get_binders_tk(), "invalid notation declaration, 'binders' expected " "(declaration prefix matches reserved notation)"); ts.push_back(transition(tk, a, pp_tk)); break; case notation::action_kind::Expr: case notation::action_kind::Exprs: case notation::action_kind::ScopedExpr: case notation::action_kind::Ext: { if (g_allow_local && !p.curr_is_identifier()) { ts.push_back(parse_transition(p, pt, tk, locals, new_tokens, grp, pp_tk)); break; } name n = p.check_id_next("invalid notation declaration, identifier expected " "(declaration prefix matches reserved notation)"); if (p.curr_is_token(get_colon_tk())) { if (g_allow_local) { unsigned default_prec = get_default_prec(pt, tk); action a = parse_action(p, tk, default_prec, locals, new_tokens, grp); expr local_type = mk_Prop(); // type used in notation local declarations, it is irrelevant expr l = mk_local(n, local_type); p.add_local(l); locals.push_back(l); ts.push_back(transition(tk, a, pp_tk)); break; } else { throw parser_error("invalid notation declaration, invalid ':' occurrence " "(declaration prefix matches reserved notation)", p.pos()); } } else { expr local_type = mk_Prop(); // type used in notation local declarations, it is irrelevant expr l = mk_local(n, local_type); p.add_local(l); locals.push_back(l); ts.push_back(transition(tk, a, pp_tk)); break; } }} } else { reserved_pt = optional<parse_table>(); ts.push_back(parse_transition(p, pt, tk, locals, new_tokens, grp, pp_tk)); } pt = find_match(pt, ts.back()); } // for atomic notation where binding power was not set, we set it to max if (used_default && ts.size() == 1 && ts.back().get_action().kind() == notation::action_kind::Skip) { lean_assert(!new_tokens.empty()); new_tokens.back().m_prec = get_max_prec(); } expr n; if (grp == notation_entry_group::Reserve) { // reserve notation commands do not have a denotation lean_assert(p.curr_is_command() || p.curr_is_eof()); expr dummy = mk_Prop(); // any expression without free variables will do n = dummy; } else { lean_assert(p.curr_is_token(get_assign_tk())); p.next(); if (ts.empty()) throw parser_error("invalid notation declaration, empty notation is not allowed", p.pos()); n = parse_notation_expr(p, locals); } return notation_entry(is_nud, to_list(ts.begin(), ts.end()), n, overload, priority, grp, parse_only); }
static action parse_action(parser & p, name const & prev_token, unsigned default_prec, buffer<expr> & locals, buffer<token_entry> & new_tokens, notation_entry_group grp) { if (p.curr_is_token(get_colon_tk())) { p.next(); if (p.curr_is_numeral() || p.curr_is_token_or_id(get_max_tk())) { unsigned prec = parse_precedence(p); return mk_expr_action(prec); } else if (p.curr_is_token_or_id(get_prev_tk())) { p.next(); return mk_expr_action(get_precedence(p.env(), new_tokens, prev_token)); } else if (p.curr_is_token_or_id(get_scoped_tk())) { p.next(); return mk_scoped_expr_action(mk_var(0)); } else { p.check_token_next(get_lparen_tk(), "invalid notation declaration, '(', numeral or 'scoped' expected"); if (p.curr_is_token_or_id(get_foldl_tk()) || p.curr_is_token_or_id(get_foldr_tk())) { bool is_fold_right = p.curr_is_token_or_id(get_foldr_tk()); p.next(); auto prec = parse_optional_precedence(p); name sep = parse_quoted_symbol_or_token(p, new_tokens, grp); expr rec; { parser::local_scope scope(p); p.check_token_next(get_lparen_tk(), "invalid fold notation argument, '(' expected"); parse_notation_local(p, locals); parse_notation_local(p, locals); p.check_token_next(get_comma_tk(), "invalid fold notation argument, ',' expected"); rec = parse_notation_expr(p, locals); p.check_token_next(get_rparen_tk(), "invalid fold notation argument, ')' expected"); locals.pop_back(); locals.pop_back(); } optional<expr> ini; if (!p.curr_is_token(get_rparen_tk()) && !p.curr_is_quoted_symbol()) ini = parse_notation_expr(p, locals); optional<name> terminator; if (!p.curr_is_token(get_rparen_tk())) terminator = parse_quoted_symbol_or_token(p, new_tokens, grp); p.check_token_next(get_rparen_tk(), "invalid fold notation argument, ')' expected"); return mk_exprs_action(sep, rec, ini, terminator, is_fold_right, prec ? *prec : 0); } else if (p.curr_is_token_or_id(get_scoped_tk())) { p.next(); auto prec = parse_optional_precedence(p); expr rec; { parser::local_scope scope(p); parse_notation_local(p, locals); p.check_token_next(get_comma_tk(), "invalid scoped notation argument, ',' expected"); rec = parse_notation_expr(p, locals); locals.pop_back(); } p.check_token_next(get_rparen_tk(), "invalid scoped notation argument, ')' expected"); return mk_scoped_expr_action(rec, prec ? *prec : 0); } else { throw parser_error("invalid notation declaration, 'foldl', 'foldr' or 'scoped' expected", p.pos()); } } } else { return mk_expr_action(default_prec); } }