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.
83 lines
3.4 KiB
Plaintext
83 lines
3.4 KiB
Plaintext
;;;; The prelude's in-place slice algorithms.
|
|
;;;;
|
|
;;;; Every input here is chosen so that a wrong implementation passes nothing.
|
|
;;;; The sort input is unsorted, has duplicates, has negatives and has an odd
|
|
;;;; length, so a comparison with the wrong sense, an off-by-one that drops the
|
|
;;;; last element, and a swap that loses an equal key all show up. The second
|
|
;;;; sort is reverse-sorted, which is the worst case for insertion sort and the
|
|
;;;; case a no-op comparison would pass. The third sorts a *subslice* and then
|
|
;;;; prints the whole owning array: a slice is ptr+len into its owner, so the
|
|
;;;; five elements inside the range must be sorted and the three outside it
|
|
;;;; must be untouched. That last one is the property that dies silently if a
|
|
;;;; slice parameter ever starts being copied.
|
|
|
|
(defvar xs [7 i32])
|
|
(defvar ys [5 i32])
|
|
(defvar zs [8 i32])
|
|
|
|
(defn show [s [i32]] ()
|
|
(dotimes [i (len s)]
|
|
(when (> i 0) (print " "))
|
|
(print (at s i)))
|
|
(println ""))
|
|
|
|
(defn load-xs [] ()
|
|
(set (at xs 0) 5)
|
|
(set (at xs 1) -3)
|
|
(set (at xs 2) 5)
|
|
(set (at xs 3) 0)
|
|
(set (at xs 4) 12)
|
|
(set (at xs 5) -3)
|
|
(set (at xs 6) 7))
|
|
|
|
(defn main [] i32
|
|
(load-xs)
|
|
(show (slice xs 0 (len xs))) ; 5 -3 5 0 12 -3 7
|
|
|
|
;; Reading the whole slice, before anything reorders it.
|
|
(print (sum-i32 (slice xs 0 (len xs)))) (println "") ; 23
|
|
(print (match (min-i32 (slice xs 0 (len xs))) (Some v) v None 99))
|
|
(println "") ; -3
|
|
(print (match (max-i32 (slice xs 0 (len xs))) (Some v) v None 99))
|
|
(println "") ; 12
|
|
;; First index, not the last: 5 appears at 0 and at 2.
|
|
(print (match (index-of-i32 (slice xs 0 (len xs)) 5) (Some v) v None -1))
|
|
(println "") ; 0
|
|
(print (match (index-of-i32 (slice xs 0 (len xs)) 4) (Some v) v None -1))
|
|
(println "") ; -1
|
|
;; An empty slice has no least element, and None is the answer.
|
|
(print (match (min-i32 (slice xs 3 3)) (Some v) v None 99))
|
|
(println "") ; 99
|
|
|
|
;; Reverse of an odd-length slice: the middle element stays put.
|
|
(reverse-i32! (slice xs 0 (len xs)))
|
|
(show (slice xs 0 (len xs))) ; 7 -3 12 0 5 -3 5
|
|
;; And of a two-element one, the smallest case that can actually move.
|
|
(reverse-i32! (slice xs 0 2))
|
|
(show (slice xs 0 (len xs))) ; -3 7 12 0 5 -3 5
|
|
|
|
(load-xs)
|
|
(sort-i32! (slice xs 0 (len xs)))
|
|
(show (slice xs 0 (len xs))) ; -3 -3 0 5 5 7 12
|
|
|
|
;; Reverse-sorted: the case a comparison that never fires would pass.
|
|
(set (at ys 0) 5) (set (at ys 1) 4) (set (at ys 2) 3)
|
|
(set (at ys 3) 2) (set (at ys 4) 1)
|
|
(sort-i32! (slice ys 0 (len ys)))
|
|
(show (slice ys 0 (len ys))) ; 1 2 3 4 5
|
|
|
|
;; A subslice, with the elements on both sides left alone.
|
|
(set (at zs 0) 100) (set (at zs 1) 9) (set (at zs 2) -1)
|
|
(set (at zs 3) 9) (set (at zs 4) 4) (set (at zs 5) 0)
|
|
(set (at zs 6) 200) (set (at zs 7) 300)
|
|
(sort-i32! (slice zs 1 6))
|
|
(show (slice zs 0 (len zs))) ; 100 -1 0 4 9 9 200 300
|
|
|
|
;; Degenerate lengths must do nothing rather than run off an end.
|
|
(sort-i32! (slice zs 0 0))
|
|
(reverse-i32! (slice zs 0 0))
|
|
(sort-i32! (slice zs 2 3))
|
|
(reverse-i32! (slice zs 2 3))
|
|
(show (slice zs 0 (len zs))) ; 100 -1 0 4 9 9 200 300
|
|
0)
|