ocaml: phase 6 Filename module + Char.compare/equal/escaped (+7 tests, 569 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 31s

Filename module (forward-slash only, no Windows-separator detection):

  basename '/foo/bar/baz.ml'        = 'baz.ml'
  dirname  '/foo/bar/baz.ml'        = '/foo/bar'
  extension 'baz.tar.gz'            = '.gz'
  chop_extension 'hello.ml'         = 'hello'
  concat 'a' 'b'                    = 'a/b'
  is_relative 'a/b'                 = true
  current_dir_name = '.', parent_dir_name = '..', dir_sep = '/'

Char additions:

  equal a b                         = (a = b)
  compare a b                       = code(a) - code(b)
  escaped '\n'                      = '\\n'    (likewise t, r, \\, ")
This commit is contained in:
2026-05-09 05:24:37 +00:00
parent 7773c40337
commit 5d33f8f20b
3 changed files with 98 additions and 0 deletions

View File

@@ -474,6 +474,69 @@
let is_alnum c = is_alpha c || is_digit c
let is_whitespace c =
c = \" \" || c = \"\\t\" || c = \"\\n\" || c = \"\\r\"
let equal a b = a = b
let compare a b = _char_code a - _char_code b
let escaped c =
if c = \"\\n\" then \"\\\\n\"
else if c = \"\\t\" then \"\\\\t\"
else if c = \"\\r\" then \"\\\\r\"
else if c = \"\\\\\" then \"\\\\\\\\\"
else if c = \"\\\"\" then \"\\\\\\\"\"
else c
end ;;
module Filename = struct
(* Minimal Filename: basename / dirname / extension / concat /
chop_suffix. Forward-slash only — doesn't try to detect
Windows-style separators. *)
let _last_slash s =
let n = _string_length s in
let rec aux i =
if i < 0 then -1
else if _string_get s i = \"/\" then i
else aux (i - 1)
in
aux (n - 1)
let basename s =
let i = _last_slash s in
if i < 0 then s
else _string_sub s (i + 1) (_string_length s - i - 1)
let dirname s =
let i = _last_slash s in
if i < 0 then \".\"
else if i = 0 then \"/\"
else _string_sub s 0 i
let extension s =
let b = basename s in
let n = _string_length b in
let rec aux i =
if i < 0 then \"\"
else if _string_get b i = \".\" then
_string_sub b i (n - i)
else aux (i - 1)
in
aux (n - 1)
let chop_extension s =
let ext = extension s in
let nx = _string_length ext in
if nx = 0 then s
else _string_sub s 0 (_string_length s - nx)
let concat a b =
if _string_length a = 0 then b
else if _string_get a (_string_length a - 1) = \"/\" then a ^ b
else a ^ \"/\" ^ b
let is_relative s =
_string_length s = 0 || _string_get s 0 <> \"/\"
let current_dir_name = \".\"
let parent_dir_name = \"..\"
let dir_sep = \"/\"
end ;;
module Int = struct

View File

@@ -1404,6 +1404,24 @@ cat > "$TMPFILE" << 'EPOCHS'
(epoch 5152)
(eval "(ocaml-run \"let f ?x ~y = x + y in f ?x:1 ~y:2\")")
;; ── Filename module ──────────────────────────────────────────
(epoch 5160)
(eval "(ocaml-run \"Filename.basename \\\"/foo/bar/baz.ml\\\"\")")
(epoch 5161)
(eval "(ocaml-run \"Filename.dirname \\\"/foo/bar/baz.ml\\\"\")")
(epoch 5162)
(eval "(ocaml-run \"Filename.extension \\\"baz.tar.gz\\\"\")")
(epoch 5163)
(eval "(ocaml-run \"Filename.concat \\\"a\\\" \\\"b\\\"\")")
(epoch 5164)
(eval "(ocaml-run \"Filename.chop_extension \\\"hello.ml\\\"\")")
;; ── Char.compare / equal / escaped ─────────────────────────
(epoch 5170)
(eval "(ocaml-run \"Char.compare \\\"b\\\" \\\"a\\\"\")")
(epoch 5171)
(eval "(ocaml-run \"Char.equal \\\"a\\\" \\\"a\\\"\")")
EPOCHS
OUTPUT=$(timeout 360 "$SX_SERVER" < "$TMPFILE" 2>/dev/null)
@@ -2232,6 +2250,17 @@ check 5150 "f ~x:3 ~y:7 sum" '10'
check 5151 "f ~x ~y punning" '20'
check 5152 "f ?x:1 ~y:2 (no Some wrap)" '3'
# ── Filename module ─────────────────────────────────────────────
check 5160 "basename /foo/bar/baz.ml" '"baz.ml"'
check 5161 "dirname /foo/bar/baz.ml" '"/foo/bar"'
check 5162 "extension baz.tar.gz" '".gz"'
check 5163 "concat a b" '"a/b"'
check 5164 "chop_extension hello.ml" '"hello"'
# ── Char.compare / equal ────────────────────────────────────────
check 5170 "Char.compare b a" '1'
check 5171 "Char.equal a a" 'true'
TOTAL=$((PASS + FAIL))
if [ $FAIL -eq 0 ]; then
echo "ok $PASS/$TOTAL OCaml-on-SX tests passed"

View File

@@ -407,6 +407,12 @@ _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 — Filename module + Char.compare/equal/escaped
(+7 tests, 569 total). Filename: basename, dirname, extension,
chop_extension, concat, is_relative + dir_sep / current_dir_name /
parent_dir_name constants. Forward-slash only, doesn't try to
detect Windows separators. Char additions: equal, compare (via
code subtraction), escaped (handles `\n`/`\t`/`\r`/`\\`/`\"`).
- 2026-05-09 Phase 4 — basic labeled / optional argument syntax
(label dropped, positional semantics) (+3 tests, 562 total). Three
parser changes: