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
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:
@@ -47,7 +47,26 @@
|
||||
;; can pattern-match them.
|
||||
(list "raise" (fn (e) (raise e)))
|
||||
(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
|
||||
(fn (env name)
|
||||
|
||||
@@ -136,6 +136,40 @@
|
||||
match r with
|
||||
| Ok _ -> false
|
||||
| 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")
|
||||
|
||||
(define ocaml-stdlib-loaded false)
|
||||
|
||||
@@ -672,6 +672,36 @@ cat > "$TMPFILE" << 'EPOCHS'
|
||||
(epoch 913)
|
||||
(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
|
||||
|
||||
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 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))
|
||||
if [ $FAIL -eq 0 ]; then
|
||||
echo "ok $PASS/$TOTAL OCaml-on-SX tests passed"
|
||||
|
||||
@@ -229,6 +229,16 @@ SX CEK evaluator (both JS and OCaml hosts)
|
||||
_(Pending: fold/join/iter/to_list/to_result.)_
|
||||
- [~] `Result`: `map`, `bind`, `is_ok`, `is_error`. _(Pending:
|
||||
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`,
|
||||
`uppercase_ascii`, `lowercase_ascii`, `contains`, `starts_with`, `ends_with`,
|
||||
`index_opt`, `replace_all` (non-stdlib but needed).
|
||||
@@ -333,6 +343,14 @@ the "mother tongue" closure: OCaml → SX → OCaml. This means:
|
||||
|
||||
_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
|
||||
consumer of `lib/guest/hm.sx` (algebra) and `lib/guest/match.sx`
|
||||
(unify). `lib/ocaml/infer.sx` ships Algorithm W rules for OCaml AST:
|
||||
|
||||
Reference in New Issue
Block a user