The mechanical half, ahead of the parser change that needs it. tools/unit-return.py
fills the empty slot with () and rewrites Unit as () wherever a type is spelled --
(Fn [i32] Unit), (Map i32 Unit), a return type written out.
Deciding whether a defn already had a return type is the whole difficulty, and
the script does it the way parse.ml did: is_type_form is transcribed rather than
improved, because being identical to the parser it replaces is what makes the
sweep meaning-preserving. It is re-runnable, so the lanes that branched before
this can have the same pass at merge:
python3 tools/unit-return.py .
python3 tools/unit-return.py --in-strings test/test_flan.ml test/test_acceptance.ml \
test/test_session.ml emacs/test-flan-dev.el emacs/test-flan-mode.el
python3 tools/unit-return.py --raw-ml lib/prelude.ml
python3 tools/unit-return.py --in-html web/index.html
-v logs every defn it saw and what it decided, which is how a sweep of 440 sites
gets reviewed at all. Embedded modes pool a file's type declarations across all
its fragments, because a snippet split across concatenation -- decls ^ "(defn f
[s [u8]] Cursor ...)" -- cannot see the names the other half declared; pooled
names count only in bare-symbol position, for the same reason the prelude's do.
A fragment that cuts off mid-form is skipped rather than guessed at. Five sites
in test_flan.ml still needed a hand, and they are in this commit.
Two things ride along because the sweep needs them: parse.ml reads a lone () as
the return type of a function with no body, which was not a shape the old
optional slot could produce; and the map refusals name () rather than Unit, since
that is now the spelling a caller wrote.
61 lines
2.7 KiB
Plaintext
61 lines
2.7 KiB
Plaintext
;;;; The prelude's rounding, and sqrt.
|
|
;;;;
|
|
;;;; Every input is one a plausible wrong implementation gets wrong. The
|
|
;;;; negatives are the whole point: a floor written as a bare cast truncates
|
|
;;;; toward zero and answers -2 for -2.5, and a round written as
|
|
;;;; (floor-f32 (+ x 0.5)) answers -2 for -2.5 as well, where C's round says
|
|
;;;; -3. The exact halves appear on both signs for that reason. The values
|
|
;;;; that are already integers check that the correction does *not* fire —
|
|
;;;; a floor that always subtracts one turns 3.0 into 2.0 — and 16777216.0 is
|
|
;;;; past 2^24, where an f32 has no fractional bits and the guard, not the
|
|
;;;; cast, has to produce the answer.
|
|
|
|
(defn show [x f32] ()
|
|
(print x)
|
|
(print " "))
|
|
|
|
(defn main [] i32
|
|
;; floor: down on both signs, and unmoved on the integers.
|
|
(show (floor-f32 2.7)) (show (floor-f32 2.0)) (show (floor-f32 2.3))
|
|
(show (floor-f32 -2.7)) (show (floor-f32 -2.0)) (show (floor-f32 -2.3))
|
|
(show (floor-f32 0.5)) (show (floor-f32 -0.5))
|
|
(println "")
|
|
|
|
;; ceil: up on both signs. -2.7 must give -2, which is where a ceil written
|
|
;; as "floor plus one" goes wrong.
|
|
(show (ceil-f32 2.7)) (show (ceil-f32 2.0)) (show (ceil-f32 2.3))
|
|
(show (ceil-f32 -2.7)) (show (ceil-f32 -2.0)) (show (ceil-f32 -2.3))
|
|
(show (ceil-f32 0.5)) (show (ceil-f32 -0.5))
|
|
(println "")
|
|
|
|
;; Zero keeps its sign through floor, which is what the (= x 0.0) guard in
|
|
;; it is for and the only place that guard is observable: the cast it skips
|
|
;; would turn -0.0 into +0.0, and %g prints the difference. Drop the guard
|
|
;; and the third column here reads 0 instead of -0.
|
|
(show (floor-f32 0.0)) (show (ceil-f32 0.0)) (show (floor-f32 -0.0))
|
|
(println "")
|
|
|
|
;; round: half away from zero on both signs, so -2.5 is -3 and not -2.
|
|
(show (round-f32 2.4)) (show (round-f32 2.5)) (show (round-f32 2.6))
|
|
(show (round-f32 -2.4)) (show (round-f32 -2.5)) (show (round-f32 -2.6))
|
|
(show (round-f32 0.5)) (show (round-f32 -0.5))
|
|
(println "")
|
|
|
|
;; Past 2^24 there is no fraction left; the answer is the input, and the
|
|
;; cast that would produce it is out of i32's range on the way there.
|
|
(show (floor-f32 16777216.0)) (show (ceil-f32 16777216.0))
|
|
(show (round-f32 16777216.0)) (show (floor-f32 -16777216.0))
|
|
(println "")
|
|
|
|
;; sqrt, including the two values a wrong-sense iteration still passes
|
|
;; (0 and 1) and one that is not a perfect square.
|
|
(show (sqrt-f32 0.0)) (show (sqrt-f32 1.0)) (show (sqrt-f32 4.0))
|
|
(show (sqrt-f32 2.0)) (show (sqrt-f32 0.25)) (show (sqrt-f32 1e6))
|
|
(println "")
|
|
|
|
;; A squared distance through sqrt, which is what a game actually calls it
|
|
;; for: 3-4-5 exactly, so a last-bit error would show.
|
|
(show (sqrt-f32 (+ (* 3.0 3.0) (* 4.0 4.0))))
|
|
(println "")
|
|
0)
|