aboutsummaryrefslogtreecommitdiff
path: root/parsing
diff options
context:
space:
mode:
authorHugo Herbelin2017-08-12 09:15:40 +0200
committerHugo Herbelin2018-02-20 10:03:06 +0100
commitedd0d22429354a5f2c703a8c7bd1f775e2f97d9e (patch)
tree865fd16d40f5641cac233f951f951a9a4502159f /parsing
parent398358618bb3eabfe822b79c669703c1c33b67e6 (diff)
Adding support for parsing subterms of a notation as "pattern".
This allows in particular to define notations with 'pat style binders. E.g.: A non-trivial change in this commit is storing binders and patterns separately from terms. This is not strictly necessary but has some advantages. However, it is relatively common to have binders also used as terms, or binders parsed as terms. Thus, it is already relatively common to embed binders into terms (see e.g. notation for ETA in output test Notations3.v) or to coerce terms to idents (see e.g. the notation for {x|P} where x is parsed as a constr). So, it is as simple to always store idents (and eventually patterns) as terms.
Diffstat (limited to 'parsing')
-rw-r--r--parsing/egramcoq.ml30
-rw-r--r--parsing/g_constr.ml48
-rw-r--r--parsing/g_vernac.ml42
3 files changed, 22 insertions, 18 deletions
diff --git a/parsing/egramcoq.ml b/parsing/egramcoq.ml
index 4fd84eac50..a3d2571549 100644
--- a/parsing/egramcoq.ml
+++ b/parsing/egramcoq.ml
@@ -231,6 +231,7 @@ type (_, _) entry =
| TTBigint : ('self, Constrexpr.raw_natural_number) entry
| TTConstr : prod_info * 'r target -> ('r, 'r) entry
| TTConstrList : prod_info * Tok.t list * 'r target -> ('r, 'r list) entry
+| TTPattern : int -> ('self, cases_pattern_expr) entry
| TTOpenBinderList : ('self, local_binder_expr list) entry
| TTClosedBinderList : Tok.t list -> ('self, local_binder_expr list list) entry
@@ -288,6 +289,7 @@ let symbol_of_entry : type s r. _ -> _ -> (s, r) entry -> (s, r) symbol = fun as
Alist1 (symbol_of_target typ' assoc from forpat)
| TTConstrList (typ', tkl, forpat) ->
Alist1sep (symbol_of_target typ' assoc from forpat, make_sep_rules tkl)
+| TTPattern p -> Aentryl (Constr.pattern, p)
| TTClosedBinderList [] -> Alist1 (Aentry Constr.binder)
| TTClosedBinderList tkl -> Alist1sep (Aentry Constr.binder, make_sep_rules tkl)
| TTName -> Aentry Prim.name
@@ -300,16 +302,12 @@ let interp_entry forpat e = match e with
| ETProdReference -> TTAny TTReference
| ETProdBigint -> TTAny TTBigint
| ETProdConstr p -> TTAny (TTConstr (p, forpat))
-| ETProdPattern -> assert false (** not used *)
+| ETProdPattern p -> TTAny (TTPattern p)
| ETProdOther _ -> assert false (** not used *)
| ETProdConstrList (p, tkl) -> TTAny (TTConstrList (p, tkl, forpat))
| ETProdBinderList ETBinderOpen -> TTAny TTOpenBinderList
| ETProdBinderList (ETBinderClosed tkl) -> TTAny (TTClosedBinderList tkl)
-let constr_expr_of_name (loc,na) = CAst.make ?loc @@ match na with
- | Anonymous -> CHole (None,Misctypes.IntroAnonymous,None)
- | Name id -> CRef (Ident (Loc.tag ?loc id), None)
-
let cases_pattern_expr_of_name (loc,na) = CAst.make ?loc @@ match na with
| Anonymous -> CPatAtom None
| Name id -> CPatAtom (Some (Ident (Loc.tag ?loc id)))
@@ -317,7 +315,8 @@ let cases_pattern_expr_of_name (loc,na) = CAst.make ?loc @@ match na with
type 'r env = {
constrs : 'r list;
constrlists : 'r list list;
- binderlists : (local_binder_expr list * bool) list;
+ binders : cases_pattern_expr list;
+ binderlists : local_binder_expr list list;
}
let push_constr subst v = { subst with constrs = v :: subst.constrs }
@@ -327,11 +326,16 @@ match e with
| TTConstr _ -> push_constr subst v
| TTName ->
begin match forpat with
- | ForConstr -> push_constr subst (constr_expr_of_name v)
+ | ForConstr -> { subst with binders = cases_pattern_expr_of_name v :: subst.binders }
| ForPattern -> push_constr subst (cases_pattern_expr_of_name v)
end
-| TTOpenBinderList -> { subst with binderlists = (v, true) :: subst.binderlists }
-| TTClosedBinderList _ -> { subst with binderlists = (List.flatten v, false) :: subst.binderlists }
+| TTPattern _ ->
+ begin match forpat with
+ | ForConstr -> { subst with binders = v :: subst.binders }
+ | ForPattern -> push_constr subst v
+ end
+| TTOpenBinderList -> { subst with binderlists = v :: subst.binderlists }
+| TTClosedBinderList _ -> { subst with binderlists = List.flatten v :: subst.binderlists }
| TTBigint ->
begin match forpat with
| ForConstr -> push_constr subst (CAst.make @@ CPrim (Numeral (v,true)))
@@ -431,11 +435,9 @@ let rec pure_sublevels : type a b c. int option -> (a, b, c) rule -> int list =
let make_act : type r. r target -> _ -> r gen_eval = function
| ForConstr -> fun notation loc env ->
- let env = (env.constrs, env.constrlists, List.map fst env.binderlists) in
- CAst.make ~loc @@ CNotation (notation , env)
+ let env = (env.constrs, env.constrlists, env.binders, env.binderlists) in
+ CAst.make ~loc @@ CNotation (notation, env)
| ForPattern -> fun notation loc env ->
- let invalid = List.exists (fun (_, b) -> not b) env.binderlists in
- let () = if invalid then Constrexpr_ops.error_invalid_pattern_notation ~loc () in
let env = (env.constrs, env.constrlists) in
CAst.make ~loc @@ CPatNotation (notation, env, [])
@@ -451,7 +453,7 @@ let extend_constr state forpat ng =
let needed_levels, state = register_empty_levels state isforpat pure_sublevels in
let (pos,p4assoc,name,reinit), state = find_position state isforpat assoc level in
let empty_rules = List.map (prepare_empty_levels isforpat) needed_levels in
- let empty = { constrs = []; constrlists = []; binderlists = [] } in
+ let empty = { constrs = []; constrlists = []; binders = []; binderlists = [] } in
let act = ty_eval r (make_act forpat ng.notgram_notation) empty in
let rule = (name, p4assoc, [Rule (symbs, act)]) in
let r = ExtendRule (entry, reinit, (pos, [rule])) in
diff --git a/parsing/g_constr.ml4 b/parsing/g_constr.ml4
index 4c55f3ec65..c2ce003f13 100644
--- a/parsing/g_constr.ml4
+++ b/parsing/g_constr.ml4
@@ -120,7 +120,7 @@ let name_colon =
| _ -> err ())
| _ -> err ())
-let aliasvar = function { CAst.loc = loc; CAst.v = CPatAlias (_, id) } -> Some (loc,Name id) | _ -> None
+let aliasvar = function { CAst.v = CPatAlias (_, na) } -> Some na | _ -> None
GEXTEND Gram
GLOBAL: binder_constr lconstr constr operconstr universe_level sort sort_family
@@ -216,7 +216,7 @@ GEXTEND Gram
| "("; c = operconstr LEVEL "200"; ")" ->
(match c.CAst.v with
| CPrim (Numeral (n,true)) ->
- CAst.make ~loc:(!@loc) @@ CNotation("( _ )",([c],[],[]))
+ CAst.make ~loc:(!@loc) @@ CNotation("( _ )",([c],[],[],[]))
| _ -> c)
| "{|"; c = record_declaration; "|}" -> c
| "`{"; c = operconstr LEVEL "200"; "}" ->
@@ -385,8 +385,8 @@ GEXTEND Gram
| "99" RIGHTA [ ]
| "90" RIGHTA [ ]
| "10" LEFTA
- [ p = pattern; "as"; id = ident ->
- CAst.make ~loc:!@loc @@ CPatAlias (p, id)
+ [ p = pattern; "as"; na = name ->
+ CAst.make ~loc:!@loc @@ CPatAlias (p, na)
| p = pattern; lp = LIST1 NEXT -> mkAppPattern ~loc:!@loc p lp
| "@"; r = Prim.reference; lp = LIST0 NEXT ->
CAst.make ~loc:!@loc @@ CPatCstr (r, Some lp, []) ]
diff --git a/parsing/g_vernac.ml4 b/parsing/g_vernac.ml4
index d42b5f622c..6ef0b4fa88 100644
--- a/parsing/g_vernac.ml4
+++ b/parsing/g_vernac.ml4
@@ -1181,6 +1181,8 @@ GEXTEND Gram
[ [ IDENT "ident" -> ETName | IDENT "global" -> ETReference
| IDENT "bigint" -> ETBigint
| IDENT "binder" -> ETBinder true
+ | IDENT "pattern" -> ETPattern 0
+ | IDENT "pattern"; "at"; IDENT "level"; n = natural -> ETPattern n
| IDENT "closed"; IDENT "binder" -> ETBinder false
] ]
;