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.
125 lines
4.9 KiB
Plaintext
125 lines
4.9 KiB
Plaintext
;;;; println, one row per arm of the structural printer.
|
|
;;;;
|
|
;;;; The walk in render.ml is shared with the REPL, but until now its only
|
|
;;;; coverage was the REPL tests -- and those run a dev build, where the pieces
|
|
;;;; go to flan_dev_emit. println is the same walk with the other emitter, in
|
|
;;;; an ordinary build, so every arm needs saying again here: the two emitters
|
|
;;;; are the one thing the shared module does *not* make identical.
|
|
;;;;
|
|
;;;; Run at -O0 as well as -O2. The slice arm emits a loop over slots taken
|
|
;;;; from the enclosing function's frame, and mem2reg is exactly the pass that
|
|
;;;; would launder a slot mistake into working code.
|
|
|
|
(defstruct V [x f32 y f32])
|
|
(defstruct Blob [id i32 name string pos V tags [3 i32]])
|
|
(defenum Colour [red 0 green 1 blue 2])
|
|
|
|
;; Five deep, so the walk hits max_depth (4) and prints "..." rather than
|
|
;; descending forever. A self-containing struct is the case this cap exists
|
|
;; for; five nested ones are the same shape without needing a pointer.
|
|
(defstruct D5 [n i32])
|
|
(defstruct D4 [d D5])
|
|
(defstruct D3 [d D4])
|
|
(defstruct D2 [d D3])
|
|
(defstruct D1 [d D2])
|
|
|
|
(defvar b Blob)
|
|
(defvar col Colour)
|
|
(defvar big u64)
|
|
(defvar small u64)
|
|
(defvar arr [4 i32])
|
|
(defvar wide [10 i32])
|
|
(defvar deep D1)
|
|
(defvar n i32)
|
|
(defstruct Long [s string])
|
|
(defvar long-one Long)
|
|
|
|
(defn nothing [] () )
|
|
|
|
(defn find-it [s [i32] k i32] (Option i32)
|
|
(dotimes [i (len s)]
|
|
(when (= (at s i) k) (return (Some i))))
|
|
None)
|
|
|
|
(defn main [] i32
|
|
;; A string at top level prints raw. Anywhere else it is quoted, which the
|
|
;; Blob row below shows -- the two are the same value printed two ways on
|
|
;; purpose, and that difference is the thing most likely to be "fixed".
|
|
(println "plain string")
|
|
(println (bytes "plain bytes"))
|
|
|
|
(println 42)
|
|
(println -7)
|
|
(set small 5)
|
|
(println small)
|
|
;; The u64 row. Through the signed printer this reads -1, which is the one
|
|
;; way println could disagree with the REPL about a value both can hold.
|
|
(set big 0xFFFFFFFFFFFFFFFF)
|
|
(println big)
|
|
|
|
(println 3.5)
|
|
(println -0.25)
|
|
|
|
(println true)
|
|
(println false)
|
|
|
|
;; Unit is evaluated and *then* reported: a Unit expression is a call made
|
|
;; for its effect, so emitting () without running it would be a lie.
|
|
(println (nothing))
|
|
|
|
(set col :green)
|
|
(println col)
|
|
;; red is 0, which is also the zero value, so this row says the chain of
|
|
;; comparisons reaches the *first* member and does not fall through to the
|
|
;; number it is erased to.
|
|
(set col :red)
|
|
(println col)
|
|
|
|
;; A pointer is its shape and is never followed -- the only thing that could
|
|
;; make this walk cycle.
|
|
(set n 3)
|
|
(println (addr n))
|
|
|
|
(println (find-it (slice wide 0 10) 0))
|
|
(println (find-it (slice wide 0 10) 99))
|
|
|
|
(set (.id b) 7)
|
|
(set (.name b) "sandy \"quoted\"")
|
|
(set (.x (.pos b)) 1.5)
|
|
(set (.y (.pos b)) -2.0)
|
|
(set (at (.tags b) 1) 42)
|
|
(println b)
|
|
|
|
(set (at arr 2) 9)
|
|
(println arr)
|
|
|
|
;; Ten elements against a span cap of eight: eight, then "...".
|
|
(set (at wide 9) 1)
|
|
(println wide)
|
|
|
|
;; A slice's length is not known until it runs, so this is the arm that
|
|
;; emits a loop rather than unrolling.
|
|
(println (slice arr 1 4))
|
|
|
|
(set (.n (.d (.d (.d (.d deep))))) 5)
|
|
(println deep)
|
|
|
|
;; Two slice printlns in one function, and one inside a loop: the slots the
|
|
;; loop needs are allocated per *call site* at check time, not per iteration.
|
|
(dotimes [i 2]
|
|
(println (slice arr 0 2)))
|
|
(println (slice arr 2 4))
|
|
|
|
;; A nested string longer than the escape buffer. Escaping is the one
|
|
;; conversion whose output is not a bounded handful of characters, so it
|
|
;; truncates -- with an ellipsis inside the quotes, because a value that
|
|
;; prints as a shorter value is the failure nobody notices.
|
|
(set (.s long-one) "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
|
|
(println long-one)
|
|
|
|
;; print is println without the newline.
|
|
(print "a")
|
|
(print "b")
|
|
(println "c")
|
|
0)
|