feat(frontends/lean,library/init/lean/parser/combinators): add node_longest_choice! macro

This commit is contained in:
Sebastian Ullrich 2018-11-19 18:02:28 +01:00
parent 4ec98a4595
commit c8eaee74b4
8 changed files with 44 additions and 34 deletions

View file

@ -101,15 +101,10 @@ def to_pexpr : syntax → elaborator_m expr
pure (binder_info.implicit, bc)
| bracketed_binder.view.strict_implicit {content := bc} :=
pure (binder_info.strict_implicit, bc)
| bracketed_binder.view.inst_implicit {content := bc} :=
prod.mk binder_info.inst_implicit <$> (match bc.kind with
| some @inst_implicit_anonymous_binder :=
pure {ids := ["_inst_"], type := some {type := (view inst_implicit_anonymous_binder bc).type}}
| some @inst_implicit_named_binder :=
let v := view inst_implicit_named_binder bc in
pure {ids := [v.id], type := some {type := v.type}}
| _ := error stx "ill-formed lambda")
/-| bracketed_binder.view.anonymous_constructor {content := bc} :=-/
| bracketed_binder.view.inst_implicit {content := bc} := do
inst_implicit_binder_content.view.named bcn ← pure bc
| error stx "ill-formed lambda",
pure (binder_info.inst_implicit, {ids := [bcn.id], type := some {type := bcn.type}})
| _ := error stx "ill-formed lambda",
{ids := [binder_ident.view.id id], type := some type} ← pure bc | error stx "ill-formed lambda",
expr.lam (mangle_ident id) bi <$> to_pexpr type.type <*> to_pexpr body

View file

@ -53,7 +53,7 @@ review lambda {
| binder_info.implicit := bracketed_binder.view.implicit {content := bc}
| binder_info.strict_implicit := bracketed_binder.view.strict_implicit {content := bc}
| binder_info.inst_implicit := bracketed_binder.view.inst_implicit
{content := review inst_implicit_named_binder {id := id, type := dom}}
{content := inst_implicit_binder_content.view.named {id := id, type := dom}}
| binder_info.aux_decl := /- should not happen -/
bracketed_binder.view.explicit {content := explicit_binder_content.view.other bc}
]},
@ -90,13 +90,11 @@ def lambda.transform : transformer :=
| bracketed_binder.view.implicit {content := bc} := (binder_info.implicit, bc)
| bracketed_binder.view.strict_implicit {content := bc} := (binder_info.strict_implicit, bc)
| bracketed_binder.view.inst_implicit {content := bc} :=
prod.mk binder_info.inst_implicit $ (match bc.kind with
| some @inst_implicit_anonymous_binder :=
{ids := ["_inst_"], type := some {type := (view inst_implicit_anonymous_binder bc).type}}
| some @inst_implicit_named_binder :=
let v := view inst_implicit_named_binder bc in
{ids := [v.id], type := some {type := v.type}}
| _ := {ids := []} /- unreachable -/)
prod.mk binder_info.inst_implicit $ (match bc with
| inst_implicit_binder_content.view.anonymous bca :=
{ids := ["_inst_"], type := some {type := bca.type}}
| inst_implicit_binder_content.view.named bcn :=
{ids := [bcn.id], type := some {type := bcn.type}})
| bracketed_binder.view.anonymous_constructor _ := (binder_info.default, {ids := []}) /- unreachable -/),
let type := (binder_content_type.view.type <$> bc.type).get_or_else $ review hole {},
type ← match bc.default with

View file

@ -165,9 +165,6 @@ instance longest_match.tokens (rs : list parser) [parser.has_tokens rs] : parser
⟨tokens rs⟩
instance longest_match.view (rs : list parser) : parser.has_view syntax (longest_match rs) := default _
/-- Parse a list `[p1, ..., pn]` of parsers as `p1 <|> ... <|> pn`.
The result will be wrapped in a node with the the index of the successful
parser as the name. -/
def choice_aux : list parser → nat → parser
| [] _ := error "choice: empty list"
| (r::rs) i :=
@ -175,15 +172,29 @@ def choice_aux : list parser → nat → parser
pure $ syntax.mk_node ⟨name.mk_numeral name.anonymous i⟩ [stx] }
<|> choice_aux rs (i+1)
/-- Parse a list `[p1, ..., pn]` of parsers as `p1 <|> ... <|> pn`.
The result will be wrapped in a node with the index of the successful
parser as the name.
Remark: Does not have a `has_view` instance because we only use it in `node_choice!` macros
that define their own views. -/
def choice (rs : list parser) : parser :=
choice_aux rs 0
instance choice.tokens (rs : list parser) [parser.has_tokens rs] : parser.has_tokens (choice rs) :=
⟨tokens rs⟩
/- Remark: `choice` does not have `has_view` instance because we only use it at the pratt combinator
which doesn't need the view. -/
/-- Like `choice`, but using `longest_match`. Does not create choice nodes, prefers the first successful parser. -/
def longest_choice (rs : list parser) : parser :=
do stx::stxs ← monad_parsec.longest_match $ rs.enum.map $ λ ⟨i, r⟩, do {
stx ← r,
pure $ syntax.mk_node ⟨name.mk_numeral name.anonymous i⟩ [stx]
} | error "unreachable",
pure stx
instance longest_choice.tokens (rs : list parser) [parser.has_tokens rs] : parser.has_tokens (longest_choice rs) :=
⟨tokens rs⟩
instance try.tokens (r : parser) [parser.has_tokens r] : parser.has_tokens (try r) :=
⟨tokens r⟩
instance try.view (r : parser) [i : parser.has_view α r] : parser.has_view α (try r) :=

