Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file zarith_ppx.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161openMigrate_parsetree(* Define the rewriter on OCaml 4.05 AST *)openAst_405letocaml_version=Versions.ocaml_405moduleStre=StropenParsetreeopenAst_helpermoduleAM=Ast_mapperleterrorppf=Format.kasprintf(funs->letloc=!default_locinExp.extension~loc@@AM.extension_of_error(Location.error~locs))ppfletmklidmlid=Exp.ident{Location.loc=!default_loc;txt=Longident.(Ldot(Lidentm,lid))}letappmlidl=Exp.(apply(mklidmlid)(List.map(fune->Asttypes.Nolabel,e)l))letintegerms=letx=Z.of_stringsinifx=Z.zerothenmklidm"zero"elseifx=Z.onethenmklidm"one"elseifx=Z.minus_onethenmklidm"minus_one"elseifZ.numbitsx<31thenappm"of_int"[Exp.constant@@Const.int@@Z.to_intx]elseifZ.fits_int32xthenappm"of_int32"[Exp.constant@@Const.int32@@Z.to_int32x]elseifZ.fits_int64xthenappm"of_int64"[Exp.constant@@Const.int64@@Z.to_int64x]elseappm"of_string"[Exp.constant@@Const.strings]letinteger_z=integer"Z"letinteger_q=integer"Q"(* When the programmer writes 9007199254740993.0q, they want the rational for
9007199254740993, not for the closest double-precision number to that
9007199254740992.
Similarly, when the programmer writes 0.1q, they want the rational for 1/10,
not for 1000000000000000055511151231257827021181583404541015625/10000000000000000000000000000000000000000000000000000000.
For all these reasons float_of_string must not be used here.
Instead we use a regular expression to get the pieces and recombine them.
The format is I.FeX
We produce I * 10^E + F * 10^k where k = E - |F|
This fits in an integer if E >= |F|
*)letre=Stre.regexp_case_fold{|^\(-?\)\([0-9]+\)\(\.\([0-9]+\)?\)?\(e\([+-]?[0-9]+\)\)?$|}letmatch_floats=ifStre.string_matchres0thenletsign=Stre.matched_group1s=""inleti=Stre.matched_group2sinletf=trySome(Stre.matched_group4s)withNot_found->Noneinlete=tryint_of_string@@Stre.matched_group6swithNot_found->0inSome(sign,i,e,f)elseNoneletten=app"Z""of_int"[Exp.constant@@Const.int10]lete10n=app"Z""pow"[ten;Exp.constant@@Const.intn]letaddm=appm"add"letneg_ifbmx=ifbthenxelseappm"neg"[x]letmul_10expan=ifn=0then`Zaelseifn<0then`Q(app"Q""make"[a;e10(-n)])else`Z(app"Z""mul"[a;e10n])letaddxab=matcha,bwith|`Za,`Zb->`Z(add"Z"[a;b])|`Za,`Qb|`Qb,`Za->`Q(add"Q"[app"Q""of_bigint"[a];b])|`Qa,`Qb->`Q(add"Q"[a;b])letmake_floatief=leta=mul_10exp(integer_zi)einmatchfwith|None->a|Somef->letb=mul_10exp(integer_zf)(e-String.lengthf)inaddxabletis_float_exas=String.lengths>=2&&letpre=String.subs02inpre="0x"||pre="0X"letfail_exa()=error"%a"Format.pp_print_text"Hexadecimal floating point numbers are not accepted. \
Please use hexadecimal integers, or regular floating point numbers."letfloat_zs=ifis_float_exasthenfail_exa()elsematchmatch_floatswith|None->error"This literal is not a valid zarith integer."|Some(pos,i,e,f)->matchmake_floatiefwith|`Q_->error"This literal does not fit in an integer. You should use a rational number."|`Zz->neg_ifpos"Z"zletfloat_qs=ifis_float_exasthenfail_exa()elsematchmatch_floatswith|None->error"This literal is not a valid zarith rational number."|Some(pos,i,e,f)->neg_ifpos"Q"@@matchmake_floatiefwith|`Qq->q|`Zz->app"Q""of_bigint"[z](** Boilerplate to recognize z and q prefixes. *)letexprmapperexpr=letloc=expr.pexp_locinmatchexpr.pexp_descwith|Pexp_constant(Pconst_integer(s,Some'z'))->with_default_locloc@@fun()->integer_zs|Pexp_constant(Pconst_float(s,Some'z'))->with_default_locloc@@fun()->float_zs|Pexp_constant(Pconst_integer(s,Some'q'))->with_default_locloc@@fun()->integer_qs|Pexp_constant(Pconst_float(s,Some'q'))->with_default_locloc@@fun()->float_qs|_->AM.default_mapper.AM.exprmapperexprletmapper={AM.default_mapperwithAM.expr}(** Register the rewriter in the driver *)let()=Driver.register~name:"zarith-ppx"ocaml_version(fun_config_cookies->mapper)(*
* Copyright (c) 2019 Gabriel Radanne <drupyog@zoho.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)