feat(frontends/lean/notation_cmd): reuse existing precedence to increase compatibility with existing notation
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
fa1857e6a9
commit
b5f63e78ca
2 changed files with 59 additions and 3 deletions
|
@ -198,7 +198,7 @@ unsigned get_precedence(environment const & env, buffer<token_entry> const & new
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static action parse_action(parser & p, name const & prev_token, buffer<expr> & locals, buffer<token_entry> & new_tokens) {
|
static action parse_action(parser & p, name const & prev_token, unsigned default_prec, buffer<expr> & locals, buffer<token_entry> & new_tokens) {
|
||||||
if (p.curr_is_token(g_colon)) {
|
if (p.curr_is_token(g_colon)) {
|
||||||
p.next();
|
p.next();
|
||||||
if (p.curr_is_numeral() || p.curr_is_token_or_id(g_max)) {
|
if (p.curr_is_numeral() || p.curr_is_token_or_id(g_max)) {
|
||||||
|
@ -259,18 +259,38 @@ static action parse_action(parser & p, name const & prev_token, buffer<expr> & l
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return mk_expr_action();
|
return mk_expr_action(default_prec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief If the action for token \c tk in parse table \c pt is an Expr action,
|
||||||
|
then return its precedence. We use this value as the default precedence
|
||||||
|
when the user does not provide it. The idea is to minimize conflict with existing
|
||||||
|
notation.
|
||||||
|
*/
|
||||||
|
unsigned get_default_prec(optional<parse_table> const & pt, name const & tk) {
|
||||||
|
if (!pt)
|
||||||
|
return 0;
|
||||||
|
if (auto at = pt->find(tk)) {
|
||||||
|
if (at->first.kind() == notation::action_kind::Expr)
|
||||||
|
return at->first.rbp();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
notation_entry parse_notation_core(parser & p, bool overload, buffer<token_entry> & new_tokens) {
|
notation_entry parse_notation_core(parser & p, bool overload, buffer<token_entry> & new_tokens) {
|
||||||
buffer<expr> locals;
|
buffer<expr> locals;
|
||||||
buffer<transition> ts;
|
buffer<transition> ts;
|
||||||
parser::local_scope scope(p);
|
parser::local_scope scope(p);
|
||||||
bool is_nud = true;
|
bool is_nud = true;
|
||||||
|
optional<parse_table> pt;
|
||||||
if (p.curr_is_identifier()) {
|
if (p.curr_is_identifier()) {
|
||||||
parse_notation_local(p, locals);
|
parse_notation_local(p, locals);
|
||||||
is_nud = false;
|
is_nud = false;
|
||||||
|
pt = get_led_table(p.env());
|
||||||
|
} else {
|
||||||
|
pt = get_nud_table(p.env());
|
||||||
}
|
}
|
||||||
while (!p.curr_is_token(g_assign)) {
|
while (!p.curr_is_token(g_assign)) {
|
||||||
name tk = parse_quoted_symbol_or_token(p, new_tokens);
|
name tk = parse_quoted_symbol_or_token(p, new_tokens);
|
||||||
|
@ -281,9 +301,10 @@ notation_entry parse_notation_core(parser & p, bool overload, buffer<token_entry
|
||||||
p.next();
|
p.next();
|
||||||
ts.push_back(transition(tk, mk_binders_action()));
|
ts.push_back(transition(tk, mk_binders_action()));
|
||||||
} else if (p.curr_is_identifier()) {
|
} else if (p.curr_is_identifier()) {
|
||||||
|
unsigned default_prec = get_default_prec(pt, tk);
|
||||||
name n = p.get_name_val();
|
name n = p.get_name_val();
|
||||||
p.next();
|
p.next();
|
||||||
action a = parse_action(p, tk, locals, new_tokens);
|
action a = parse_action(p, tk, default_prec, locals, new_tokens);
|
||||||
expr l = mk_local(n, g_local_type);
|
expr l = mk_local(n, g_local_type);
|
||||||
p.add_local_expr(n, l);
|
p.add_local_expr(n, l);
|
||||||
locals.push_back(l);
|
locals.push_back(l);
|
||||||
|
@ -293,6 +314,21 @@ notation_entry parse_notation_core(parser & p, bool overload, buffer<token_entry
|
||||||
} else {
|
} else {
|
||||||
throw parser_error("invalid notation declaration, quoted-symbol, identifier, 'binder', 'binders' expected", p.pos());
|
throw parser_error("invalid notation declaration, quoted-symbol, identifier, 'binder', 'binders' expected", p.pos());
|
||||||
}
|
}
|
||||||
|
if (pt) {
|
||||||
|
// new notation is still compatible with the existing one
|
||||||
|
transition const & new_trans = ts.back();
|
||||||
|
if (auto at = pt->find(new_trans.get_token())) {
|
||||||
|
if (new_trans.get_action().is_compatible(at->first)) {
|
||||||
|
pt = at->second;
|
||||||
|
} else {
|
||||||
|
// new notation is not compatible with existing one
|
||||||
|
pt = optional<parse_table>();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// parse table does not handle this prefix
|
||||||
|
pt = optional<parse_table>();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
p.next();
|
p.next();
|
||||||
if (ts.empty())
|
if (ts.empty())
|
||||||
|
|
20
tests/lean/run/n5.lean
Normal file
20
tests/lean/run/n5.lean
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
variable N : Type.{1}
|
||||||
|
variable f : N → N → N → N
|
||||||
|
variable g : N → N → N
|
||||||
|
variable h : N → N → N → N
|
||||||
|
variable s : N → N → N → N → N
|
||||||
|
|
||||||
|
precedence `*`:75
|
||||||
|
precedence `|`:75
|
||||||
|
|
||||||
|
notation a * b:prev | c:prev := f a b c
|
||||||
|
notation a * b := g a b
|
||||||
|
notation a * b * c:prev := h a b c
|
||||||
|
notation a * b | c * d:prev := s a b c d
|
||||||
|
|
||||||
|
variables a b c d e : N
|
||||||
|
|
||||||
|
check a * b
|
||||||
|
check a * b | d
|
||||||
|
check a * b * c
|
||||||
|
check a * b | d * e
|
Loading…
Reference in a new issue