View file

@ -110,10 +110,10 @@ node_choice! bracketed_binder {
}, right: symbol ")"],
implicit: node! implicit_binder ["{", content: binder_content.parser, "}"],
strict_implicit: node! strict_implicit_binder ["⦃", content: binder_content.parser, "⦄"],
inst_implicit: node! inst_implicit_binder ["[", content: longest_match [
node! inst_implicit_named_binder [id: ident.parser, " : ", type: term.parser 0],
node! inst_implicit_anonymous_binder [type: term.parser 0]
], "]"],
inst_implicit: node! inst_implicit_binder ["[", content: node_longest_choice! inst_implicit_binder_content {
named: node! inst_implicit_named_binder [id: ident.parser, " : ", type: term.parser 0],
anonymous: node! inst_implicit_anonymous_binder [type: term.parser 0]
}, "]"],
anonymous_constructor: anonymous_constructor.parser,
}

View file

@ -934,6 +934,8 @@ static expr parse_node(parser & p, unsigned, expr const *, pos_info const &) {
}
static expr parse_choice(parser & p, unsigned, expr const *, pos_info const &) {
name this_macro = p.get_token_info().value();
p.next();
name macro = p.check_id_next("identifier expected");
std::function<buffer<expr>()> go;
buffer<expr> args;
@ -962,7 +964,7 @@ static expr parse_choice(parser & p, unsigned, expr const *, pos_info const &) {
p.next();
}
p.check_token_next("}", "`}` expected");
return mk_mdata(set_name(kvmap(), "node_choice!", macro), mk_lean_list(args));
return mk_mdata(set_name(kvmap(), this_macro, macro), mk_lean_list(args));
}
parse_table init_nud_table() {
@ -999,7 +1001,8 @@ parse_table init_nud_table() {
r = r.add({transition("match", mk_ext_action(parse_match))}, x0);
r = r.add({transition("do", mk_ext_action(parse_do_expr))}, x0);
r = r.add({transition("node!", mk_ext_action(parse_node))}, x0);
r = r.add({transition("node_choice!", mk_ext_action(parse_choice))}, x0);
r = r.add({transition("node_choice!", mk_ext_action_core(parse_choice))}, x0);
r = r.add({transition("node_longest_choice!", mk_ext_action_core(parse_choice))}, x0);
return r;
}

View file

@ -3311,8 +3311,8 @@ expr elaborator::visit_node_macro(expr const & e, optional<expr> const & expecte
expected_type);
}
expr elaborator::visit_node_choice_macro(expr const & e, optional<expr> const & expected_type) {
name macro = *get_name(mdata_data(e), "node_choice!");
expr elaborator::visit_node_choice_macro(expr const & e, bool longest_match, optional<expr> const & expected_type) {
name macro = *get_name(mdata_data(e), longest_match ? "node_longest_choice!" : "node_choice!");
name esc_macro = macro.is_atomic() ? "«" + macro.to_string() + "»" : macro;
expr args = mdata_expr(e);
name full_macro = get_namespace(m_env) + macro;
@ -3388,7 +3388,7 @@ expr elaborator::visit_node_choice_macro(expr const & e, optional<expr> const &
return visit(mk_app(mk_const({"lean", "parser", "combinators", "node"}),
mk_const(full_macro),
mk_app(mk_const({"list", "cons"}),
mk_app(mk_const({"lean", "parser", "combinators", "choice"}),
mk_app(mk_const({"lean", "parser", "combinators", longest_match ? "longest_choice" : "choice"}),
mk_lean_list(new_args)),
mk_const({"list", "nil"}))), expected_type);
}
@ -3438,7 +3438,9 @@ expr elaborator::visit_mdata(expr const & e, optional<expr> const & expected_typ
} else if (get_name(mdata_data(e), "node!")) {
return visit_node_macro(e, expected_type);
} else if (get_name(mdata_data(e), "node_choice!")) {
return visit_node_choice_macro(e, expected_type);
return visit_node_choice_macro(e, false, expected_type);
} else if (get_name(mdata_data(e), "node_longest_choice!")) {
return visit_node_choice_macro(e, true, expected_type);
} else {
expr new_e = visit(mdata_expr(e), expected_type);
return update_mdata(e, new_e);

View file

@ -238,7 +238,7 @@ private:
expr visit_lambda(expr const & e, optional<expr> const & expected_type);
expr visit_pi(expr const & e);
expr visit_node_macro(expr const & e, optional<expr> const & expected_type);
expr visit_node_choice_macro(expr const & e, optional<expr> const & expected_type);
expr visit_node_choice_macro(expr const & e, bool longest_match, optional<expr> const & expected_type);
expr visit_mdata(expr const & e, optional<expr> const & expected_type, bool is_app_fn);
expr visit_app(expr const & e, optional<expr> const & expected_type);
expr visit_let(expr const & e, optional<expr> const & expected_type);

View file

@ -97,7 +97,8 @@ void init_token_table(token_table & t) {
{"@@", g_max_prec}, {"@", g_max_prec},
{"sorry", g_max_prec}, {"+", g_plus_prec}, {"->", g_arrow_prec}, {"<-", 0},
{"match", 0}, {"^.", g_max_prec+1}, {"::", 67},
{"renaming", 0}, {"extends", 0}, {"node!", g_max_prec}, {"node_choice!", g_max_prec}, {nullptr, 0}};
{"renaming", 0}, {"extends", 0}, {"node!", g_max_prec}, {"node_choice!", g_max_prec},
{"node_longest_choice!", g_max_prec}, {nullptr, 0}};
char const * commands[] =
{"theorem", "axiom", "axioms", "variable", "protected", "private", "hide",