Use match for value dispatch in evaluator and compiler

Convert large cond chains doing string equality dispatch to use the
match special form: step-eval-list (42 arms), step-continue (31 arms),
compile-list (30 arms), ho-setup-dispatch (7 arms), value-matches-type?
(10 arms). Also fix test-canonical.sx to use defsuite/deftest format
and load canonical.sx in both test runners.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-29 07:53:16 +00:00
parent 394c86b474
commit 8bba02fbc9
5 changed files with 1399 additions and 1414 deletions

View File

@@ -82,6 +82,18 @@ env["env-merge"] = function(a, b) { return Object.assign({}, a, b); };
// Missing primitives referenced by tests
// primitive? is now in platform.py PRIMITIVES
env["contains-char?"] = function(s, c) { return typeof s === "string" && typeof c === "string" && s.indexOf(c) >= 0; };
env["escape-string"] = function(s) { return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\t/g, "\\t"); };
env["trim-right"] = function(s) { return typeof s === "string" ? s.trimEnd() : s; };
env["sha3-256"] = function(s) {
// Simple hash stub for testing — not real SHA3
var h = 0;
for (var i = 0; i < s.length; i++) { h = ((h << 5) - h + s.charCodeAt(i)) | 0; }
h = Math.abs(h);
var hex = h.toString(16);
while (hex.length < 64) hex = "0" + hex;
return hex;
};
env["upcase"] = function(s) { return s.toUpperCase(); };
env["downcase"] = function(s) { return s.toLowerCase(); };
env["make-keyword"] = function(name) { return new Sx.Keyword(name); };
@@ -291,6 +303,18 @@ if (fs.existsSync(harnessPath)) {
}
}
// Load canonical.sx (content-addressing, serialization)
const canonicalPath = path.join(projectDir, "spec", "canonical.sx");
if (fs.existsSync(canonicalPath)) {
const canonicalSrc = fs.readFileSync(canonicalPath, "utf8");
const canonicalExprs = Sx.parse(canonicalSrc);
for (const expr of canonicalExprs) {
try { Sx.eval(expr, env); } catch (e) {
console.error(`Error loading canonical.sx: ${e.message}`);
}
}
}
// Load compiler + VM from lib/ when running full tests
if (fullBuild) {
const libDir = path.join(projectDir, "lib");

View File

@@ -390,6 +390,22 @@ let make_test_env () =
bind "defeffect" (fun _args -> Nil);
(* --- Primitives for canonical.sx / content tests --- *)
bind "symbol-name" (fun args ->
match args with
| [Symbol s] -> String s
| _ -> raise (Eval_error "symbol-name: expected symbol"));
bind "keyword-name" (fun args ->
match args with
| [Keyword k] -> String k
| _ -> raise (Eval_error "keyword-name: expected keyword"));
bind "trim-right" (fun args ->
match args with
| [String s] ->
let len = String.length s in
let i = ref (len - 1) in
while !i >= 0 && (s.[!i] = ' ' || s.[!i] = '\t' || s.[!i] = '\n' || s.[!i] = '\r') do decr i done;
String (String.sub s 0 (!i + 1))
| _ -> raise (Eval_error "trim-right: expected string"));
bind "contains-char?" (fun args ->
match args with
| [String s; String c] when String.length c = 1 ->
@@ -809,6 +825,8 @@ let run_spec_tests env test_files =
with e -> Printf.eprintf "Warning: %s: %s\n%!" name (Printexc.to_string e))
end
in
(* Content-addressing, serialization *)
load_module "canonical.sx" spec_dir;
(* Render adapter for test-render-html.sx *)
load_module "render.sx" spec_dir;
load_module "adapter-html.sx" web_dir;