ocaml: phase 6 String/Char/Int/Float/Printf modules (+13 tests, 278 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 53s

Host primitives _string_length / _string_sub / _char_code / etc. exposed
in the base env (underscore-prefixed to avoid user clash). lib/ocaml/
runtime.sx wraps them into OCaml-syntax modules: String (length, get,
sub, concat, uppercase/lowercase_ascii, starts_with), Char (code, chr,
lowercase/uppercase_ascii), Int (to_string, of_string, abs, max, min),
Float.to_string, Printf stubs.

Also added print_string / print_endline / print_int IO builtins.
This commit is contained in:
2026-05-08 09:10:06 +00:00
parent 26863242a0
commit c8bfd22786
4 changed files with 119 additions and 1 deletions

View File

@@ -47,7 +47,26 @@
;; can pattern-match them. ;; can pattern-match them.
(list "raise" (fn (e) (raise e))) (list "raise" (fn (e) (raise e)))
(list "failwith" (fn (msg) (raise (list "Failure" msg)))) (list "failwith" (fn (msg) (raise (list "Failure" msg))))
(list "invalid_arg" (fn (msg) (raise (list "Invalid_argument" msg))))))) (list "invalid_arg" (fn (msg) (raise (list "Invalid_argument" msg)))
)
;; Host primitives exposed for the OCaml stdlib (lib/ocaml/runtime.sx).
;; Underscore-prefixed to avoid clashing with user names.
(list "_string_length" (fn (s) (len s)))
(list "_string_get" (fn (s) (fn (i) (nth s i))))
(list "_string_sub" (fn (s) (fn (i) (fn (n) (slice s i (+ i n))))))
(list "_string_concat" (fn (sep) (fn (xs) (join sep xs))))
(list "_string_upper" (fn (s) (upper s)))
(list "_string_lower" (fn (s) (lower s)))
(list "_string_starts_with" (fn (p) (fn (s) (starts-with? s p))))
(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)))
(list "_char_code" (fn (c) (char-code c)))
(list "_char_chr" (fn (n) (char-from-code n)))
;; Print: prints to host stdout via println.
(list "print_string" (fn (s) (begin (print s) nil)))
(list "print_endline" (fn (s) (begin (println s) nil)))
(list "print_int" (fn (i) (begin (print (str i)) nil))))))
(define ocaml-env-lookup (define ocaml-env-lookup
(fn (env name) (fn (env name)

View File

@@ -136,6 +136,40 @@
match r with match r with
| Ok _ -> false | Ok _ -> false
| Error _ -> true | Error _ -> true
end ;;
module String = struct
let length s = _string_length s
let get s i = _string_get s i
let sub s i n = _string_sub s i n
let concat sep xs = _string_concat sep xs
let uppercase_ascii s = _string_upper s
let lowercase_ascii s = _string_lower s
let starts_with prefix s = _string_starts_with prefix s
end ;;
module Char = struct
let code c = _char_code c
let chr n = _char_chr n
let lowercase_ascii c = _string_lower c
let uppercase_ascii c = _string_upper c
end ;;
module Int = struct
let to_string i = _string_of_int i
let of_string s = _int_of_string s
let abs n = if n < 0 then 0 - n else n
let max a b = if a > b then a else b
let min a b = if a < b then a else b
end ;;
module Float = struct
let to_string f = _string_of_float f
end ;;
module Printf = struct
let sprintf fmt = fmt
let printf fmt = print_string fmt
end") end")
(define ocaml-stdlib-loaded false) (define ocaml-stdlib-loaded false)

View File

@@ -672,6 +672,36 @@ cat > "$TMPFILE" << 'EPOCHS'
(epoch 913) (epoch 913)
(eval "(ocaml-type-of \"not true\")") (eval "(ocaml-type-of \"not true\")")
;; ── Phase 6 expanded: String / Char / Int / Float modules ─────
(epoch 950)
(eval "(ocaml-run \"String.length \\\"hello\\\"\")")
(epoch 951)
(eval "(ocaml-run \"String.uppercase_ascii \\\"hi\\\"\")")
(epoch 952)
(eval "(ocaml-run \"String.lowercase_ascii \\\"HI\\\"\")")
(epoch 953)
(eval "(ocaml-run \"String.sub \\\"hello\\\" 1 3\")")
(epoch 954)
(eval "(ocaml-run \"String.starts_with \\\"he\\\" \\\"hello\\\"\")")
(epoch 955)
(eval "(ocaml-run \"String.concat \\\",\\\" [\\\"a\\\"; \\\"b\\\"; \\\"c\\\"]\")")
(epoch 960)
(eval "(ocaml-run \"Char.code \\\"A\\\"\")")
(epoch 961)
(eval "(ocaml-run \"Char.chr 65\")")
(epoch 970)
(eval "(ocaml-run \"Int.to_string 42\")")
(epoch 971)
(eval "(ocaml-run \"Int.of_string \\\"123\\\"\")")
(epoch 972)
(eval "(ocaml-run \"Int.abs (-5)\")")
(epoch 973)
(eval "(ocaml-run \"Int.max 7 3\")")
(epoch 974)
(eval "(ocaml-run \"Int.min 7 3\")")
EPOCHS EPOCHS
OUTPUT=$(timeout 60 "$SX_SERVER" < "$TMPFILE" 2>/dev/null) OUTPUT=$(timeout 60 "$SX_SERVER" < "$TMPFILE" 2>/dev/null)
@@ -1065,6 +1095,23 @@ check 911 "type twice" ' -> '
check 912 "type bool branch" '"Bool -> Int"' check 912 "type bool branch" '"Bool -> Int"'
check 913 "type not true" '"Bool"' check 913 "type not true" '"Bool"'
# ── Phase 6 String / Char / Int ─────────────────────────────────
check 950 "String.length" '5'
check 951 "String.uppercase_ascii" '"HI"'
check 952 "String.lowercase_ascii" '"hi"'
check 953 "String.sub" '"ell"'
check 954 "String.starts_with" 'true'
check 955 "String.concat" '"a,b,c"'
check 960 "Char.code A" '65'
check 961 "Char.chr 65" '"A"'
check 970 "Int.to_string" '"42"'
check 971 "Int.of_string" '123'
check 972 "Int.abs -5" '5'
check 973 "Int.max" '7'
check 974 "Int.min" '3'
TOTAL=$((PASS + FAIL)) TOTAL=$((PASS + FAIL))
if [ $FAIL -eq 0 ]; then if [ $FAIL -eq 0 ]; then
echo "ok $PASS/$TOTAL OCaml-on-SX tests passed" echo "ok $PASS/$TOTAL OCaml-on-SX tests passed"

View File

@@ -229,6 +229,16 @@ SX CEK evaluator (both JS and OCaml hosts)
_(Pending: fold/join/iter/to_list/to_result.)_ _(Pending: fold/join/iter/to_list/to_result.)_
- [~] `Result`: `map`, `bind`, `is_ok`, `is_error`. _(Pending: - [~] `Result`: `map`, `bind`, `is_ok`, `is_error`. _(Pending:
fold/get_ok/get_error/map_error/to_option.)_ fold/get_ok/get_error/map_error/to_option.)_
- [~] `String`: `length`, `get`, `sub`, `concat`, `uppercase_ascii`,
`lowercase_ascii`, `starts_with`. _(Pending: split_on_char, trim,
contains, ends_with, index_opt, replace_all.)_
- [~] `Char`: `code`, `chr`, `lowercase_ascii`, `uppercase_ascii`.
_(Pending: escaped.)_
- [~] `Int`: `to_string`, `of_string`, `abs`, `max`, `min`.
_(Pending: arithmetic helpers, min_int/max_int.)_
- [~] `Float`: `to_string`. _(Pending: of_string, arithmetic helpers.)_
- [~] `Printf`: stub `sprintf`/`printf`. _(Real format-string
interpretation pending.)_
- [ ] `String`: `length`, `get`, `sub`, `concat`, `split_on_char`, `trim`, - [ ] `String`: `length`, `get`, `sub`, `concat`, `split_on_char`, `trim`,
`uppercase_ascii`, `lowercase_ascii`, `contains`, `starts_with`, `ends_with`, `uppercase_ascii`, `lowercase_ascii`, `contains`, `starts_with`, `ends_with`,
`index_opt`, `replace_all` (non-stdlib but needed). `index_opt`, `replace_all` (non-stdlib but needed).
@@ -333,6 +343,14 @@ the "mother tongue" closure: OCaml → SX → OCaml. This means:
_Newest first._ _Newest first._
- 2026-05-08 Phase 6 — extended stdlib slice (+13 tests, 278 total).
Host primitives exposed via `_string_*`, `_char_*`, `_int_*`,
`_string_of_*` underscore-prefixed builtins so the OCaml-side
`lib/ocaml/runtime.sx` modules can wrap them: String (length, get,
sub, concat, uppercase_ascii, lowercase_ascii, starts_with), Char
(code, chr, lowercase_ascii, uppercase_ascii), Int (to_string,
of_string, abs, max, min), Float.to_string, Printf stubs. Also added
`print_string`/`print_endline`/`print_int` builtins.
- 2026-05-08 Phase 5 — Hindley-Milner type inference, paired-sequencing - 2026-05-08 Phase 5 — Hindley-Milner type inference, paired-sequencing
consumer of `lib/guest/hm.sx` (algebra) and `lib/guest/match.sx` consumer of `lib/guest/hm.sx` (algebra) and `lib/guest/match.sx`
(unify). `lib/ocaml/infer.sx` ships Algorithm W rules for OCaml AST: (unify). `lib/ocaml/infer.sx` ships Algorithm W rules for OCaml AST: