Conversation
|
Note that there is the question of making this resilient to changes in OCaml itself. using either ppx_tools or ocaml-migrate-parsetree could eliminate the issue. |
ppx.ml
Outdated
| (List.map (fun e -> Asttypes.Nolabel, e) l)) | ||
|
|
||
| let try_int s = | ||
| try `Int32 (Int32.of_string s) |
There was a problem hiding this comment.
Is it on purpose that there is no attempt to fit the integer in a native (I mean 31- or 63-bit) int here? On 32-bit platforms, it makes a difference because int values are unboxed whereas Int32.t values are allocated.
There was a problem hiding this comment.
Yes, I though about that. We could definitely check if they are small enough to fit. I don't want to emit integers literals that are bigger than 31 bits though, as it's going to annoy people that do cross-compilation greatly.
There was a problem hiding this comment.
While implementing this, I realized there is a bug in the implementation:
# 0x8fffffffl ;;
- : int32 = -1879048193l
# 0x8fffffffz ;;
- : Z.t = -1879048193Which is a bit unfortunate. I'm not sure yet what's the best way to solve it. Until now, I tried to avoid using zarith inside the ppx itself but maybe It would be best, to avoid this kind of issues ...
ppx.ml
Outdated
| let integer_z = integer "Z" | ||
| let integer_q = integer "Q" | ||
|
|
||
| (* float_of_string doesn't error on floats that are not representable so |
There was a problem hiding this comment.
Sorry to comment on a comment, but as phrased this confused me more than it helped me.
How about replacing the sentence “float_of_string doesn't error on floats …” by:
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.
There was a problem hiding this comment.
I changed the comment using your version, thanks!
|
Concerning your surprises with Int32.of_string et al: It is intentional that hexadecimal or octal strings in the [2^31, 2^32[ range are converted to negative integers. But that's definitely not what you want here. One possible solution is to compare the sign of the string (does the string start with a minus sign?) with that of the integer returned by the "of_string" function. If they differ, you are in the 2^31 to 2^32 range and an overflow occurred. Note that Int32.of_string raises an exception if the result is < -2^31 or >= 2^32. So, by combining the exception with the explicit sign check, you're safe. |
|
@xavierleroy The behavior absolutely makes sense in the context of integers with a limited size. I'm just not used to writing large constants in hexa. :) |
|
It appears that the ppx preprocessor is a standalone executable. In which case, I see no reason not to use ZArith inside the ppx. |
|
One year later, where are we with this pull request? |
|
Oh, I completely forgot about that one. |
|
Ok, I now use Zarith, exports to integer when it fits, and added a test for the bug found in the discussion above. The only remaining annoying point is the portability across OCaml versions. The best way to solve it is clearly to use ocaml-migrate-parsetree, but I'm not sure how you feel about adding an optional dependencies to Zarith ... |
|
Wouldn't it make sense to distribute a separate |
|
I like the idea of having two distinct OPAM packages so that the PPX package can depend on ocaml-migrate-parsetree. |
|
Right, I also agree, I just didn't have the courage to wrestle with the build system... Let me see what I can do after the ICFP deadline. :) |
|
I tried to make the makefile build different packages. I really have no idea how to do it, so instead I wrote a completely independent package in a subdirectory. Since we're building a ppx, it uses jbuilder, as that makes building driverified ppxs much easier. If/When someone jbuilderify the rest of the library, it will be possible to build zarith and the ppx either separately or together easily. For now, it can only be done separately. It's now using omp and is compatible with ppx drivers. I also added a |
562c2e6 to
72365b5
Compare
|
So, feedback on the last version of the patch? :) |
|
This is now hosted in https://github.com/Drup/zarith-ppx and released. |
I added a little ppx that recognizes two new suffix for integers and floating pointer numbers: 'z' and 'q' for the
ZandQmodules respectively.Here is a bunch of things you can do with it:
The ppx does not have any dependency and should be cross-compilation proof (the ppx does not link with zarith itself and do not make assumption about the wordsize of the target). At the moment, it does not handle the hexa notation of floats, although that could be added.
The ppx is only compiled when ocaml >= 4.03. I tried to make it all fit in the configure/makefile stuff. I hope it's correct, my makefile-fu is not extremly strong. I also added some tests.
The code is not particularly elegant, especially the float part, in particular because we do not use zarith itself.
The transformation is strictly local. We could lift the constant definition to be globally bound, but I feel it's better to let the compiler do it's job.
Merlin works perfectly well with it.