1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039(************************************************************************)(* * The Rocq Prover / The Rocq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)openCErrorsopenUtilopenPpopenNamesopenConstropenLibnamesopenConstrexpropenGlob_termopenGlob_opsopenNumTokletmkRef(env,sigmaref)r=letsigma,c=Evd.fresh_globalenv!sigmarefrinsigmaref:=sigma;EConstr.Unsafe.to_constrcletmkConstructesigc=mkRefesig(ConstructRefc)letmkIndesigi=mkRefesig(IndRefi)(**********************************************************************)(* Interpreting numbers (not in summary because functional objects) *)typerawnum=NumTok.Signed.ttypeprim_token_uid=stringtype'aprim_token_interpreter=?loc:Loc.t->'a->glob_constrtype'aprim_token_uninterpreter=any_glob_constr->'aoptiontype'aprim_token_interpretation='aprim_token_interpreter*'aprim_token_uninterpretermoduleInnerPrimToken=structtypeinterpreter=|RawNumInterpof(?loc:Loc.t->rawnum->glob_constr)|BigNumInterpof(?loc:Loc.t->Z.t->glob_constr)|StringInterpof(?loc:Loc.t->string->glob_constr)letinterp_eqff'=matchf,f'with|RawNumInterpf,RawNumInterpf'->f==f'|BigNumInterpf,BigNumInterpf'->f==f'|StringInterpf,StringInterpf'->f==f'|_->falseletdo_interp?locinterpprimtok=matchprimtok,interpwith|Numbern,RawNumInterpinterp->interp?locn|Numbern,BigNumInterpinterp->(matchNumTok.Signed.to_bigintnwith|Somen->interp?locn|None->raiseNot_found)|Strings,StringInterpinterp->interp?locs|(Number_|String_),(RawNumInterp_|BigNumInterp_|StringInterp_)->raiseNot_foundtypeuninterpreter=|RawNumUninterpof(any_glob_constr->rawnumoption)|BigNumUninterpof(any_glob_constr->Z.toption)|StringUninterpof(any_glob_constr->stringoption)letuninterp_eqff'=matchf,f'with|RawNumUninterpf,RawNumUninterpf'->f==f'|BigNumUninterpf,BigNumUninterpf'->f==f'|StringUninterpf,StringUninterpf'->f==f'|_->falseletmkNumbern=Number(NumTok.Signed.of_bigintCDecn)letmkString=function|None->None|Somes->ifUnicode.is_utf8sthenSome(Strings)elseNoneletdo_uninterpuninterpg=matchuninterpwith|RawNumUninterpu->Option.map(fun(s,n)->Number(s,n))(ug)|BigNumUninterpu->Option.mapmkNumber(ug)|StringUninterpu->mkString(ug)end(* The following two tables of (un)interpreters will *not* be
synchronized. But their indexes will be checked to be unique.
These tables contain primitive token interpreters which are
registered in plugins, such as string and ascii syntax. It is
essential that only plugins add to these tables, and that
vernacular commands do not. See
https://github.com/rocq-prover/rocq/issues/8401 for details of what goes
wrong when vernacular commands add to these tables. *)letprim_token_interpreters=(Hashtbl.create7:(prim_token_uid,InnerPrimToken.interpreter)Hashtbl.t)letprim_token_uninterpreters=(Hashtbl.create7:(prim_token_uid,InnerPrimToken.uninterpreter)Hashtbl.t)(*******************************************************)(* Number notation interpretation *)typeprim_token_notation_error=|UnexpectedTermofConstr.t|UnexpectedNonOptionTermofConstr.texceptionPrimTokenNotationErrorofstring*Environ.env*Evd.evar_map*prim_token_notation_errortypenumnot_option=|Nop|WarningofNumTok.UnsignedNat.t|AbstractofNumTok.UnsignedNat.ttypeint_ty={dec_uint:Names.inductive;dec_int:Names.inductive;hex_uint:Names.inductive;hex_int:Names.inductive;uint:Names.inductive;int:Names.inductive}typez_pos_ty={z_ty:Names.inductive;pos_ty:Names.inductive}typenumber_ty={int:int_ty;decimal:Names.inductive;hexadecimal:Names.inductive;number:Names.inductive}typepos_neg_int63_ty={pos_neg_int63_ty:Names.inductive}typetarget_kind=|Intofint_ty(* Corelib.Init.Number.int + uint *)|UIntofint_ty(* Corelib.Init.Number.uint *)|Zofz_pos_ty(* Corelib.Numbers.BinNums.Z and positive *)|Int63ofpos_neg_int63_ty(* Corelib.Numbers.Cyclic.Int63.PrimInt63.pos_neg_int63 *)|Float64(* Corelib.Floats.PrimFloat.float *)|Numberofnumber_ty(* Corelib.Init.Number.number + uint + int *)typestring_target_kind=|ListByte|Byte|PStringtypeoption_kind=Direct|Option|Errortype'targetconversion_kind='target*option_kind(** A postprocessing translation [to_post] can be done after execution
of the [to_ty] interpreter. The reverse translation is performed
before the [of_ty] uninterpreter.
[to_post] is an array of [n] lists [l_i] of tuples [(f, t,
args)]. When the head symbol of the translated term matches one of
the [f] in the list [l_0] it is replaced by [t] and its arguments
are translated acording to [args] where [ToPostCopy] means that the
argument is kept unchanged and [ToPostAs k] means that the
argument is recursively translated according to [l_k].
[ToPostHole] introduces an additional implicit argument hole
(in the reverse translation, the corresponding argument is removed).
[ToPostCheck r] behaves as [ToPostCopy] except in the reverse
translation which fails if the copied term is not [r].
When [n] is null, no translation is performed. *)typeto_post_arg=ToPostCopy|ToPostAsofint|ToPostHoleofId.t|ToPostCheckofConstr.ttype('target,'warning)prim_token_notation_obj={to_kind:'targetconversion_kind;to_ty:GlobRef.t;to_post:((GlobRef.t*GlobRef.t*to_post_arglist)list)array;of_kind:'targetconversion_kind;of_ty:GlobRef.t;ty_name:Libnames.qualid;(* for warnings / error messages *)warning:'warning}typenumber_notation_obj=(target_kind,numnot_option)prim_token_notation_objtypestring_notation_obj=(string_target_kind,unit)prim_token_notation_objtype'atoken_kind=|TVarofId.t*'alist|TSortofSorts.t|TConstofConstant.t*'alist|TIndofinductive*'alist|TConstructofconstructor*'alist|TIntofUint63.t|TFloatofFloat64.t|TStringofPstring.t|TArrayof'aarray*'a*'a|TOthermoduleTokenValue:sigtypetvalkind:t->ttoken_kindvalmake:Environ.env->Evd.evar_map->EConstr.unsafe_judgment->tvalrepr:t->Constr.tend=structtypet=Constr.t(* Guaranteed to be in strong normal form *)letkindc=lethd,args=decompose_app_listcinmatchConstr.kindhdwith|Varid->TVar(id,args)|Sorts->TSorts|Const(c,_)->TConst(c,args)|Ind(ind,_)->TInd(ind,args)|Construct(c,_)->TConstruct(c,args)|Inti->TInti|Floatf->TFloatf|Strings->TStrings|Array(_,t,u,v)->TArray(t,u,v)|Rel_|Meta_|Evar_|Cast_|Prod_|Lambda_|LetIn_|App_|Proj_|Case_|Fix_|CoFix_->TOtherletmakeenvsigmac=letc'=Tacred.computeenvsigmac.Environ.uj_valinEConstr.Unsafe.to_constr@@c'letreprc=cendmodulePrimTokenNotation=struct(** * Code shared between Number notation and String notation *)(** Reduction
The constr [c] below isn't necessarily well-typed, since we
built it via an [mkApp] of a conversion function on a term
that starts with the right constructor but might be partially
applied.
At least [c] is known to be evar-free, since it comes from
our own ad-hoc [constr_of_glob] or from conversions such
as [rocqint_of_rawnum].
It is important to fully normalize the term, *including inductive
parameters of constructors*; see
https://github.com/rocq-prover/rocq/issues/9840 for details on what goes
wrong if this does not happen, e.g., from using the vm rather than
cbv.
*)leteval_constrenvsigma(c:Constr.t)=letc=EConstr.of_constrcinletsigma,t=Typing.type_ofenvsigmacinTokenValue.makeenvsigma{Environ.uj_val=c;Environ.uj_type=t}leteval_constr_appenvsigmac1c2=eval_constrenvsigma(mkApp(c1,[|c2|]))exceptionNotAValidPrimToken(** The uninterp function below work at the level of [glob_constr]
which is too low for us here. So here's a crude conversion back
to [constr] for the subset that concerns us.
Note that if you update [constr_of_glob], you should update the
corresponding number notation *and* string notation doc in
doc/sphinx/user-extensions/syntax-extensions.rst that describes
what it means for a term to be ground / to be able to be
considered for parsing. *)letconstr_of_globref?(allow_constant=true)envsigma=letopenEConstrinfunction|GlobRef.ConstructRefc->letsigma,c=Evd.fresh_constructor_instanceenvsigmacinsigma,mkConstructUc|GlobRef.IndRefc->letsigma,c=Evd.fresh_inductive_instanceenvsigmacinsigma,mkIndUc|GlobRef.ConstRefcwhenallow_constant||Environ.is_primitive_typeenvc->letsigma,c=Evd.fresh_constant_instanceenvsigmacinsigma,mkConstUc|_->raiseNotAValidPrimToken(** [check_glob g c] checks that glob [g] is equal to constr [c]
and returns [g] as a constr (with fresh universe instances)
or raises [NotAValidPrimToken]. *)letreccheck_globenvsigmagc=letopenEConstrinmatchDAst.getg,Constr.kindcwith|Glob_term.GRef(GlobRef.ConstructRefcasg,_),Constr.Construct(c',_)whenEnviron.QConstruct.equalenvcc'->constr_of_globrefenvsigmag|Glob_term.GRef(GlobRef.IndRefcasg,_),Constr.Ind(c',_)whenEnviron.QInd.equalenvcc'->constr_of_globrefenvsigmag|Glob_term.GRef(GlobRef.ConstRefcasg,_),Constr.Const(c',_)whenEnviron.QConstant.equalenvcc'->constr_of_globrefenvsigmag|Glob_term.GApp(gc,gcl),Constr.App(gc',gc'a)->letsigma,c=check_globenvsigmagcgc'inletsigma,cl=tryList.fold_left2_map(check_globenv)sigmagcl(Array.to_listgc'a)withInvalid_argument_->raiseNotAValidPrimTokeninsigma,mkApp(c,Array.of_listcl)|Glob_term.GInti,Constr.Inti'whenUint63.equalii'->sigma,mkInti|Glob_term.GFloatf,Constr.Floatf'whenFloat64.equalff'->sigma,mkFloatf|Glob_term.GStrings,Constr.Strings'whenPstring.equalss'->sigma,mkStrings|Glob_term.GArray(_,t,def,ty),Constr.Array(_,t',def',ty')->letsigma,u=Evd.fresh_array_instanceenvsigmainletsigma,def=check_globenvsigmadefdef'inletsigma,t=tryArray.fold_left2_map(check_globenv)sigmatt'withInvalid_argument_->raiseNotAValidPrimTokeninletsigma,ty=check_globenvsigmatyty'insigma,mkArray(u,t,def,ty)|Glob_term.GSorts,Constr.Sorts'->letsigma,s=Glob_ops.fresh_glob_sort_in_qualitysigmasinlets'=ESorts.makes'inifnot(ESorts.equalsigmass')thenraiseNotAValidPrimToken;sigma,mkSorts|_->raiseNotAValidPrimTokenletrecconstr_of_globto_postpostenvsigmag=letopenEConstrinmatchDAst.getgwith|Glob_term.GRef(r,_)->leto=List.find_opt(fun(_,r',_)->Environ.QGlobRef.equalenvrr')postinbeginmatchowith|None->constr_of_globref~allow_constant:falseenvsigmar|Some(r,_,a)->(* [g] is not a GApp so check that [post]
does not expect any actual argument
(i.e., [a] contains only ToPostHole since they mean "ignore arg") *)ifList.exists(functionToPostHole_->false|_->true)athenraiseNotAValidPrimToken;constr_of_globrefenvsigmarend|Glob_term.GApp(gc,gcl)->leto=matchDAst.getgcwith|Glob_term.GRef(r,_)->List.find_opt(fun(_,r',_)->Environ.QGlobRef.equalenvrr')post|_->Noneinbeginmatchowith|None->letsigma,c=constr_of_globto_postpostenvsigmagcinletsigma,cl=List.fold_left_map(constr_of_globto_postpostenv)sigmagclinsigma,mkApp(c,Array.of_listcl)|Some(r,_,a)->letsigma,c=constr_of_globrefenvsigmarinletrecauxsigmaagcl=matcha,gclwith|[],[]->sigma,[]|ToPostCopy::a,gc::gcl->letsigma,c=constr_of_glob[||][]envsigmagcinletsigma,cl=auxsigmaagclinsigma,c::cl|ToPostCheckr::a,gc::gcl->letsigma,c=check_globenvsigmagcrinletsigma,cl=auxsigmaagclinsigma,c::cl|ToPostAsi::a,gc::gcl->letsigma,c=constr_of_globto_postto_post.(i)envsigmagcinletsigma,cl=auxsigmaagclinsigma,c::cl|ToPostHole_::post,_::gcl->auxsigmapostgcl|[],_::_|_::_,[]->raiseNotAValidPrimTokeninletsigma,cl=auxsigmaagclinsigma,mkApp(c,Array.of_listcl)end|Glob_term.GInti->sigma,mkInti|Glob_term.GFloatf->sigma,mkFloatf|Glob_term.GStrings->sigma,mkStrings|Glob_term.GArray(_,t,def,ty)->letsigma,u'=Evd.fresh_array_instanceenvsigmainletsigma,def'=constr_of_globto_postpostenvsigmadefinletsigma,t'=Array.fold_left_map(constr_of_globto_postpostenv)sigmatinletsigma,ty'=constr_of_globto_postpostenvsigmatyinsigma,mkArray(u',t',def',ty')|Glob_term.GSortgs->letsigma,c=Glob_ops.fresh_glob_sort_in_qualitysigmagsinsigma,mkSortc|_->raiseNotAValidPrimTokenletconstr_of_globto_postenvsigma(Glob_term.AnyGlobConstrg)=letpost=matchto_postwith[||]->[]|_->to_post.(0)inconstr_of_globto_postpostenvsigmagletrecglob_of_constrtoken_kind?locenvsigmac=matchConstr.kindcwith|App(c,ca)->letc=glob_of_constrtoken_kind?locenvsigmacinletcel=List.map(glob_of_constrtoken_kind?locenvsigma)(Array.to_listca)inDAst.make?loc(Glob_term.GApp(c,cel))|Construct(c,_)->DAst.make?loc(Glob_term.GRef(GlobRef.ConstructRefc,None))|Const(c,_)->DAst.make?loc(Glob_term.GRef(GlobRef.ConstRefc,None))|Ind(ind,_)->DAst.make?loc(Glob_term.GRef(GlobRef.IndRefind,None))|Varid->DAst.make?loc(Glob_term.GRef(GlobRef.VarRefid,None))|Inti->DAst.make?loc(Glob_term.GInti)|Floatf->DAst.make?loc(Glob_term.GFloatf)|Strings->DAst.make?loc(Glob_term.GStrings)|Array(u,t,def,ty)->letdef'=glob_of_constrtoken_kind?locenvsigmadefandt'=Array.map(glob_of_constrtoken_kind?locenvsigma)tandty'=glob_of_constrtoken_kind?locenvsigmatyinDAst.make?loc(Glob_term.GArray(None,t',def',ty'))|SortSorts.SProp->DAst.make?loc(Glob_term.GSortGlob_ops.glob_SProp_sort)|SortSorts.Prop->DAst.make?loc(Glob_term.GSortGlob_ops.glob_Prop_sort)|SortSorts.Set->DAst.make?loc(Glob_term.GSortGlob_ops.glob_Set_sort)|Sort(Sorts.Type_)->DAst.make?loc(Glob_term.GSortGlob_ops.glob_Type_sort)|_->Loc.raise?loc(PrimTokenNotationError(token_kind,env,sigma,UnexpectedTermc))letmkGApp?lochdargs=matchargswith|[]->hd|_::_->mkGApp?lochdargsletrecglob_of_tokentoken_kind?locenvsigmac=matchTokenValue.kindcwith|TConstruct(c,l)->letce=DAst.make?loc(Glob_term.GRef(GlobRef.ConstructRefc,None))inletcel=List.map(glob_of_tokentoken_kind?locenvsigma)linmkGApp?loccecel|TConst(c,l)->letce=DAst.make?loc(Glob_term.GRef(GlobRef.ConstRefc,None))inletcel=List.map(glob_of_tokentoken_kind?locenvsigma)linmkGApp?loccecel|TInd(ind,l)->letce=DAst.make?loc(Glob_term.GRef(GlobRef.IndRefind,None))inletcel=List.map(glob_of_tokentoken_kind?locenvsigma)linmkGApp?loccecel|TVar(id,l)->letce=DAst.make?loc(Glob_term.GRef(GlobRef.VarRefid,None))inletcel=List.map(glob_of_tokentoken_kind?locenvsigma)linmkGApp?loccecel|TInti->DAst.make?loc(Glob_term.GInti)|TFloatf->DAst.make?loc(Glob_term.GFloatf)|TStrings->DAst.make?loc(Glob_term.GStrings)|TArray(t,def,ty)->letdef'=glob_of_tokentoken_kind?locenvsigmadefandt'=Array.map(glob_of_tokentoken_kind?locenvsigma)tandty'=glob_of_tokentoken_kind?locenvsigmatyinDAst.make?loc(Glob_term.GArray(None,t',def',ty'))|TSortSorts.SProp->DAst.make?loc(Glob_term.GSortGlob_ops.glob_SProp_sort)|TSortSorts.Prop->DAst.make?loc(Glob_term.GSortGlob_ops.glob_Prop_sort)|TSortSorts.Set->DAst.make?loc(Glob_term.GSortGlob_ops.glob_Set_sort)|TSort(Sorts.Type_|Sorts.QSort_)->DAst.make?loc(Glob_term.GSortGlob_ops.glob_Type_sort)|TOther->letc=TokenValue.reprcinLoc.raise?loc(PrimTokenNotationError(token_kind,env,sigma,UnexpectedTermc))letno_such_prim_tokenuninterpreted_token_kind?loc?errmsgty=CErrors.user_err?loc(str("Cannot interpret this "^uninterpreted_token_kind^" as a value of type ")++pr_qualidty++pr_opt(funerrmsg->surrounderrmsg)errmsg)letrecpostprocessenvtoken_kind?loctyto_postpostg=letg',gl=matchDAst.getgwithGlob_term.GApp(g,gl)->g,gl|_->g,[]inleto=matchDAst.getg'with|Glob_term.GRef(r,None)->List.find_opt(fun(r',_,_)->Environ.QGlobRef.equalenvrr')post|_->NoneinmatchowithNone->g|Some(_,r,a)->letrecfnagl=matcha,glwith|[],[]->[]|ToPostHoleid::a,gl->lete=GImplicitArg(r,(n,id),true)inleth=DAst.make?loc(Glob_term.GHolee)inh::f(n+1)agl|(ToPostCopy|ToPostCheck_)::a,g::gl->g::f(n+1)agl|ToPostAsc::a,g::gl->postprocessenvtoken_kind?loctyto_postto_post.(c)g::f(n+1)agl|[],_::_|_::_,[]->no_such_prim_tokentoken_kind?loctyinletgl=f1aglinletg=DAst.make?loc(Glob_term.GRef(r,None))inDAst.make?loc(Glob_term.GApp(g,gl))letglob_of_constrtoken_kindty?locenvsigmato_postc=letg=glob_of_constrtoken_kind?locenvsigmacinmatchto_postwith[||]->g|_->postprocessenvtoken_kind?loctyto_postto_post.(0)gletglob_of_tokentoken_kindty?locenvsigmato_postc=letg=glob_of_tokentoken_kind?locenvsigmacinmatchto_postwith[||]->g|_->postprocessenvtoken_kind?loctyto_postto_post.(0)gletinterp_optionuninterpreted_token_kindtoken_kindty?locenvsigmato_postc=matchTokenValue.kindcwith|TConstruct(_Some,[_;c])->glob_of_tokentoken_kindty?locenvsigmato_postc|TConstruct(_None,[_])->no_such_prim_tokenuninterpreted_token_kind?locty|x->letc=TokenValue.reprcinLoc.raise?loc(PrimTokenNotationError(token_kind,env,sigma,UnexpectedNonOptionTermc))letinterp_erroruninterpreted_token_kindtoken_kindty?locenvsigmato_postc=matchTokenValue.kindcwith|TConstruct((_,1),[_;_;c])->glob_of_tokentoken_kindty?locenvsigmato_postc|TConstruct((_,2),[_;_;msg])->leterrmsg=Termops.Internal.print_constr_envenvsigma(EConstr.of_constr@@TokenValue.reprmsg)inno_such_prim_tokenuninterpreted_token_kind?loc~errmsgty|x->letc=TokenValue.reprcinLoc.raise?loc(PrimTokenNotationError(token_kind,env,sigma,UnexpectedNonOptionTermc))letuninterp_optionc=matchTokenValue.kindcwith|TConstruct(_Some,[_;x])->x|_->raiseNotAValidPrimTokenletuninterp_errorc=matchTokenValue.kindcwith|TConstruct((_,1),[_;_;x])->x|_->raiseNotAValidPrimTokenletuninterpto_rawon=letenv=Global.env()inletsigma=Evd.from_envenvinletsigma,of_ty=Evd.fresh_globalenvsigmao.of_tyinletof_ty=EConstr.Unsafe.to_constrof_tyintryletsigma,n=constr_of_globo.to_postenvsigmaninletn=EConstr.Unsafe.to_constrninletc=eval_constr_appenvsigmaof_tyninletc=matchsndo.of_kindwith|Direct->c|Option->uninterp_optionc|Error->uninterp_errorcinSome(to_raw(fsto.of_kind,c))with|Type_errors.TypeError_|Pretype_errors.PretypeError_->None(* cf. eval_constr_app *)|NotAValidPrimToken->None(* all other functions except NumTok.Signed.of_bigint *)endletz_two=Z.of_int2(** Conversion from bigint to int63 *)letint63_of_pos_biginti=Uint63.of_int64(Z.to_int64i)moduleNumbers=struct(** * Number notation *)openPrimTokenNotationletwarn_large_num=CWarnings.create~name:"large-number"~category:CWarnings.CoreCategories.numbers(funty->strbrk"Stack overflow or segmentation fault happens when "++strbrk"working with large numbers in "++pr_qualidty++strbrk" (threshold may vary depending"++strbrk" on your system limits and on the command executed).")letwarn_abstract_large_num=CWarnings.create~name:"abstract-large-number"~category:CWarnings.CoreCategories.numbers(fun(ty,f)->strbrk"To avoid stack overflow, large numbers in "++pr_qualidty++strbrk" are interpreted as applications of "++Termops.pr_global_env(Global.env())f++strbrk".")(***********************************************************************)(** ** Conversion between Rocq [Decimal.int] and internal raw string *)(** Decimal.Nil has index 1, then Decimal.D0 has index 2 .. Decimal.D9 is 11 *)letdigit_of_charc=assert('0'<=c&&c<='9'||'a'<=c&&c<='f');ifc<='9'thenChar.codec-Char.code'0'+2elseChar.codec-Char.code'a'+12letchar_of_digitn=assert(2<=n&&n<=17);ifn<=11thenChar.chr(n-2+Char.code'0')elseChar.chr(n-12+Char.code'a')letrocquint_of_rawnumesigindscn=letuint=matchcwithCDec->inds.dec_uint|CHex->inds.hex_uintinletnil=mkConstructesig(uint,1)inmatchnwithNone->nil|Somen->letstr=NumTok.UnsignedNat.to_stringninletstr=matchcwith|CDec->str|CHex->String.substr2(String.lengthstr-2)in(* cut "0x" *)letrecdo_charssiacc=ifi<0thenaccelseletdg=mkConstructesig(uint,digit_of_chars.[i])indo_charss(i-1)(mkApp(dg,[|acc|]))indo_charsstr(String.lengthstr-1)nilletrocqint_of_rawnumesigindsc(sign,n)=letind=matchcwithCDec->inds.dec_int|CHex->inds.hex_intinletuint=rocquint_of_rawnumesigindsc(Somen)inletpos_neg=matchsignwithSPlus->1|SMinus->2inmkApp(mkConstructesig(ind,pos_neg),[|uint|])letrocqnumber_of_rawnumesigindscn=letind=matchcwithCDec->inds.decimal|CHex->inds.hexadecimalinleti,f,e=NumTok.Signed.to_int_frac_and_exponentninleti=rocqint_of_rawnumesiginds.intciinletf=rocquint_of_rawnumesiginds.intcfinmatchewith|None->mkApp(mkConstructesig(ind,1),[|i;f|])(* (D|Hexad)ecimal *)|Somee->lete=rocqint_of_rawnumesiginds.intCDeceinmkApp(mkConstructesig(ind,2),[|i;f;e|])(* (D|Hexad)ecimalExp *)letmkDecHexesigindcn=matchcwith|CDec->mkApp(mkConstructesig(ind,1),[|n|])(* (UInt|Int|)Decimal *)|CHex->mkApp(mkConstructesig(ind,2),[|n|])(* (UInt|Int|)Hexadecimal *)letrocqnumber_of_rawnumesigindsn=letc=NumTok.Signed.classifyninletn=rocqnumber_of_rawnumesigindscninmkDecHexesiginds.numbercnletrocquint_of_rawnumesigindsn=letc=NumTok.UnsignedNat.classifyninletn=rocquint_of_rawnumesigindsc(Somen)inmkDecHexesiginds.uintcnletrocqint_of_rawnumesigindsn=letc=NumTok.SignedNat.classifyninletn=rocqint_of_rawnumesigindscninmkDecHexesiginds.intcnletrawnum_of_rocquintclc=letrecof_uint_loopcbuf=matchTokenValue.kindcwith|TConstruct((_,1),_)(* Nil *)->()|TConstruct((_,n),[a])(* D0 to Df *)->let()=Buffer.add_charbuf(char_of_digitn)inof_uint_loopabuf|_->raiseNotAValidPrimTokeninletbuf=Buffer.create64inifcl=CHexthen(Buffer.add_charbuf'0';Buffer.add_charbuf'x');let()=of_uint_loopcbufinifInt.equal(Buffer.lengthbuf)(matchclwithCDec->0|CHex->2)then(* To avoid ambiguities between Nil and (D0 Nil), we choose
to not display Nil alone as "0" *)raiseNotAValidPrimTokenelseNumTok.UnsignedNat.of_string(Buffer.contentsbuf)letrawnum_of_rocqintclc=matchTokenValue.kindcwith|TConstruct((_,1),[c'])(* Pos *)->(SPlus,rawnum_of_rocquintclc')|TConstruct((_,2),[c'])(* Neg *)->(SMinus,rawnum_of_rocquintclc')|_->raiseNotAValidPrimTokenletrawnum_of_rocqnumberclc=letof_ifeife=letn=rawnum_of_rocqintcliinletf=trySome(rawnum_of_rocquintclf)withNotAValidPrimToken->Noneinlete=matchewithNone->None|Somee->Some(rawnum_of_rocqintCDece)inNumTok.Signed.of_int_frac_and_exponentnfeinmatchTokenValue.kindcwith|TConstruct(_,[i;f])->of_ifeifNone|TConstruct(_,[i;f;e])->of_ifeif(Somee)|_->raiseNotAValidPrimTokenletdestDecHexc=matchTokenValue.kindcwith|TConstruct((_,1),[c'])(* (UInt|Int|)Decimal *)->CDec,c'|TConstruct((_,2),[c'])(* (UInt|Int|)Hexadecimal *)->CHex,c'|_->raiseNotAValidPrimTokenletrawnum_of_rocqnumberc=letcl,c=destDecHexcinrawnum_of_rocqnumberclcletrawnum_of_rocquintc=letcl,c=destDecHexcinrawnum_of_rocquintclcletrawnum_of_rocqintc=letcl,c=destDecHexcinrawnum_of_rocqintclc(***********************************************************************)(** ** Conversion between Rocq [Z] and internal bigint *)(** First, [positive] from/to bigint *)letrecpos_of_bigintesigpostyn=matchZ.div_remnz_twowith|(q,rem)whenrem=Z.zero->letc=mkConstructesig(posty,2)in(* xO *)mkApp(c,[|pos_of_bigintesigpostyq|])|(q,_)whennot(Z.equalqZ.zero)->letc=mkConstructesig(posty,1)in(* xI *)mkApp(c,[|pos_of_bigintesigpostyq|])|(q,_)->mkConstructesig(posty,3)(* xH *)letrecbigint_of_posc=matchTokenValue.kindcwith|TConstruct((_,3),[])->(* xH *)Z.one|TConstruct((_,1),[d])->(* xI *)Z.addZ.one(Z.mulz_two(bigint_of_posd))|TConstruct((_,2),[d])->(* xO *)Z.mulz_two(bigint_of_posd)|x->raiseNotAValidPrimToken(** Now, [Z] from/to bigint *)letz_of_bigintesig{z_ty;pos_ty}n=ifZ.(equalnzero)thenmkConstructesig(z_ty,1)(* Z0 *)elselet(s,n)=ifZ.(leqzeron)then(2,n)(* Zpos *)else(3,Z.negn)(* Zneg *)inletc=mkConstructesig(z_ty,s)inmkApp(c,[|pos_of_bigintesigpos_tyn|])letbigint_of_zz=matchTokenValue.kindzwith|TConstruct((_,1),[])->(* Z0 *)Z.zero|TConstruct((_,2),[d])->(* Zpos *)bigint_of_posd|TConstruct((_,3),[d])->(* Zneg *)Z.neg(bigint_of_posd)|_->raiseNotAValidPrimToken(** Now, [Int63] from/to bigint *)letint63_of_pos_bigint?locn=leti=int63_of_pos_bigintninmkIntileterror_overflow?locn=CErrors.user_err?locPp.(str"Overflow in int63 literal: "++str(Z.to_stringn)++str".")letrocqpos_neg_int63_of_bigint?locesigind(sign,n)=letuint=int63_of_pos_bigint?locninletpos_neg=matchsignwithSPlus->1|SMinus->2inmkApp(mkConstructesig(ind,pos_neg),[|uint|])letinterp_int63?locesigindn=letsign=ifZ.(comparenzero>=0)thenSPluselseSMinusinletan=Z.absninifZ.(ltan(powz_two63))thenrocqpos_neg_int63_of_bigint?locesigind(sign,an)elseerror_overflow?locnletwarn_inexact_float=CWarnings.create~name:"inexact-float"~category:CWarnings.CoreCategories.parsing(fun(sn,f)->Pp.strbrk(Printf.sprintf"The constant %s is not a binary64 floating-point value. \
A closest value %s will be used and unambiguously printed %s."sn(Float64.to_hex_stringf)(Float64.to_stringf)))letinterp_float64?locn=letsn=NumTok.Signed.to_stringninletf=Float64.of_stringsnin(* return true when f is not exactly equal to n,
this is only used to decide whether or not to display a warning
and does not play any actual role in the parsing *)letinexact()=matchFloat64.classifyfwith|Float64.(PInf|NInf|NaN)->true|Float64.(PZero|NZero)->not(NumTok.Signed.is_zeron)|Float64.(PNormal|NNormal|PSubn|NSubn)->letm,e=let(_,i),f,e=NumTok.Signed.to_int_frac_and_exponentninleti=NumTok.UnsignedNat.to_stringiinletf=matchfwith|None->""|Somef->NumTok.UnsignedNat.to_stringfinlete=matchewith|None->"0"|Somee->NumTok.SignedNat.to_stringeinZ.of_string(i^f),(tryint_of_stringewithFailure_->0)-String.lengthfinletm',e'=letm',e'=Float64.frshiftexpfinletm'=Float64.normfr_mantissam'inlete'=Uint63.to_int_mine'4096-Float64.eshift-53inZ.of_string(Uint63.to_stringm'),e'inletc2,c5=Z.(of_int2,of_int5)in(* check m*5^e <> m'*2^e' *)letcheckmem'e'=not(Z.(equal(mulm(powc5e))(mulm'(powc2e'))))in(* check m*5^e*2^e' <> m' *)letcheck'mee'm'=not(Z.(equal(mul(mulm(powc5e))(powc2e'))m'))in(* we now have to check m*10^e <> m'*2^e' *)ife>=0thenife<=e'thencheckmem'(e'-e)elsecheck'me(e-e')m'else(* e < 0 *)ife'<=ethencheckm'(-e)m(e-e')elsecheck'm'(-e)(e'-e)minifNumTok.(Signed.classifyn=CDec)&&inexact()thenwarn_inexact_float?loc(sn,f);mkFloatfletbigint_of_int63c=matchTokenValue.kindcwith|TInti->Z.of_int64(Uint63.to_int64i)|_->raiseNotAValidPrimTokenletbigint_of_rocqpos_neg_int63c=matchTokenValue.kindcwith|TConstruct((_,1),[c'])(* Pos *)->bigint_of_int63c'|TConstruct((_,2),[c'])(* Neg *)->Z.neg(bigint_of_int63c')|_->raiseNotAValidPrimTokenletuninterp_float64~print_floatc=matchTokenValue.kindcwith|TFloatfwhennot(Float64.is_infinityf||Float64.is_neg_infinityf||Float64.is_nanf)&&print_float->NumTok.Signed.of_string(Float64.to_stringf)|_->raiseNotAValidPrimTokenletinterpo?locn=beginmatcho.warning,nwith|Warningthreshold,nwhenNumTok.Signed.is_bigger_int_thannthreshold->warn_large_numo.ty_name|_->()end;letenv=Global.env()inletsigma=ref(Evd.from_envenv)inletesig=env,sigmainletc=matchfsto.to_kind,NumTok.Signed.to_intnwith|Intint_ty,Somen->rocqint_of_rawnumesigint_tyn|UIntint_ty,Some(SPlus,n)->rocquint_of_rawnumesigint_tyn|Zz_pos_ty,Somen->z_of_bigintesigz_pos_ty(NumTok.SignedNat.to_bigintn)|Int63pos_neg_int63_ty,Somen->interp_int63?locesigpos_neg_int63_ty.pos_neg_int63_ty(NumTok.SignedNat.to_bigintn)|(Int_|UInt_|Z_|Int63_),_->no_such_prim_token"number"?loco.ty_name|Float64,_->interp_float64?locn|Numbernumber_ty,_->rocqnumber_of_rawnumesignumber_tyninletsigma=!sigmainletsigma,to_ty=Evd.fresh_globalenvsigmao.to_tyinletto_ty=EConstr.Unsafe.to_constrto_tyinmatcho.warning,sndo.to_kindwith|Abstractthreshold,DirectwhenNumTok.Signed.is_bigger_int_thannthreshold->warn_abstract_large_num(o.ty_name,o.to_ty);assert(Array.lengtho.to_post=0);glob_of_constr"number"o.ty_name?locenvsigmao.to_post(mkApp(to_ty,[|c|]))|_->letres=eval_constr_appenvsigmato_tycinmatchsndo.to_kindwith|Direct->glob_of_token"number"o.ty_name?locenvsigmao.to_postres|Option->interp_option"number""number"o.ty_name?locenvsigmao.to_postres|Error->interp_error"number""number"o.ty_name?locenvsigmao.to_postresletuninterp~print_floaton=PrimTokenNotation.uninterpbeginfunction|(Int_,c)->NumTok.Signed.of_int(rawnum_of_rocqintc)|(UInt_,c)->NumTok.Signed.of_nat(rawnum_of_rocquintc)|(Z_,c)->NumTok.Signed.of_bigintCDec(bigint_of_zc)|(Int63_,c)->NumTok.Signed.of_bigintCDec(bigint_of_rocqpos_neg_int63c)|(Float64,c)->uninterp_float64~print_floatc|(Number_,c)->rawnum_of_rocqnumbercendonendmoduleStrings=struct(** * String notation *)openPrimTokenNotationletq_refn=n|>Rocqlib.lib_refletq_list()=q_ref"core.list.type"letq_byte()=q_ref"core.byte.type"letforce_indq=matchqwith|GlobRef.IndRefi->i|_->raiseNot_foundletlocate_list()=force_ind(q_list())letlocate_byte()=force_ind(q_byte())(***********************************************************************)(** ** Conversion between Rocq [list Byte.byte] and internal raw string *)letrocqbyte_of_char_codeesigbytec=mkConstructesig(byte,1+c)letrocqbyte_of_string?locesigbytes=letp=ifInt.equal(String.lengths)1thenint_of_chars.[0]elseletn=ifInt.equal(String.lengths)3&&is_digits.[0]&&is_digits.[1]&&is_digits.[2]thenint_of_stringselse256inifn<256thennelseuser_err?loc(str"Expects a single character or a three-digit ASCII code.")inrocqbyte_of_char_codeesigbytepletrocqbyte_of_charesigbytec=rocqbyte_of_char_codeesigbyte(Char.codec)letpstring_of_string?locs=matchPstring.of_stringswith|Somes->Constr.mkStrings|None->user_err?loc(str"String literal would be too large on a 32-bits system.")letmake_ascii_stringn=ifn>=32&&n<=126thenString.make1(char_of_intn)elsePrintf.sprintf"%03d"nletchar_code_of_rocqbytec=matchTokenValue.kindcwith|TConstruct((_,c),[])->c-1|_->raiseNotAValidPrimTokenletstring_of_rocqbytec=make_ascii_string(char_code_of_rocqbytec)letstring_of_pstringc=matchTokenValue.kindcwith|TStrings->Pstring.to_strings|_->raiseNotAValidPrimTokenletrocqlist_byte_of_stringesigbyte_tylist_tystr=letcbyte=mkIndesigbyte_tyinletnil=mkApp(mkConstructesig(list_ty,1),[|cbyte|])inletconsxxs=mkApp(mkConstructesig(list_ty,2),[|cbyte;x;xs|])inletrecdo_charssiacc=ifi<0thenaccelseletb=rocqbyte_of_charesigbyte_tys.[i]indo_charss(i-1)(consbacc)indo_charsstr(String.lengthstr-1)nil(* N.B. We rely on the fact that [nil] is the first constructor and [cons] is the second constructor, for [list] *)letstring_of_rocqlist_bytec=letrecof_rocqlist_byte_loopcbuf=matchTokenValue.kindcwith|TConstruct(_nil,[_ty])->()|TConstruct(_cons,[_ty;b;c])->let()=Buffer.add_charbuf(Char.chr(char_code_of_rocqbyteb))inof_rocqlist_byte_loopcbuf|_->raiseNotAValidPrimTokeninletbuf=Buffer.create64inlet()=of_rocqlist_byte_loopcbufinBuffer.contentsbufletinterpo?locn=letbyte_ty=locate_byte()inletlist_ty=locate_list()inletenv=Global.env()inletsigma=ref(Evd.from_envenv)inletesig=env,sigmainletc=matchfsto.to_kindwith|ListByte->rocqlist_byte_of_stringesigbyte_tylist_tyn|Byte->rocqbyte_of_string?locesigbyte_tyn|PString->pstring_of_string?locninletsigma=!sigmainletsigma,to_ty=Evd.fresh_globalenvsigmao.to_tyinletto_ty=EConstr.Unsafe.to_constrto_tyinletres=eval_constr_appenvsigmato_tycinmatchsndo.to_kindwith|Direct->glob_of_token"string"o.ty_name?locenvsigmao.to_postres|Option->interp_option"string""string"o.ty_name?locenvsigmao.to_postres|Error->interp_error"string""string"o.ty_name?locenvsigmao.to_postresletuninterpon=PrimTokenNotation.uninterpbeginfunction|(ListByte,c)->string_of_rocqlist_bytec|(Byte,c)->string_of_rocqbytec|(PString,c)->string_of_pstringcendonendlethashtbl_check_and_setallow_overwriteuidfheq=matchHashtbl.findhuidwith|exceptionNot_found->Hashtbl.addhuidf|_whenallow_overwrite->Hashtbl.addhuidf|gwheneqfg->()|_->user_err(str"Unique identifier "++struid++str" already used to register a number or string (un)interpreter.")letregister_gen_interpretationallow_overwrite(uid:string)(interp,uninterp):prim_token_uid=hashtbl_check_and_setallow_overwriteuidinterpprim_token_interpretersInnerPrimToken.interp_eq;hashtbl_check_and_setallow_overwriteuiduninterpprim_token_uninterpretersInnerPrimToken.uninterp_eq;uidletregister_rawnumeral_interpretation?(allow_overwrite=false)uid(interp,uninterp)=register_gen_interpretationallow_overwriteuid(InnerPrimToken.RawNumInterpinterp,InnerPrimToken.RawNumUninterpuninterp)letregister_bignumeral_interpretation?(allow_overwrite=false)uid(interp,uninterp)=register_gen_interpretationallow_overwriteuid(InnerPrimToken.BigNumInterpinterp,InnerPrimToken.BigNumUninterpuninterp)letregister_string_interpretation?(allow_overwrite=false)uid(interp,uninterp)=register_gen_interpretationallow_overwriteuid(InnerPrimToken.StringInterpinterp,InnerPrimToken.StringUninterpuninterp)typeprim_token_interp_info=|Uidofprim_token_uid|NumberNotationofnumber_notation_obj|StringNotationofstring_notation_objletdo_interp?locinfop=letinterp=matchinfowith|Uiduid->Hashtbl.findprim_token_interpretersuid|NumberNotationo->InnerPrimToken.RawNumInterp(Numbers.interpo)|StringNotationo->InnerPrimToken.StringInterp(Strings.interpo)inInnerPrimToken.do_interp?locinterppletdo_uninterp~print_floatinfoc=tryletuninterp=matchinfowith|Uiduid->Hashtbl.findprim_token_uninterpretersuid|NumberNotationo->InnerPrimToken.RawNumUninterp(Numbers.uninterp~print_floato)|StringNotationo->InnerPrimToken.StringUninterp(Strings.uninterpo)inInnerPrimToken.do_uninterpuninterp(AnyGlobConstrc)withNot_found->Noneletcan_interpuidn=letopenInnerPrimTokeninmatchn,uidwith|Constrexpr.Number_,NumberNotation_->true|_,NumberNotation_->false|String_,StringNotation_->true|_,StringNotation_->false|_,Uiduid->letinterp=Hashtbl.find_optprim_token_interpretersuidinmatchn,interpwith|Constrexpr.Number_,Some(RawNumInterp_|BigNumInterp_)->true|String_,Some(StringInterp_)->true|_->false