ocaml: phase 6 Printf %i/%u/%x/%X/%o + int_to_hex/octal host primitives (+5 tests, 533 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 41s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 41s
Three new host primitives in eval.sx: _int_to_hex_lower n -> string of hex digits (lowercase) _int_to_hex_upper n -> string of hex digits (uppercase) _int_to_octal n -> string of octal digits Each builds the digit string by repeated floor(n / base) + mod, prepending the digit at each step. Negative numbers prefix '-' so the output round-trips through int_of_string with a sign. Printf walker now fans out: %d, %i, %u -> _string_of_int %f -> _string_of_float %x -> _int_to_hex_lower %X -> _int_to_hex_upper %o -> _int_to_octal %s, %c, %b -> existing handling Printf.sprintf '%x' 255 = 'ff' Printf.sprintf '%X' 4096 = '1000' Printf.sprintf '%o' 8 = '10' Printf.sprintf '%x %X %o' 255 4096 8 = 'ff 1000 10'
This commit is contained in:
@@ -70,6 +70,61 @@
|
||||
(list "_int_of_string" (fn (s) (parse-number s)))
|
||||
(list "_string_of_int" (fn (i) (str i)))
|
||||
(list "_string_of_float" (fn (f) (str f)))
|
||||
;; Integer formatting helpers used by Printf %x/%X/%o.
|
||||
(list "_int_to_hex_lower"
|
||||
(fn (n)
|
||||
(cond
|
||||
((= n 0) "0")
|
||||
(else
|
||||
(let ((digits "0123456789abcdef")
|
||||
(m (if (< n 0) (- 0 n) n))
|
||||
(out ""))
|
||||
(begin
|
||||
(define loop
|
||||
(fn ()
|
||||
(when (> m 0)
|
||||
(begin
|
||||
(set! out (str (nth digits (mod m 16)) out))
|
||||
(set! m (floor (/ m 16)))
|
||||
(loop)))))
|
||||
(loop)
|
||||
(if (< n 0) (str "-" out) out)))))))
|
||||
(list "_int_to_hex_upper"
|
||||
(fn (n)
|
||||
(cond
|
||||
((= n 0) "0")
|
||||
(else
|
||||
(let ((digits "0123456789ABCDEF")
|
||||
(m (if (< n 0) (- 0 n) n))
|
||||
(out ""))
|
||||
(begin
|
||||
(define loop
|
||||
(fn ()
|
||||
(when (> m 0)
|
||||
(begin
|
||||
(set! out (str (nth digits (mod m 16)) out))
|
||||
(set! m (floor (/ m 16)))
|
||||
(loop)))))
|
||||
(loop)
|
||||
(if (< n 0) (str "-" out) out)))))))
|
||||
(list "_int_to_octal"
|
||||
(fn (n)
|
||||
(cond
|
||||
((= n 0) "0")
|
||||
(else
|
||||
(let ((digits "01234567")
|
||||
(m (if (< n 0) (- 0 n) n))
|
||||
(out ""))
|
||||
(begin
|
||||
(define loop
|
||||
(fn ()
|
||||
(when (> m 0)
|
||||
(begin
|
||||
(set! out (str (nth digits (mod m 8)) out))
|
||||
(set! m (floor (/ m 8)))
|
||||
(loop)))))
|
||||
(loop)
|
||||
(if (< n 0) (str "-" out) out)))))))
|
||||
(list "_char_code" (fn (c) (char-code c)))
|
||||
(list "_char_chr" (fn (n) (char-from-code n)))
|
||||
;; Print: route to host SX `display` (no automatic newline).
|
||||
|
||||
@@ -524,12 +524,18 @@
|
||||
else if pos + 1 < n && _string_get fmt pos = \"%\" then
|
||||
let spec = _string_get fmt (pos + 1) in
|
||||
if spec = \"%\" then walk (pos + 2) (prefix ^ \"%\")
|
||||
else if spec = \"d\" || spec = \"s\" || spec = \"f\"
|
||||
|| spec = \"c\" || spec = \"b\" then
|
||||
else if spec = \"d\" || spec = \"i\" || spec = \"s\"
|
||||
|| spec = \"f\" || spec = \"c\" || spec = \"b\"
|
||||
|| spec = \"x\" || spec = \"X\" || spec = \"o\"
|
||||
|| spec = \"u\" then
|
||||
(fun arg ->
|
||||
let s =
|
||||
if spec = \"d\" then _string_of_int arg
|
||||
if spec = \"d\" || spec = \"i\" || spec = \"u\"
|
||||
then _string_of_int arg
|
||||
else if spec = \"f\" then _string_of_float arg
|
||||
else if spec = \"x\" then _int_to_hex_lower arg
|
||||
else if spec = \"X\" then _int_to_hex_upper arg
|
||||
else if spec = \"o\" then _int_to_octal arg
|
||||
else if spec = \"b\" then
|
||||
(if arg then \"true\" else \"false\")
|
||||
else arg
|
||||
|
||||
@@ -1318,6 +1318,18 @@ cat > "$TMPFILE" << 'EPOCHS'
|
||||
(epoch 5062)
|
||||
(eval "(ocaml-run \"List.length (List.sort compare [9;8;7;6;5;4;3;2;1;0])\")")
|
||||
|
||||
;; ── Printf %i %x %X %o ─────────────────────────────────────────
|
||||
(epoch 5070)
|
||||
(eval "(ocaml-run \"Printf.sprintf \\\"%i\\\" 42\")")
|
||||
(epoch 5071)
|
||||
(eval "(ocaml-run \"Printf.sprintf \\\"%x\\\" 255\")")
|
||||
(epoch 5072)
|
||||
(eval "(ocaml-run \"Printf.sprintf \\\"%X\\\" 4096\")")
|
||||
(epoch 5073)
|
||||
(eval "(ocaml-run \"Printf.sprintf \\\"%o\\\" 8\")")
|
||||
(epoch 5074)
|
||||
(eval "(ocaml-run \"Printf.sprintf \\\"%x %X %o\\\" 255 4096 8\")")
|
||||
|
||||
EPOCHS
|
||||
|
||||
OUTPUT=$(timeout 360 "$SX_SERVER" < "$TMPFILE" 2>/dev/null)
|
||||
@@ -2094,6 +2106,13 @@ check 5060 "sort 9-element list" '(1 2 3 4 5 6 7 8 9)'
|
||||
check 5061 "sort with reverse cmp" '(5 4 3 1 1)'
|
||||
check 5062 "sort 10 reversed -> length" '10'
|
||||
|
||||
# ── Printf %i %x %X %o ──────────────────────────────────────────
|
||||
check 5070 "%i 42" '"42"'
|
||||
check 5071 "%x 255" '"ff"'
|
||||
check 5072 "%X 4096" '"1000"'
|
||||
check 5073 "%o 8" '"10"'
|
||||
check 5074 "%x %X %o multi" '"ff 1000 10"'
|
||||
|
||||
TOTAL=$((PASS + FAIL))
|
||||
if [ $FAIL -eq 0 ]; then
|
||||
echo "ok $PASS/$TOTAL OCaml-on-SX tests passed"
|
||||
|
||||
@@ -407,6 +407,13 @@ _Newest first._
|
||||
binary search tree (`type 'a tree = Leaf | Node of 'a * 'a tree *
|
||||
'a tree`) with insert + in-order traversal. Tests parametric ADT,
|
||||
recursive match, List.append, List.fold_left.
|
||||
- 2026-05-09 Phase 6 — Printf.sprintf adds %i, %u (aliases of %d),
|
||||
%x (lowercase hex), %X (uppercase hex), %o (octal) (+5 tests, 533
|
||||
total). New host primitives `_int_to_hex_lower`, `_int_to_hex_upper`,
|
||||
`_int_to_octal` build the digit string by repeated host
|
||||
`floor (/ n base)` + `mod`. The Printf walker fans out specs to the
|
||||
right host helper. Examples: `%x` 255 = "ff", `%X` 4096 = "1000",
|
||||
`%o` 8 = "10", multi: `%x %X %o` 255 4096 8 = "ff 1000 10".
|
||||
- 2026-05-09 Phase 6 — List.sort upgraded from O(n²) insertion sort
|
||||
to O(n log n) mergesort (+3 tests, 528 total). split + merge are
|
||||
inner functions of sort; tuple destructuring on the split result is
|
||||
|
||||
Reference in New Issue
Block a user