Move stdlib out of spec — clean spec/library boundary

spec/ now contains only the language definition (5 files):
  evaluator.sx, parser.sx, primitives.sx, render.sx, special-forms.sx

lib/ contains code written IN the language (8 files):
  stdlib.sx, types.sx, freeze.sx, content.sx,
  bytecode.sx, compiler.sx, vm.sx, callcc.sx

Test files follow source: spec/tests/ for core language tests,
lib/tests/ for library tests (continuations, freeze, types, vm).

Updated all consumers:
- JS/Python/OCaml bootstrappers: added lib/ to source search paths
- OCaml bridge: spec_dir for parser/render, lib_dir for compiler/freeze
- JS test runner: scans spec/tests/ (always) + lib/tests/ (--full)
- OCaml test runner: scans spec/tests/, lib tests via explicit request
- Docker dev mounts: added ./lib:/app/lib:ro

Tests: 1041 JS standard, 1322 JS full, 1101 OCaml — all pass

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-24 23:18:30 +00:00
parent 50871780a3
commit f3f70cc00b
26 changed files with 109 additions and 64 deletions

View File

@@ -386,12 +386,13 @@ let () =
in
let root = find_root (Sys.getcwd ()) in
let spec p = Filename.concat (Filename.concat root "spec") p in
let lib p = Filename.concat (Filename.concat root "lib") p in
let web p = Filename.concat (Filename.concat root "web") p in
let env = make_integration_env () in
(* Load spec + adapters *)
Printf.printf "Loading spec + adapters...\n%!";
(* Load spec + lib + adapters *)
Printf.printf "Loading spec + lib + adapters...\n%!";
let load path =
if Sys.file_exists path then begin
let exprs = Sx_parser.parse_file path in
@@ -405,6 +406,7 @@ let () =
load (web "signals.sx");
load (web "adapter-html.sx");
load (web "adapter-sx.sx");
ignore lib; (* available for future library loading *)
(* Helper: render SX source string to HTML *)
let render_html src =

View File

