From 877b4fae0436bdf22e7c0f911ce8f7030038a04c Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Sat, 17 Jan 2015 15:41:24 -0800 Subject: 576 - helper for printing integers This requires creating a new data structure called buffer, because strings are too inefficient for appending to, and we need to know how long they need to be before we clear them. But I'm not gonna bother to write tests for all the new primitives I just introduced, because that's not expedient. One test for mu is how nicely it handles situations like this without requiring perfect test hygiene. In this case, I can imagine tools that will extract tests for a particular function out of all known tests. Especially if it's a pure function that should be easy. Then just show each test to the programmer and ask him to give it a reasonable name. --- horizon | 4 ++ mu.arc | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mu.arc.t | 35 ++++++++++++++++++ 3 files changed, 164 insertions(+) diff --git a/horizon b/horizon index a8869da4..f46e56ec 100644 --- a/horizon +++ b/horizon @@ -23,3 +23,7 @@ Trace should contain [ typed "b" typed "c" ] + +--- + +Extract unit tests for helper out of all existing tests. diff --git a/mu.arc b/mu.arc index cc267850..2e1d8fd6 100644 --- a/mu.arc +++ b/mu.arc @@ -156,6 +156,9 @@ string-address-array-address (obj size 1 address t elem '(string-address-array)) character (obj size 1) ; int32 like a Go rune character-address (obj size 1 address t elem '(character)) + ; a buffer makes it easy to append to a string + buffer (obj size 2 and-record t elems '((integer) (string-address)) fields '(length data)) + buffer-address (obj size 1 address t elem '(buffer)) ; isolating function calls space (obj array t elem '(location)) ; by convention index 0 points to outer space space-address (obj size 1 address t elem '(space)) @@ -1116,6 +1119,7 @@ (replace-names-with-location instrs name)) (def assign-names-to-location (instrs name) +;? (tr name) (ret location (table) (with (isa-field (table) idx 1) ; 0 always reserved for next space @@ -1944,6 +1948,126 @@ (print-primitive-to-host c:location) ) +(init-fn init-buffer + (default-space:space-address <- new space:literal 30:literal) + (result:buffer-address <- new buffer:literal) + (len:integer-address <- get-address result:buffer-address/deref length:offset) + (len:integer-address/deref <- copy 0:literal) + (s:string-address-address <- get-address result:buffer-address/deref data:offset) + (capacity:integer <- next-input) + (s:string-address-address/deref <- new string:literal capacity:integer) + (reply result:buffer-address) +) + +(init-fn grow-buffer + (default-space:space-address <- new space:literal 30:literal) + (in:buffer-address <- next-input) + ; double buffer size + (x:string-address-address <- get-address in:buffer-address/deref data:offset) + (oldlen:integer <- length x:string-address-address/deref/deref) + (newlen:integer <- multiply oldlen:integer 2:literal) + (olddata:string-address <- copy x:string-address-address/deref) + (x:string-address-address/deref <- new string:literal newlen:integer) + ; copy old contents + (i:integer <- copy 0:literal) + { begin + (done?:boolean <- greater-or-equal i:integer oldlen:integer) + (break-if done?:boolean) + (src:byte <- index olddata:string-address/deref i:integer) + (dest:byte-address <- index-address x:string-address-address/deref/deref i:integer) + (dest:byte-address <- copy src:byte) + (loop) + } + (reply in:buffer-address) +) + +(init-fn buffer-full? + (default-space:space-address <- new space:literal 30:literal) + (in:buffer-address <- next-input) + (len:integer <- get in:buffer-address/deref length:offset) + (s:string-address <- get in:buffer-address/deref data:offset) + (capacity:integer <- length s:string-address/deref) + (result:boolean <- greater-or-equal len:integer capacity:integer) + (reply result:boolean) +) + +(init-fn append + (default-space:space-address <- new space:literal 30:literal) + (in:buffer-address <- next-input) + (c:character <- next-input) + { begin + ; grow buffer if necessary + (full?:boolean <- buffer-full? in:buffer-address) + (break-unless full?:boolean) + (in:buffer-address <- grow-buffer in:buffer-address) + } + (len:integer-address <- get-address in:buffer-address/deref length:offset) + (s:string-address <- get in:buffer-address/deref data:offset) + (dest:byte-address <- index-address s:string-address/deref len:integer-address/deref) + (dest:byte-address/deref <- copy c:character) ; todo: unicode + (len:integer-address/deref <- add len:integer-address/deref 1:literal) + (reply in:buffer-address) +) + +(init-fn integer-to-decimal-string + (n:integer <- next-input) + ; is it zero? + { begin + (zero?:boolean <- equal n:integer 0:literal) + (break-unless zero?:boolean) + (s:string-address <- new "0") + (reply s:string-address) + } + ; save sign + (negate-result:boolean <- copy nil:literal) + { begin + (negative?:boolean <- less-than n:integer 0:literal) + (break-unless negative?:boolean) +;? (print-primitive-to-host (("is negative " literal))) + (negate-result:boolean <- copy t:literal) + (n:integer <- multiply n:integer -1:literal) + } + ; add digits from right to left into intermediate buffer + (tmp:buffer-address <- init-buffer 30:literal) + (zero:character <- copy ((#\0 literal))) + (digit-base:integer <- character-to-integer zero:character) + { begin + (done?:boolean <- equal n:integer 0:literal) + (break-if done?:boolean) + (n:integer digit:integer <- divide-with-remainder n:integer 10:literal) + (digit-codepoint:integer <- add digit-base:integer digit:integer) + (c:character <- integer-to-character digit-codepoint:integer) + (tmp:buffer-address <- append tmp:buffer-address c:character) + (loop) + } + ; add sign + { begin + (break-unless negate-result:boolean) + (tmp:buffer-address <- append tmp:buffer-address ((#\- literal))) + } + ; reverse buffer into string result + (len:integer <- get tmp:buffer-address/deref length:offset) + (buf:string-address <- get tmp:buffer-address/deref data:offset) + (result:string-address <- new string:literal len:integer) + (i:integer <- subtract len:integer 1:literal) + (j:integer <- copy 0:literal) + { begin + ; while (i >= 0) + (done?:boolean <- less-than i:integer 0:literal) + (break-if done?:boolean) + ; result[j] = tmp[i] + (src:byte <- index buf:string-address/deref i:integer) + (dest:byte-address <- index-address result:string-address/deref j:integer) + (dest:byte-address/deref <- copy src:byte) + ; ++i + (i:integer <- subtract i:integer 1:literal) + ; --j + (j:integer <- add j:integer 1:literal) + (loop) + } + (reply result:string-address) +) + (init-fn send-prints-to-stdout (default-space:space-address <- new space:literal 30:literal) (stdout:channel-address <- next-input) @@ -1960,6 +2084,7 @@ ) ; after all system software is loaded: +;? (= dump-trace* (obj whitelist '("cn0" "cn1"))) (freeze system-function*) ) ; section 100 for system software diff --git a/mu.arc.t b/mu.arc.t index 1b378c5a..dcb38e0f 100644 --- a/mu.arc.t +++ b/mu.arc.t @@ -4034,6 +4034,41 @@ (~memory-contains-array (memory* (+ base 4)) "c")) (prn "F - 'split' cuts string at two delimiters"))) +(reset) +(new-trace "integer-to-decimal-string") +(add-code + '((function main [ + (1:string-address/raw <- integer-to-decimal-string 34:literal) + ]))) +;? (set dump-trace*) +;? (= dump-trace* (obj whitelist '("run"))) +(run 'main) +(let base memory*.1 + (when (~memory-contains-array base "34") + (prn "F - converting integer to decimal string"))) + +(reset) +(new-trace "integer-to-decimal-string-zero") +(add-code + '((function main [ + (1:string-address/raw <- integer-to-decimal-string 0:literal) + ]))) +(run 'main) +(let base memory*.1 + (when (~memory-contains-array base "0") + (prn "F - converting zero to decimal string"))) + +(reset) +(new-trace "integer-to-decimal-string-negative") +(add-code + '((function main [ + (1:string-address/raw <- integer-to-decimal-string -237:literal) + ]))) +(run 'main) +(let base memory*.1 + (when (~memory-contains-array base "-237") + (prn "F - converting negative integer to decimal string"))) + ) ; section 100 for string utilities (reset) -- cgit 1.4.1-2-gfad0