aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/sphinx/user-extensions/syntax-extensions.rst48
-rw-r--r--plugins/syntax/g_numeral.ml411
-rw-r--r--test-suite/interactive/PrimNotation.v58
-rw-r--r--test-suite/success/NumeralNotations.v123
4 files changed, 195 insertions, 45 deletions
diff --git a/doc/sphinx/user-extensions/syntax-extensions.rst b/doc/sphinx/user-extensions/syntax-extensions.rst
index ca588acf29..50425c8a5d 100644
--- a/doc/sphinx/user-extensions/syntax-extensions.rst
+++ b/doc/sphinx/user-extensions/syntax-extensions.rst
@@ -1376,16 +1376,15 @@ Abbreviations
Numeral notations
-----------------
-Starting with version 8.9, the following command allows the user to customize
-the way numeral literals are parsed and printed:
-
.. cmd:: Numeral Notation @ident__1 @ident__2 @ident__3 : @scope.
- In the previous line, :n:`@ident__1` should be the name of an
- inductive type, while :n:`@ident__2` and :n:`@ident__3` should be
- the names of the parsing and printing functions, respectively. The
- parsing function :n:`@ident__2` should have one of the following
- types:
+ This command allows the user to customize the way numeral literals
+ are parsed and printed.
+
+ The token :n:`@ident__1` should be the name of an inductive type,
+ while :n:`@ident__2` and :n:`@ident__3` should be the names of the
+ parsing and printing functions, respectively. The parsing function
+ :n:`@ident__2` should have one of the following types:
* :n:`Decimal.int -> @ident__1`
* :n:`Decimal.int -> option @ident__1`
@@ -1404,6 +1403,10 @@ the way numeral literals are parsed and printed:
* :n:`@ident__1 -> Z`
* :n:`@ident__1 -> option Z`
+ When parsing, the application of the parsing function
+ :n:`@ident__2` to the number will be fully reduced, and universes
+ of the resulting term will be refreshed.
+
.. cmdv:: Numeral Notation @ident__1 @ident__2 @ident__3 : @scope (warning after @num).
When a literal larger than :token:`num` is parsed, a warning
@@ -1420,12 +1423,13 @@ the way numeral literals are parsed and printed:
more compact representation of literals in types such as :g:`nat`,
and limits parse failures due to stack overflow. Note that a
warning will be emitted when an integer larger than :token:`num`
- is parsed.
+ is parsed. Note that :n:`(abstract after @num)` has no effect
+ when :n:`@ident__2` lands in an :g:`option` type.
.. exn:: Cannot interpret this number as a value of type @type
- The numeral notation registered for :g:`ty` does not support the
- given numeral. This error is given when the interpretation
+ The numeral notation registered for :token:`type` does not support
+ the given numeral. This error is given when the interpretation
function returns :g:`None`, or if the interpretation is registered
for only non-negative integers, and the given numeral is negative.
@@ -1434,7 +1438,7 @@ the way numeral literals are parsed and printed:
The parsing function given to the :cmd:`Numeral Notation`
vernacular is not of the right type.
- .. exn:: @ident should go from @type to Decimal.int or (option Decimal.int). Instead of Decimal.int, the the types Decimal.uint or Z could be used{? (require BinNums first)}.
+ .. exn:: @ident should go from @type to Decimal.int or (option Decimal.int). Instead of Decimal.int, the types Decimal.uint or Z could be used{? (require BinNums first)}.
The printing function given to the :cmd:`Numeral Notation`
vernacular is not of the right type.
@@ -1444,20 +1448,6 @@ the way numeral literals are parsed and printed:
Numeral notations can only be declared for inductive types with no
arguments.
- .. exn:: The inductive type @type cannot be used in numeral notations because support for polymorphic inductive types is not yet implemented.
-
- Numeral notations do not currently support polymorphic inductive
- types. Ensure that all types involved in numeral notations are
- declared with :g:`Unset Universe Polymorphism`, or with the
- :g:`Monomorphic` attribute.
-
- .. exn:: The function @ident cannot be used in numeral notations because support for polymorphic printing and parsing functions is not yet implemented.
-
- Numeral notations do not currently support polymorphic functions
- for printing and parsing. Ensure that both functions passed to
- :cmd:`Numeral Notation` are defined with :g:`Unset Universe
- Polymorphism`, or with the :g:`Monomorphic` attribute.
-
.. exn:: Unexpected term while parsing a numeral notation
Parsing functions must always return ground terms, made up of
@@ -1482,6 +1472,12 @@ the way numeral literals are parsed and printed:
Both functions passed to :cmd:`Numeral Notation` must be single
identifiers.
+ .. exn:: The reference @ident was not found in the current environment.
+
+ Identifiers passed to :cmd:`Numeral Notation` must be global
+ definitions, not notations, section variables, section-local
+ :g:`Let` bound identifiers, etc.
+
.. warn:: Stack overflow or segmentation fault happens when working with large numbers in @type (threshold may vary depending on your system limits and on the command executed).
When a :cmd:`Numeral Notation` is registered in the current scope
diff --git a/plugins/syntax/g_numeral.ml4 b/plugins/syntax/g_numeral.ml4
index 1d2d47fbaa..a097adec24 100644
--- a/plugins/syntax/g_numeral.ml4
+++ b/plugins/syntax/g_numeral.ml4
@@ -36,13 +36,14 @@ open Constr
let eval_constr env sigma (c : Constr.t) =
let c = EConstr.of_constr c in
let sigma,t = Typing.type_of env sigma c in
- let c'= Vnorm.cbv_vm env sigma c t in
+ let c' = Vnorm.cbv_vm env sigma c t in
EConstr.Unsafe.to_constr c'
(* For testing with "compute" instead of "vm_compute" :
-let eval_constr (c : constr) =
- let (sigma, env) = Lemmas.get_current_context () in
- Tacred.compute env sigma c
+let eval_constr env sigma (c : Constr.t) =
+ let c = EConstr.of_constr c in
+ let c' = Tacred.compute env sigma c in
+ EConstr.Unsafe.to_constr c'
*)
let eval_constr_app env sigma c1 c2 =
@@ -325,7 +326,7 @@ let uninterp o (Glob_term.AnyGlobConstr n) =
| UInt _ -> Some (rawnum_of_coquint c, true)
| Z _ -> Some (big2raw (bigint_of_z c))
with
- | Type_errors.TypeError _ -> None (* cf. eval_constr_app *)
+ | Type_errors.TypeError _ | Pretype_errors.PretypeError _ -> None (* cf. eval_constr_app *)
| NotANumber -> None (* all other functions except big2raw *)
(* Here we only register the interp and uninterp functions
diff --git a/test-suite/interactive/PrimNotation.v b/test-suite/interactive/PrimNotation.v
index 4c81095c68..07986b0df3 100644
--- a/test-suite/interactive/PrimNotation.v
+++ b/test-suite/interactive/PrimNotation.v
@@ -5,14 +5,60 @@
Delimit Scope Z_scope with Z.
Open Scope Z_scope.
-Check 0.
-(* 0 : nat *)
+Check let v := 0 in v : nat.
+(* let v := 0 in v : nat : nat *)
Require BinInt.
-Check 0.
-(* 0 : BinNums.Z *)
+Check let v := 0 in v : BinNums.Z.
+(* let v := 0 in v : BinNums.Z : BinNums.Z *)
Back 2.
-Check 0.
-(* Expected answer: 0 : nat *)
+Check let v := 0 in v : nat.
+(* Expected answer: let v := 0 in v : nat : nat *)
(* Used to fail with:
Error: Cannot interpret in Z_scope without requiring first module BinNums.
*)
+
+Local Set Universe Polymorphism.
+Delimit Scope punit_scope with punit.
+Delimit Scope pcunit_scope with pcunit.
+Delimit Scope int_scope with int.
+Numeral Notation Decimal.int Decimal.int_of_int Decimal.int_of_int : int_scope.
+Module A.
+ NonCumulative Inductive punit@{u} : Type@{u} := ptt.
+ Cumulative Inductive pcunit@{u} : Type@{u} := pctt.
+ Definition to_punit : Decimal.int -> option punit
+ := fun v => match v with 0%int => Some ptt | _ => None end.
+ Definition to_pcunit : Decimal.int -> option pcunit
+ := fun v => match v with 0%int => Some pctt | _ => None end.
+ Definition of_punit : punit -> Decimal.uint := fun _ => Nat.to_uint 0.
+ Definition of_pcunit : pcunit -> Decimal.uint := fun _ => Nat.to_uint 0.
+ Numeral Notation punit to_punit of_punit : punit_scope.
+ Check let v := 0%punit in v : punit.
+ Back 2.
+ Numeral Notation pcunit to_pcunit of_pcunit : punit_scope.
+ Check let v := 0%punit in v : pcunit.
+End A.
+Reset A.
+Local Unset Universe Polymorphism.
+Module A.
+ Inductive punit : Set := ptt.
+ Definition to_punit : Decimal.int -> option punit
+ := fun v => match v with 0%int => Some ptt | _ => None end.
+ Definition of_punit : punit -> Decimal.uint := fun _ => Nat.to_uint 0.
+ Numeral Notation punit to_punit of_punit : punit_scope.
+ Check let v := 0%punit in v : punit.
+End A.
+Local Set Universe Polymorphism.
+Inductive punit@{u} : Type@{u} := ptt.
+Definition to_punit : Decimal.int -> option punit
+ := fun v => match v with 0%int => Some ptt | _ => None end.
+Definition of_punit : punit -> Decimal.uint := fun _ => Nat.to_uint 0.
+Numeral Notation punit to_punit of_punit : punit_scope.
+Check let v := 0%punit in v : punit.
+Back 6. (* check backtracking of registering universe polymorphic constants *)
+Local Unset Universe Polymorphism.
+Inductive punit : Set := ptt.
+Definition to_punit : Decimal.int -> option punit
+ := fun v => match v with 0%int => Some ptt | _ => None end.
+Definition of_punit : punit -> Decimal.uint := fun _ => Nat.to_uint 0.
+Numeral Notation punit to_punit of_punit : punit_scope.
+Check let v := 0%punit in v : punit.
diff --git a/test-suite/success/NumeralNotations.v b/test-suite/success/NumeralNotations.v
index a06327c5e6..907ec32671 100644
--- a/test-suite/success/NumeralNotations.v
+++ b/test-suite/success/NumeralNotations.v
@@ -31,8 +31,9 @@ End Test3.
Module Test4.
- Polymorphic Inductive punit := ptt.
+ Polymorphic NonCumulative Inductive punit := ptt.
Polymorphic Definition pto_punit (v : Decimal.uint) : option punit := match Nat.of_uint v with O => Some ptt | _ => None end.
+ Polymorphic Definition pto_punit_all (v : Decimal.uint) : punit := ptt.
Polymorphic Definition pof_punit (v : punit) : Decimal.uint := Nat.to_uint 0.
Definition to_punit (v : Decimal.uint) : option punit := match Nat.of_uint v with O => Some ptt | _ => None end.
Definition of_punit (v : punit) : Decimal.uint := Nat.to_uint 0.
@@ -40,16 +41,122 @@ Module Test4.
Polymorphic Definition pof_unit (v : unit) : Decimal.uint := Nat.to_uint 0.
Definition to_unit (v : Decimal.uint) : option unit := match Nat.of_uint v with O => Some tt | _ => None end.
Definition of_unit (v : unit) : Decimal.uint := Nat.to_uint 0.
- Fail Numeral Notation punit to_punit of_punit : pto.
- Fail Numeral Notation punit pto_punit of_punit : ppo.
- Fail Numeral Notation punit to_punit pof_punit : ptp.
- Fail Numeral Notation punit pto_punit pof_punit : ppp.
+ Numeral Notation punit to_punit of_punit : pto.
+ Numeral Notation punit pto_punit of_punit : ppo.
+ Numeral Notation punit to_punit pof_punit : ptp.
+ Numeral Notation punit pto_punit pof_punit : ppp.
Numeral Notation unit to_unit of_unit : uto.
+ Delimit Scope pto with pto.
+ Delimit Scope ppo with ppo.
+ Delimit Scope ptp with ptp.
+ Delimit Scope ppp with ppp.
Delimit Scope uto with uto.
+ Check let v := 0%pto in v : punit.
+ Check let v := 0%ppo in v : punit.
+ Check let v := 0%ptp in v : punit.
+ Check let v := 0%ppp in v : punit.
Check let v := 0%uto in v : unit.
Fail Check 1%uto.
Fail Check (-1)%uto.
- Fail Numeral Notation unit pto_unit of_unit : upo.
- Fail Numeral Notation unit to_unit pof_unit : utp.
- Fail Numeral Notation unit pto_unit pof_unit : upp.
+ Numeral Notation unit pto_unit of_unit : upo.
+ Numeral Notation unit to_unit pof_unit : utp.
+ Numeral Notation unit pto_unit pof_unit : upp.
+ Delimit Scope upo with upo.
+ Delimit Scope utp with utp.
+ Delimit Scope upp with upp.
+ Check let v := 0%upo in v : unit.
+ Check let v := 0%utp in v : unit.
+ Check let v := 0%upp in v : unit.
+
+ Polymorphic Definition pto_punits := pto_punit_all@{Set}.
+ Polymorphic Definition pof_punits := pof_punit@{Set}.
+ Numeral Notation punit pto_punits pof_punits : ppps (abstract after 1).
+ Delimit Scope ppps with ppps.
+ Universe u.
+ Constraint Set < u.
+ Check let v := 0%ppps in v : punit@{u}. (* Check that universes are refreshed *)
+ Fail Check let v := 1%ppps in v : punit@{u}. (* Note that universes are not refreshed here *)
End Test4.
+
+Module Test5.
+ Check S. (* At one point gave Error: Anomaly "Uncaught exception Pretype_errors.PretypeError(_, _, _)." Please report at http://coq.inria.fr/bugs/. *)
+End Test5.
+
+Module Test6.
+ (* Check that numeral notations on enormous terms don't take forever to print/parse *)
+ (* Ackerman definition from https://stackoverflow.com/a/10303475/377022 *)
+ Fixpoint ack (n m : nat) : nat :=
+ match n with
+ | O => S m
+ | S p => let fix ackn (m : nat) :=
+ match m with
+ | O => ack p 1
+ | S q => ack p (ackn q)
+ end
+ in ackn m
+ end.
+
+ Timeout 1 Check (S (ack 4 4)). (* should be instantaneous *)
+
+ Local Set Primitive Projections.
+ Record > wnat := wrap { unwrap :> nat }.
+ Definition to_uint (x : wnat) : Decimal.uint := Nat.to_uint x.
+ Definition of_uint (x : Decimal.uint) : wnat := Nat.of_uint x.
+ Module Export Scopes.
+ Delimit Scope wnat_scope with wnat.
+ End Scopes.
+ Module Export Notations.
+ Export Scopes.
+ Numeral Notation wnat of_uint to_uint : wnat_scope (abstract after 5000).
+ End Notations.
+ Check let v := 0%wnat in v : wnat.
+ Check wrap O.
+ Timeout 1 Check wrap (ack 4 4). (* should be instantaneous *)
+End Test6.
+
+Module Test6_2.
+ Import Test6.Scopes.
+ Check Test6.wrap 0.
+ Import Test6.Notations.
+ Check let v := 0%wnat in v : Test6.wnat.
+End Test6_2.
+
+Module Test7.
+ Local Set Primitive Projections.
+ Record > wuint := wrap { unwrap : Decimal.uint }.
+ Delimit Scope wuint_scope with wuint.
+ Fail Numeral Notation wuint wrap unwrap : wuint_scope.
+End Test7.
+
+Module Test8.
+ Local Set Primitive Projections.
+ Record > wuint := wrap { unwrap : Decimal.uint }.
+ Delimit Scope wuint_scope with wuint.
+ Section with_var.
+ Context (dummy : unit).
+ Definition wrap' := let __ := dummy in wrap.
+ Definition unwrap' := let __ := dummy in unwrap.
+ Global Numeral Notation wuint wrap' unwrap' : wuint_scope.
+ Check let v := 0%wuint in v : wuint.
+ End with_var.
+ Fail Check let v := 0%wuint in v : wuint.
+ Compute wrap (Nat.to_uint 0).
+
+ Notation wrap'' := wrap.
+ Notation unwrap'' := unwrap.
+ Fail Numeral Notation wuint wrap'' unwrap'' : wuint_scope.
+End Test8.
+
+Module Test9.
+ Section with_let.
+ Local Set Primitive Projections.
+ Record > wuint := wrap { unwrap : Decimal.uint }.
+ Let wrap' := wrap.
+ Let unwrap' := unwrap.
+ Local Notation wrap'' := wrap.
+ Local Notation unwrap'' := unwrap.
+ Delimit Scope wuint_scope with wuint.
+ Fail Numeral Notation wuint wrap' unwrap' : wuint_scope.
+ Fail Numeral Notation wuint wrap'' unwrap'' : wuint_scope.
+ End with_let.
+End Test9.