@@ -734,10 +734,11 @@ let run_spec_tests env test_files =
Printf.printf "\nLoading test framework...\n%!";
load_and_eval framework_path;
(* Load spec modules needed by tests *)
(* Load modules needed by tests *)
let spec_dir = Filename.concat project_dir "spec" in
let lib_dir = Filename.concat project_dir "lib" in
let web_dir = Filename.concat project_dir "web" in
let load_spec name dir =
let load_module name dir =
let path = Filename.concat dir name in
if Sys.file_exists path then begin
Printf.printf "Loading %s...\n%!" name;
@@ -746,36 +747,47 @@ let run_spec_tests env test_files =
end
in
(* Render adapter for test-render-html.sx *)
load_spec "render.sx" spec_dir;
load_spec "adapter-html.sx" web_dir;
(* Compiler + VM for test-vm.sx *)
load_spec "bytecode.sx" spec_dir;
load_spec "compiler.sx" spec_dir;
load_spec "vm.sx" spec_dir;
load_module "render.sx" spec_dir;
load_module "adapter-html.sx" web_dir;
(* Library modules for lib/tests/ *)
load_module "bytecode.sx" lib_dir;
load_module "compiler.sx" lib_dir;
load_module "vm.sx" lib_dir;
load_module "signals.sx" web_dir;
load_module "freeze.sx" lib_dir;
load_module "content.sx" lib_dir;
load_module "types.sx" lib_dir;
(* Determine test files *)
(* Determine test files — scan spec/tests/ and lib/tests/ *)
let lib_tests_dir = Filename.concat project_dir "lib/tests" in
let files = if test_files = [] then begin
let entries = Sys.readdir spec_tests_dir in
Array.sort String.compare entries;
let requires_full = ["test-continuations.sx"; "test-types.sx"; "test-freeze.sx";
"test-continuations-advanced.sx"; "test-signals-advanced.sx";
"test-vm.sx"] in
Array.to_list entries
|> List.filter (fun f ->
String.length f > 5 &&
String.sub f 0 5 = "test-" &&
Filename.check_suffix f ".sx" &&
f <> "test-framework.sx" &&
not (List.mem f requires_full))
(* Spec tests (core language — always run) *)
let spec_entries = Sys.readdir spec_tests_dir in
Array.sort String.compare spec_entries;
let spec_files = Array.to_list spec_entries
|> List.filter (fun f ->
String.length f > 5 &&
String.sub f 0 5 = "test-" &&
Filename.check_suffix f ".sx" &&
f <> "test-framework.sx")
|> List.map (fun f -> Filename.concat spec_tests_dir f)
in
spec_files
end else
(* Specific test files — search all test dirs *)
List.map (fun name ->
if Filename.check_suffix name ".sx" then name
else name ^ ".sx") test_files
let name = if Filename.check_suffix name ".sx" then name else name ^ ".sx" in
let spec_path = Filename.concat spec_tests_dir name in
let lib_path = Filename.concat lib_tests_dir name in
if Sys.file_exists spec_path then spec_path
else if Sys.file_exists lib_path then lib_path
else Filename.concat spec_tests_dir name (* will fail with "not found" *)
) test_files
in
List.iter (fun name ->
let path = Filename.concat spec_tests_dir name in
List.iter (fun path ->
if Sys.file_exists path then begin
let name = Filename.basename path in
Printf.printf "\n%s\n" (String.make 60 '=');
Printf.printf "Running %s\n" name;
Printf.printf "%s\n%!" (String.make 60 '=');

View File

@@ -1174,18 +1174,20 @@ let cli_load_files env files =
let cli_mode mode =
let env = make_server_env () in
(* Load spec + adapter files for aser modes *)
let base = try Sys.getenv "SX_SPEC_DIR" with Not_found -> "spec" in
let spec_base = try Sys.getenv "SX_SPEC_DIR" with Not_found -> "spec" in
let lib_base = try Sys.getenv "SX_LIB_DIR" with Not_found -> "lib" in
let web_base = try Sys.getenv "SX_WEB_DIR" with Not_found -> "web" in
let spec_files = [
Filename.concat base "parser.sx";
Filename.concat base "render.sx";
let render_files = [
Filename.concat spec_base "parser.sx";
Filename.concat spec_base "render.sx";
Filename.concat web_base "adapter-html.sx";
Filename.concat web_base "adapter-sx.sx";
Filename.concat web_base "web-forms.sx";
] in
(* Load spec files for all CLI modes that need rendering *)
(* Load spec + adapter files for rendering CLI modes *)
(if mode = "aser" || mode = "aser-slot" || mode = "render" then
cli_load_files env spec_files);
cli_load_files env render_files);
ignore lib_base; (* available for --load paths *)
(* Load any files passed via --load *)
let load_files = ref [] in
let args = Array.to_list Sys.argv in
@@ -1256,13 +1258,14 @@ let cli_mode mode =
let test_mode () =
let env = make_server_env () in
(* Load full spec + adapter stack *)
let base = try Sys.getenv "SX_SPEC_DIR" with Not_found -> "spec" in
(* Load spec + lib + adapter stack *)
let spec_base = try Sys.getenv "SX_SPEC_DIR" with Not_found -> "spec" in
let lib_base = try Sys.getenv "SX_LIB_DIR" with Not_found -> "lib" in
let web_base = try Sys.getenv "SX_WEB_DIR" with Not_found -> "web" in
let files = [
Filename.concat base "parser.sx";
Filename.concat base "render.sx";
Filename.concat base "compiler.sx";
Filename.concat spec_base "parser.sx";
Filename.concat spec_base "render.sx";
Filename.concat lib_base "compiler.sx";
Filename.concat web_base "signals.sx";
Filename.concat web_base "adapter-html.sx";
Filename.concat web_base "adapter-sx.sx";