From b8019a96d580923033fe5147bed7bbeb8b78e348 Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Sat, 12 Sep 2026 05:37:56 +0700 Subject: [PATCH] Give the page a section on the two printers it never mentioned MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit print and println had no line anywhere on index.html — a builtin the reader meets in the first example and is never told about. There is a section for them now, between arrays and the prelude: what the walk covers, that an enum comes back as its name and a Ptr does not get followed, that a string is raw at the top and quoted inside a structure, and that the depth and span caps are what keep a grid from printing a screenful. printing.flan is beside the other examples so check.sh has been green on every line of it. The prelude's table loses its output row, because the prelude has no output functions left, and the fifty-odd example blocks follow the files they quote. Two pinned things moved. sand-headless prints 15595743031174623232 where it printed -2851001042534928384: same bits, read unsigned, because the cast that made it signed is gone. bounds.flan's trap moved from column 28 to 19, which is where (at xs i) now starts on that line. And the indirection-cell illustration is defer.flan rather than hello.flan. hello.flan cannot show a cell any more: its one call was to a prelude function, and println is compiler-provided, so the smallest program makes no Flan-to-Flan call at all. defer.flan's main calls work, and is already on the page a few sections up. --- web/examples/arrays.flan | 10 +- web/examples/boom.flan | 4 +- web/examples/bounds.flan | 6 +- web/examples/bounds.out | 2 +- web/examples/breakdemo.flan | 4 +- web/examples/conds.flan | 4 +- web/examples/control.flan | 14 +-- web/examples/defer.flan | 10 +- web/examples/enums.flan | 4 +- web/examples/ffi.flan | 2 +- web/examples/globals.flan | 8 +- web/examples/hello.flan | 2 +- web/examples/numbers.flan | 6 +- web/examples/option.flan | 8 +- web/examples/pkg.flan | 4 +- web/examples/places.flan | 8 +- web/examples/printing.flan | 13 +++ web/examples/printing.out | 7 ++ web/examples/quotes.sh | 13 ++- web/examples/restart.flan | 6 +- web/examples/shimdemo.flan | 4 +- web/examples/structs.flan | 4 +- web/index.html | 189 +++++++++++++++++++++++------------- 23 files changed, 207 insertions(+), 125 deletions(-) create mode 100644 web/examples/printing.flan create mode 100644 web/examples/printing.out diff --git a/web/examples/arrays.flan b/web/examples/arrays.flan index 336972f..747eff6 100644 --- a/web/examples/arrays.flan +++ b/web/examples/arrays.flan @@ -9,15 +9,15 @@ (defn main [] (set (at grid 1 2) 7) - (print-i64 (i64 (at grid 1 2))) (newline) ; 7 - (print-i64 (i64 (len palette))) (newline) ; 4 + (print (at grid 1 2)) (println "") ; 7 + (print (len palette)) (println "") ; 4 ;; A slice is ptr+len and non-owning: it views the array, it does not copy it. (let [row (slice (at grid 1) 0 cols)] (set (at row 0) 5) - (print-i64 (i64 (at grid 1 0))) (newline) ; 5 — the same storage - (print-i64 (sum-i32 row)) (newline)) ; 12 + (print (at grid 1 0)) (println "") ; 5 — the same storage + (print (sum-i32 row)) (println "")) ; 12 ;; (zeroed) is a memset, not an allocation. (set grid (zeroed)) - (print-i64 (i64 (at grid 1 2))) (newline)) ; 0 + (print (at grid 1 2)) (println "")) ; 0 diff --git a/web/examples/boom.flan b/web/examples/boom.flan index f4dcbd8..ca75da6 100644 --- a/web/examples/boom.flan +++ b/web/examples/boom.flan @@ -8,5 +8,5 @@ (retry [] 7))) (defn main [] - (print-i64 (i64 (load 1))) - (newline)) + (print (load 1)) + (println "")) diff --git a/web/examples/bounds.flan b/web/examples/bounds.flan index 762b186..853b734 100644 --- a/web/examples/bounds.flan +++ b/web/examples/bounds.flan @@ -5,6 +5,6 @@ ;; catches it — the same message, and the program stops where it happened. (defn main [] (let [i 7] - (print-line "before") - (print-i64 (i64 (at xs i))) - (print-line "unreachable"))) + (println "before") + (print (at xs i)) + (println "unreachable"))) diff --git a/web/examples/bounds.out b/web/examples/bounds.out index fd24439..f57d374 100644 --- a/web/examples/bounds.out +++ b/web/examples/bounds.out @@ -1,3 +1,3 @@ before -bounds.flan:9:28: index 7 is out of bounds for length 3 +bounds.flan:9:19: index 7 is out of bounds for length 3 exit 134 diff --git a/web/examples/breakdemo.flan b/web/examples/breakdemo.flan index 6afd53c..be13438 100644 --- a/web/examples/breakdemo.flan +++ b/web/examples/breakdemo.flan @@ -11,5 +11,5 @@ (defn main [] (agent/start "/tmp/flan-breakdemo.sock") - (print-i64 (i64 (load 1))) - (newline)) + (print (load 1)) + (println "")) diff --git a/web/examples/conds.flan b/web/examples/conds.flan index 0f49b99..75d3589 100644 --- a/web/examples/conds.flan +++ b/web/examples/conds.flan @@ -8,9 +8,9 @@ (defn main [] (load-all) ; no handler: a no-op - (print-i64 seen) (newline) ; 0 + (print seen) (println "") ; 0 ;; A handler that returns normally accumulates and lets the signaller run on. (handler-bind [(AssetMissing [c] (set seen (+ seen (i64 (.id c)))))] (load-all)) - (print-i64 seen) (newline)) ; 3 + (print seen) (println "")) ; 3 diff --git a/web/examples/control.flan b/web/examples/control.flan index 56b4b6c..a99b6db 100644 --- a/web/examples/control.flan +++ b/web/examples/control.flan @@ -9,10 +9,10 @@ (defn countdown [n i32] (let [i n] (while (> i 0) - (print-i64 (i64 i)) - (print-str " ") + (print i) + (print " ") (set i (- i 1))) - (newline))) + (println ""))) (defn first-even [s [i32]] (Option i32) (dotimes [i (len s)] @@ -21,10 +21,10 @@ None) (defn main [] - (print-line (classify -3)) + (println (classify -3)) (countdown 4) (unless false - (print-line "unless runs when the test is false")) + (println "unless runs when the test is false")) (match (first-even (slice nums 0 (len nums))) - (Some n) (do (print-i64 (i64 n)) (newline)) - None (print-line "none"))) + (Some n) (do (print n) (println "")) + None (println "none"))) diff --git a/web/examples/defer.flan b/web/examples/defer.flan index 57cf9cf..d4d3a75 100644 --- a/web/examples/defer.flan +++ b/web/examples/defer.flan @@ -1,11 +1,11 @@ (defn work [n i32] i32 - (defer (print-line "second")) - (defer (print-line "first")) ; innermost-first at exit + (defer (println "second")) + (defer (println "first")) ; innermost-first at exit (when (< n 0) (return 0)) ; runs both defers above it - (print-line "body") + (println "body") n) (defn main [] - (print-i64 (i64 (work 3))) - (newline)) + (print (work 3)) + (println "")) diff --git a/web/examples/enums.flan b/web/examples/enums.flan index 9745ea9..4773ea5 100644 --- a/web/examples/enums.flan +++ b/web/examples/enums.flan @@ -10,5 +10,5 @@ (defn main [] ;; :space resolves against the parameter's enum at compile time. ;; A typo is an error here, not a wrong number later. - (print-line (key-name :space)) - (print-line (key-name :left))) + (println (key-name :space)) + (println (key-name :left))) diff --git a/web/examples/ffi.flan b/web/examples/ffi.flan index 57c2d7a..2c7efb0 100644 --- a/web/examples/ffi.flan +++ b/web/examples/ffi.flan @@ -3,4 +3,4 @@ (declare cos-f64 [x f64] f64 "cos") (defn main [] - (print-f64 (cos-f64 0.0)) (newline)) + (print (cos-f64 0.0)) (println "")) diff --git a/web/examples/globals.flan b/web/examples/globals.flan index 495be74..5b6a5d2 100644 --- a/web/examples/globals.flan +++ b/web/examples/globals.flan @@ -6,7 +6,7 @@ (defvar grid [rows [cols u32]]) ; BSS, rows*cols*4 bytes (defn main [] - (print-i64 (i64 cell-size)) (newline) - (print-f64 (f64 gravity)) (newline) - (print-i64 (i64 current-color)) (newline) - (print-i64 (i64 (at grid 2 3))) (newline)) + (print cell-size) (println "") + (print gravity) (println "") + (print current-color) (println "") + (print (at grid 2 3)) (println "")) diff --git a/web/examples/hello.flan b/web/examples/hello.flan index 118a283..fcef751 100644 --- a/web/examples/hello.flan +++ b/web/examples/hello.flan @@ -1,2 +1,2 @@ (defn main [] - (print-line "hello from flan")) + (println "hello from flan")) diff --git a/web/examples/numbers.flan b/web/examples/numbers.flan index 14c58e2..0fa0a5f 100644 --- a/web/examples/numbers.flan +++ b/web/examples/numbers.flan @@ -2,7 +2,7 @@ (let [n 40 ; i32, inferred big (i64 n) ; every widening is written x 1.5] ; f64 - (print-i64 (+ big 2)) (newline) - (print-f64 (* x 2.5)) (newline) - (print-i64 (i64 (bit-xor (<< 1 8) 255))) (newline) + (print (+ big 2)) (println "") + (print (* x 2.5)) (println "") + (print (bit-xor (<< 1 8) 255)) (println "") 0)) diff --git a/web/examples/option.flan b/web/examples/option.flan index b0db48f..97986f4 100644 --- a/web/examples/option.flan +++ b/web/examples/option.flan @@ -6,8 +6,8 @@ (defn main [] (match (doubled-first (slice nums 0 4)) - (Some i) (do (print-i64 (i64 i)) (newline)) ; 4 - None (print-line "not found")) + (Some i) (do (print i) (println "")) ; 4 + None (println "not found")) (match (index-of-i32 (slice nums 0 4) 99) - (Some i) (do (print-i64 (i64 i)) (newline)) - None (print-line "not found"))) + (Some i) (do (print i) (println "")) + None (println "not found"))) diff --git a/web/examples/pkg.flan b/web/examples/pkg.flan index 3a62201..635493b 100644 --- a/web/examples/pkg.flan +++ b/web/examples/pkg.flan @@ -5,5 +5,5 @@ (defn main [] (let [v (g/add (g/V2 {:x 3.0 :y 0.0}) (g/V2 {:x 0.0 :y 4.0}))] - (print-f64 (f64 (g/length v))) - (newline))) + (print (g/length v)) + (println ""))) diff --git a/web/examples/places.flan b/web/examples/places.flan index 03f3878..913d9b7 100644 --- a/web/examples/places.flan +++ b/web/examples/places.flan @@ -14,7 +14,7 @@ (set (at room 2) 5) ; a fixed array or slice element (set (deref p) (Enemy {:hp 3 :name "wisp"})) ; a whole-object store - (print-i64 (i64 (.hp e))) (newline) - (print-line (.name e)) - (print-i64 (i64 (at room 2))) (newline) - (print-i64 (i64 spawned)) (newline))) + (print (.hp e)) (println "") + (println (.name e)) + (print (at room 2)) (println "") + (print spawned) (println ""))) diff --git a/web/examples/printing.flan b/web/examples/printing.flan new file mode 100644 index 0000000..eab17a2 --- /dev/null +++ b/web/examples/printing.flan @@ -0,0 +1,13 @@ +(defenum Key [space 32 left 263]) +(defstruct Enemy [hp i32 name string key Key]) + +(defn look-up [k Key] (Option i32) + (if (= k :space) (Some 32) None)) + +(defn main [] + (println 42) ; an i32, uncast + (println 1.5) + (println (Enemy {:hp 3 :name "wisp" :key :left})) + (println (look-up :space)) + (println (look-up :left)) + (print "no newline: ") (println true)) diff --git a/web/examples/printing.out b/web/examples/printing.out new file mode 100644 index 0000000..b3ac8a2 --- /dev/null +++ b/web/examples/printing.out @@ -0,0 +1,7 @@ +42 +1.5 +(Enemy {:hp 3 :name "wisp" :key :left}) +(some 32) +none +no newline: true +exit 0 diff --git a/web/examples/quotes.sh b/web/examples/quotes.sh index b0f50b3..b7320be 100644 --- a/web/examples/quotes.sh +++ b/web/examples/quotes.sh @@ -55,7 +55,7 @@ for pair in \ 'handle:(defvar h (Handle i32))' \ 'fnty:(defn f [g (Fn [i32] i32)] i32 (g 1))' \ 'quoted:(defn f [] i32 (quote a))' \ - 'deferblock:(defn f [] i32 (let [x 1] (defer (print-line "a")) x))' \ + 'deferblock:(defn f [] i32 (let [x 1] (defer (println "a")) x))' \ 'i64index:(defconst xs [3 i32] [1 2 3]) (defn main [] i32 (let [i (i64 1)] (at xs i)))' \ 'break:(defn main [] (let [i 0] (while (< i 3) (break))))' do @@ -66,10 +66,13 @@ do done rm -f "$here/.q.flan" -# The cell and the transfer channel, from a real --dev emit of hello.flan. -ir=$("$FLAN" emit --dev "$here/hello.flan" 2>/dev/null) -want "cell global" "$(printf '%s\n' "$ir" | grep '^@"flan.cell.print-line"')" -want "cell load" "$(printf '%s\n' "$ir" | grep 'load ptr, ptr @"flan.cell.print-line"')" +# The cell and the transfer channel, from a real --dev emit. hello.flan cannot +# show a cell any more: println is compiler-provided rather than a Flan +# function, so the smallest program makes no Flan-to-Flan call at all. defer.flan +# is the smallest one on the page that does — its main calls work. +ir=$("$FLAN" emit --dev "$here/defer.flan" 2>/dev/null) +want "cell global" "$(printf '%s\n' "$ir" | grep '^@"flan.cell.work"')" +want "cell load" "$(printf '%s\n' "$ir" | grep 'load ptr, ptr @"flan.cell.work"')" want "xfer channel" "$(printf '%s\n' "$ir" | grep 'define {} @"flan.main"')" # The generated C, from flan shim. diff --git a/web/examples/restart.flan b/web/examples/restart.flan index 5a54698..b60ee75 100644 --- a/web/examples/restart.flan +++ b/web/examples/restart.flan @@ -16,9 +16,9 @@ (retry [] 7))) (defn main [] - (print-i64 (i64 (fetch 1))) (newline) ; 101 — nothing handled it + (print (fetch 1)) (println "") ; 101 — nothing handled it (handler-bind [(AssetMissing [c] (invoke-restart 'use-placeholder))] - (print-i64 (i64 (fetch 2))) (newline)) ; -1 + (print (fetch 2)) (println "")) ; -1 - (print-i64 cleanups) (newline)) ; 2 — the defer ran both times + (print cleanups) (println "")) ; 2 — the defer ran both times diff --git a/web/examples/shimdemo.flan b/web/examples/shimdemo.flan index 4be3119..9863eae 100644 --- a/web/examples/shimdemo.flan +++ b/web/examples/shimdemo.flan @@ -3,5 +3,5 @@ (declare-c get-mouse-position [] Vector2 "GetMousePosition") (defn main [] - (print-f64 (f64 (.x (get-mouse-position)))) - (newline)) + (print (.x (get-mouse-position))) + (println "")) diff --git a/web/examples/structs.flan b/web/examples/structs.flan index e24d6dd..53ea21c 100644 --- a/web/examples/structs.flan +++ b/web/examples/structs.flan @@ -12,6 +12,6 @@ (defn main [] (let [c (Cursor {:src (bytes "hi")})] ; pos omitted, so pos is 0 - (print-i64 (i64 (peek (addr c)))) (newline) + (print (peek (addr c))) (println "") (advance (addr c)) - (print-i64 (i64 (peek (addr c)))) (newline))) + (print (peek (addr c))) (println ""))) diff --git a/web/index.html b/web/index.html index 73e630d..0760c5c 100644 --- a/web/index.html +++ b/web/index.html @@ -200,6 +200,7 @@ footer { margin-top: 3.5rem; padding-top: 1.5rem; border-top: 1px solid var(--ru
  • Control flow
  • defer
  • Arrays and slices
  • +
  • Printing
  • The prelude
  • Packages
  • Conditions and restarts
  • @@ -286,7 +287,7 @@ produced. run builds to a temporary file and execs it.

    The smallest program:

    (defn main []
    -  (print-line "hello from flan"))
    + (println "hello from flan"))

    The entry point is (defn main [args [string]] i32). Both the parameter and the return type are optional: omitting args means the program ignores @@ -337,10 +338,10 @@ heap is involved.

    (set (at room 2) 5) ; a fixed array or slice element (set (deref p) (Enemy {:hp 3 :name "wisp"})) ; a whole-object store - (print-i64 (i64 (.hp e))) (newline) - (print-line (.name e)) - (print-i64 (i64 (at room 2))) (newline) - (print-i64 (i64 spawned)) (newline))) + (print (.hp e)) (println "") + (println (.name e)) + (print (at room 2)) (println "") + (print spawned) (println "")))
    3
     wisp
    @@ -361,13 +362,13 @@ wisp
     ;; catches it — the same message, and the program stops where it happened.
     (defn main []
       (let [i 7]
    -    (print-line "before")
    -    (print-i64 (i64 (at xs i)))
    -    (print-line "unreachable")))
    + (println "before") + (print (at xs i)) + (println "unreachable")))
    $ flan run bounds.flan
     before
    -bounds.flan:9:28: index 7 is out of bounds for length 3
    +bounds.flan:9:19: index 7 is out of bounds for length 3
     $ echo $?
     134
    @@ -408,9 +409,9 @@ have one type, and every conversion is written as a cast:

    (let [n 40 ; i32, inferred big (i64 n) ; every widening is written x 1.5] ; f64 - (print-i64 (+ big 2)) (newline) - (print-f64 (* x 2.5)) (newline) - (print-i64 (i64 (bit-xor (<< 1 8) 255))) (newline) + (print (+ big 2)) (println "") + (print (* x 2.5)) (println "") + (print (bit-xor (<< 1 8) 255)) (println "") 0))
    42
    @@ -455,9 +456,9 @@ its fields, and omitted fields are zeroed.

    (defn main [] (let [c (Cursor {:src (bytes "hi")})] ; pos omitted, so pos is 0 - (print-i64 (i64 (peek (addr c)))) (newline) + (print (peek (addr c))) (println "") (advance (addr c)) - (print-i64 (i64 (peek (addr c)))) (newline)))
    + (print (peek (addr c))) (println "")))
    104
     105
    @@ -466,7 +467,8 @@ its fields, and omitted fields are zeroed.

    byte is a u8 — but there is a byte literal, so \h is 104 and \space is 32, and the prelude's digit? reads as (and (>= b \0) (<= b \9)). To see a byte as a letter rather than as a -number, print a slice of them with print-bytes.

    +number, print a slice of them: print writes a [u8] as +its bytes.

    An enum is an i32 at run time and its own type in the checker. A keyword at a call site resolves against the parameter's enum type at compile time, so a @@ -484,8 +486,8 @@ typo is an error there rather than a wrong number later.

    (defn main [] ;; :space resolves against the parameter's enum at compile time. ;; A typo is an error here, not a wrong number later. - (print-line (key-name :space)) - (print-line (key-name :left))) + (println (key-name :space)) + (println (key-name :left)))
    space
     an arrow
    @@ -515,10 +517,10 @@ functions need no forward declaration. Globals come in two kinds:

    (defvar grid [rows [cols u32]]) ; BSS, rows*cols*4 bytes (defn main [] - (print-i64 (i64 cell-size)) (newline) - (print-f64 (f64 gravity)) (newline) - (print-i64 (i64 current-color)) (newline) - (print-i64 (i64 (at grid 2 3))) (newline)) + (print cell-size) (println "") + (print gravity) (println "") + (print current-color) (println "") + (print (at grid 2 3)) (println ""))
    5
     0.05
    @@ -551,10 +553,10 @@ whose type matters is named at the top level rather than written inline.

    (defn countdown [n i32] (let [i n] (while (> i 0) - (print-i64 (i64 i)) - (print-str " ") + (print i) + (print " ") (set i (- i 1))) - (newline))) + (println ""))) (defn first-even [s [i32]] (Option i32) (dotimes [i (len s)] @@ -563,13 +565,13 @@ whose type matters is named at the top level rather than written inline.

    None) (defn main [] - (print-line (classify -3)) + (println (classify -3)) (countdown 4) (unless false - (print-line "unless runs when the test is false")) + (println "unless runs when the test is false")) (match (first-even (slice nums 0 (len nums))) - (Some n) (do (print-i64 (i64 n)) (newline)) - None (print-line "none")))
    + (Some n) (do (print n) (println "")) + None (println "none")))
    negative
     4 3 2 1 
    @@ -604,11 +606,11 @@ on nothing else today. some unwraps Some and early-ret
     
     (defn main []
       (match (doubled-first (slice nums 0 4))
    -    (Some i) (do (print-i64 (i64 i)) (newline))   ; 4
    -    None     (print-line "not found"))
    +    (Some i) (do (print i) (println ""))          ; 4
    +    None     (println "not found"))
       (match (index-of-i32 (slice nums 0 4) 99)
    -    (Some i) (do (print-i64 (i64 i)) (newline))
    -    None     (print-line "not found")))
    + (Some i) (do (print i) (println "")) + None (println "not found")))
    4
     not found
    @@ -620,16 +622,16 @@ not found has not executed yet and must not fire.

    (defn work [n i32] i32
    -  (defer (print-line "second"))
    -  (defer (print-line "first"))     ; innermost-first at exit
    +  (defer (println "second"))
    +  (defer (println "first"))        ; innermost-first at exit
       (when (< n 0)
         (return 0))                    ; runs both defers above it
    -  (print-line "body")
    +  (println "body")
       n)
     
     (defn main []
    -  (print-i64 (i64 (work 3)))
    -  (newline))
    + (print (work 3)) + (println ""))
    body
     first
    @@ -660,18 +662,18 @@ It is a place: (set (at grid r c) v) and (addr (at grid r c))
     
     (defn main []
       (set (at grid 1 2) 7)
    -  (print-i64 (i64 (at grid 1 2))) (newline)    ; 7
    -  (print-i64 (i64 (len palette))) (newline)    ; 4
    +  (print (at grid 1 2)) (println "")           ; 7
    +  (print (len palette)) (println "")           ; 4
     
       ;; A slice is ptr+len and non-owning: it views the array, it does not copy it.
       (let [row (slice (at grid 1) 0 cols)]
         (set (at row 0) 5)
    -    (print-i64 (i64 (at grid 1 0))) (newline)  ; 5 — the same storage
    -    (print-i64 (sum-i32 row)) (newline))       ; 12
    +    (print (at grid 1 0)) (println "")         ; 5 — the same storage
    +    (print (sum-i32 row)) (println ""))        ; 12
     
       ;; (zeroed) is a memset, not an allocation.
       (set grid (zeroed))
    -  (print-i64 (i64 (at grid 1 2))) (newline))   ; 0
    + (print (at grid 1 2)) (println "")) ; 0
    7
     4
    @@ -682,17 +684,72 @@ It is a place: (set (at grid r c) v) and (addr (at grid r c))
     

    A reversed range — lo greater than hi — traps, rather than yielding a huge unsigned length.

    +

    Printing

    + +

    println prints a value and a newline; print is the same +walk without the newline. There is one of each and they take any type, but neither is a +function and neither is overloading: the compiler walks the argument's type where the +call is written and emits the printing for it. Nothing is decided at run time — a Flan +value carries no header, so nothing at run time could say what it is — and there is no +user-supplied printer to choose between.

    + +
    (defenum Key [space 32 left 263])
    +(defstruct Enemy [hp i32 name string key Key])
    +
    +(defn look-up [k Key] (Option i32)
    +  (if (= k :space) (Some 32) None))
    +
    +(defn main []
    +  (println 42)                               ; an i32, uncast
    +  (println 1.5)
    +  (println (Enemy {:hp 3 :name "wisp" :key :left}))
    +  (println (look-up :space))
    +  (println (look-up :left))
    +  (print "no newline: ") (println true))
    + +
    42
    +1.5
    +(Enemy {:hp 3 :name "wisp" :key :left})
    +(some 32)
    +none
    +no newline: true
    + +

    The walk covers every integer and float type, bool, Unit, +string, [u8], enums, Ptr, Option, +structs, fixed arrays and slices. An enum member comes back as its name: the value is +an i32 by the time the backend sees it, so the name is recovered here from +the checker's table, and a value outside the declared members falls through to the +number, which is what you would want to see. A Ptr prints as +<ptr> and is never followed — it is the one thing that could make +the walk cycle, and dereferencing a pointer on someone else's behalf is not safe.

    + +

    A string prints raw at the top level and quoted-and-escaped inside a structure. +Those are not in conflict: (println "hello") has to print +hello or it is useless, and the name field above has to be +quoted or it could not be told from the punctuation around it.

    + +

    The walk is bounded in depth and in span, so a deeply nested value or a +[100 [100 u32]] grid prints ... rather than a screenful — and, +since the walk is unrolled at compile time, rather than putting ten thousand printing +sites in the module.

    + +

    That the walk takes the argument's own type matters more here than it would in a +language that widens implicitly. Nothing widens implicitly in this one, so a printer +that named a type would need a cast written at every call — and a u64 +above 263 put through a signed one comes out negative. print +takes the value as it is and prints the number it holds.

    +

    The prelude

    The prelude is written in Flan, all but one line of it, and prepended to every -program, so nothing in it needs importing. Printing is deliberately not a primitive: -write-stdout is the one output primitive and everything above it is -ordinary Flan.

    +program, so nothing in it needs importing. It holds no printing of its own: +print and println are the compiler's, and +write-stdout — the one output primitive — is what they are written +over.

    - @@ -754,8 +811,8 @@ and no ceremony.

    (defn main [] (let [v (g/add (g/V2 {:x 3.0 :y 0.0}) (g/V2 {:x 0.0 :y 4.0}))] - (print-f64 (f64 (g/length v))) - (newline))) + (print (g/length v)) + (println "")))
    5
    @@ -827,12 +884,12 @@ normally leaves the signaller to carry on — the accumulation case:

    (defn main [] (load-all) ; no handler: a no-op - (print-i64 seen) (newline) ; 0 + (print seen) (println "") ; 0 ;; A handler that returns normally accumulates and lets the signaller run on. (handler-bind [(AssetMissing [c] (set seen (+ seen (i64 (.id c)))))] (load-all)) - (print-i64 seen) (newline)) ; 3 + (print seen) (println "")) ; 3
    0
     3
    @@ -860,12 +917,12 @@ first, before the clause body starts.

    (retry [] 7))) (defn main [] - (print-i64 (i64 (fetch 1))) (newline) ; 101 — nothing handled it + (print (fetch 1)) (println "") ; 101 — nothing handled it (handler-bind [(AssetMissing [c] (invoke-restart 'use-placeholder))] - (print-i64 (i64 (fetch 2))) (newline)) ; -1 + (print (fetch 2)) (println "")) ; -1 - (print-i64 cleanups) (newline)) ; 2 — the defer ran both times + (print cleanups) (println "")) ; 2 — the defer ran both times
    101
     -1
    @@ -947,8 +1004,8 @@ and an exit status of 134:

    (retry [] 7))) (defn main [] - (print-i64 (i64 (load 1))) - (newline))
    + (print (load 1)) + (println ""))
    $ flan run boom.flan
     unhandled Missing
    @@ -966,7 +1023,7 @@ is generated; a Flan string crosses as ptr+len, exactly as it is stored.

    (declare cos-f64 [x f64] f64 "cos")
     
     (defn main []
    -  (print-f64 (cos-f64 0.0)) (newline))
    + (print (cos-f64 0.0)) (println ""))
    1
    @@ -1072,20 +1129,22 @@ bound at link time cannot be made to notice one, so a --dev build r every Flan-to-Flan call through a cell — a mutable global holding the address of the function that is current.

    -

    Here is the whole of hello.flan through -flan emit --dev:

    +

    Here is the defer example from above — its +main calls work — through flan emit --dev:

    -
    @"flan.cell.print-line" = global ptr @"flan.print-line"
    +
    @"flan.cell.work" = global ptr @"flan.work"
     
     define {} @"flan.main"(ptr %xfer) {
     entry:
    -  %t1 = load ptr, ptr @"flan.cell.print-line"
    -  %t2 = call {} %t1(%slice { ptr @".str.36", i64 15 }, ptr %xfer)
    + %t7 = alloca %slice + %t1 = load ptr, ptr @"flan.cell.work" + %t2 = call i32 %t1(i32 3, ptr %xfer)
    -

    The call site loads the cell rather than naming @"flan.print-line" +

    The call site loads the cell rather than naming @"flan.work" directly. The signature carries ptr %xfer — the transfer channel from conditions, on every Flan function, release builds -included.

    +included. println is not in there: it is not a Flan function, so there is +no call to route and no cell for it.

    Redefinition is then one store, below a microsecond. Three rules follow. A redefinition module declares every global external, so globals live in the host @@ -1242,10 +1301,10 @@ module, and the headless sand acceptance program prints the same 64-bit hash und it does natively:

    $ flan run test/programs/sand-headless.flan
    --2851001042534928384
    +15595743031174623232
     $ flan build test/programs/sand-headless.flan --target=wasm32-wasi -o sand.wasm
     $ node --no-warnings test/wasm-run.mjs sand.wasm
    --2851001042534928384
    +15595743031174623232

    The RNG is written in Flan rather than called from libc for that number: a grid hash is only a regression test if the sequence is byte-identical on both targets. It holds at

    GroupNames
    outputprint-str, print-bytes, print-i64, print-f64, print-line, newline
    slices of i32swap-i32!, reverse-i32!, sort-i32!, index-of-i32, min-i32, max-i32, sum-i32
    bytesbytes=?, starts-with?, ends-with?, index-of-byte, index-of-bytes, trim, digit?, space?
    parsingparse-i64, parse-f64