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:
@@ -31,8 +31,9 @@ services:
|
|||||||
- ./sx/sx:/app/sx
|
- ./sx/sx:/app/sx
|
||||||
- ./sx/path_setup.py:/app/path_setup.py
|
- ./sx/path_setup.py:/app/path_setup.py
|
||||||
- ./sx/entrypoint.sh:/usr/local/bin/entrypoint.sh
|
- ./sx/entrypoint.sh:/usr/local/bin/entrypoint.sh
|
||||||
# Spec + web SX files (loaded by OCaml kernel for aser, parser, render)
|
# Spec + lib + web SX files (loaded by OCaml kernel)
|
||||||
- ./spec:/app/spec:ro
|
- ./spec:/app/spec:ro
|
||||||
|
- ./lib:/app/lib:ro
|
||||||
- ./web:/app/web:ro
|
- ./web:/app/web:ro
|
||||||
# OCaml SX kernel binary (built with: cd hosts/ocaml && eval $(opam env) && dune build)
|
# OCaml SX kernel binary (built with: cd hosts/ocaml && eval $(opam env) && dune build)
|
||||||
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ services:
|
|||||||
- ./shared:/app/shared
|
- ./shared:/app/shared
|
||||||
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
||||||
- ./spec:/app/spec:ro
|
- ./spec:/app/spec:ro
|
||||||
|
- ./lib:/app/lib:ro
|
||||||
- ./web:/app/web:ro
|
- ./web:/app/web:ro
|
||||||
- ./blog/alembic.ini:/app/blog/alembic.ini:ro
|
- ./blog/alembic.ini:/app/blog/alembic.ini:ro
|
||||||
- ./blog/alembic:/app/blog/alembic:ro
|
- ./blog/alembic:/app/blog/alembic:ro
|
||||||
@@ -90,6 +91,7 @@ services:
|
|||||||
- ./shared:/app/shared
|
- ./shared:/app/shared
|
||||||
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
||||||
- ./spec:/app/spec:ro
|
- ./spec:/app/spec:ro
|
||||||
|
- ./lib:/app/lib:ro
|
||||||
- ./web:/app/web:ro
|
- ./web:/app/web:ro
|
||||||
- ./market/alembic.ini:/app/market/alembic.ini:ro
|
- ./market/alembic.ini:/app/market/alembic.ini:ro
|
||||||
- ./market/alembic:/app/market/alembic:ro
|
- ./market/alembic:/app/market/alembic:ro
|
||||||
@@ -131,6 +133,7 @@ services:
|
|||||||
- ./shared:/app/shared
|
- ./shared:/app/shared
|
||||||
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
||||||
- ./spec:/app/spec:ro
|
- ./spec:/app/spec:ro
|
||||||
|
- ./lib:/app/lib:ro
|
||||||
- ./web:/app/web:ro
|
- ./web:/app/web:ro
|
||||||
- ./cart/alembic.ini:/app/cart/alembic.ini:ro
|
- ./cart/alembic.ini:/app/cart/alembic.ini:ro
|
||||||
- ./cart/alembic:/app/cart/alembic:ro
|
- ./cart/alembic:/app/cart/alembic:ro
|
||||||
@@ -172,6 +175,7 @@ services:
|
|||||||
- ./shared:/app/shared
|
- ./shared:/app/shared
|
||||||
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
||||||
- ./spec:/app/spec:ro
|
- ./spec:/app/spec:ro
|
||||||
|
- ./lib:/app/lib:ro
|
||||||
- ./web:/app/web:ro
|
- ./web:/app/web:ro
|
||||||
- ./events/alembic.ini:/app/events/alembic.ini:ro
|
- ./events/alembic.ini:/app/events/alembic.ini:ro
|
||||||
- ./events/alembic:/app/events/alembic:ro
|
- ./events/alembic:/app/events/alembic:ro
|
||||||
@@ -213,6 +217,7 @@ services:
|
|||||||
- ./shared:/app/shared
|
- ./shared:/app/shared
|
||||||
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
||||||
- ./spec:/app/spec:ro
|
- ./spec:/app/spec:ro
|
||||||
|
- ./lib:/app/lib:ro
|
||||||
- ./web:/app/web:ro
|
- ./web:/app/web:ro
|
||||||
- ./federation/alembic.ini:/app/federation/alembic.ini:ro
|
- ./federation/alembic.ini:/app/federation/alembic.ini:ro
|
||||||
- ./federation/alembic:/app/federation/alembic:ro
|
- ./federation/alembic:/app/federation/alembic:ro
|
||||||
@@ -254,6 +259,7 @@ services:
|
|||||||
- ./shared:/app/shared
|
- ./shared:/app/shared
|
||||||
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
||||||
- ./spec:/app/spec:ro
|
- ./spec:/app/spec:ro
|
||||||
|
- ./lib:/app/lib:ro
|
||||||
- ./web:/app/web:ro
|
- ./web:/app/web:ro
|
||||||
- ./account/alembic.ini:/app/account/alembic.ini:ro
|
- ./account/alembic.ini:/app/account/alembic.ini:ro
|
||||||
- ./account/alembic:/app/account/alembic:ro
|
- ./account/alembic:/app/account/alembic:ro
|
||||||
@@ -295,6 +301,7 @@ services:
|
|||||||
- ./shared:/app/shared
|
- ./shared:/app/shared
|
||||||
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
||||||
- ./spec:/app/spec:ro
|
- ./spec:/app/spec:ro
|
||||||
|
- ./lib:/app/lib:ro
|
||||||
- ./web:/app/web:ro
|
- ./web:/app/web:ro
|
||||||
- ./relations/alembic.ini:/app/relations/alembic.ini:ro
|
- ./relations/alembic.ini:/app/relations/alembic.ini:ro
|
||||||
- ./relations/alembic:/app/relations/alembic:ro
|
- ./relations/alembic:/app/relations/alembic:ro
|
||||||
@@ -329,6 +336,7 @@ services:
|
|||||||
- ./shared:/app/shared
|
- ./shared:/app/shared
|
||||||
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
||||||
- ./spec:/app/spec:ro
|
- ./spec:/app/spec:ro
|
||||||
|
- ./lib:/app/lib:ro
|
||||||
- ./web:/app/web:ro
|
- ./web:/app/web:ro
|
||||||
- ./likes/alembic.ini:/app/likes/alembic.ini:ro
|
- ./likes/alembic.ini:/app/likes/alembic.ini:ro
|
||||||
- ./likes/alembic:/app/likes/alembic:ro
|
- ./likes/alembic:/app/likes/alembic:ro
|
||||||
@@ -363,6 +371,7 @@ services:
|
|||||||
- ./shared:/app/shared
|
- ./shared:/app/shared
|
||||||
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
||||||
- ./spec:/app/spec:ro
|
- ./spec:/app/spec:ro
|
||||||
|
- ./lib:/app/lib:ro
|
||||||
- ./web:/app/web:ro
|
- ./web:/app/web:ro
|
||||||
- ./orders/alembic.ini:/app/orders/alembic.ini:ro
|
- ./orders/alembic.ini:/app/orders/alembic.ini:ro
|
||||||
- ./orders/alembic:/app/orders/alembic:ro
|
- ./orders/alembic:/app/orders/alembic:ro
|
||||||
@@ -400,6 +409,7 @@ services:
|
|||||||
- ./shared:/app/shared
|
- ./shared:/app/shared
|
||||||
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
||||||
- ./spec:/app/spec:ro
|
- ./spec:/app/spec:ro
|
||||||
|
- ./lib:/app/lib:ro
|
||||||
- ./web:/app/web:ro
|
- ./web:/app/web:ro
|
||||||
- ./test/app.py:/app/app.py
|
- ./test/app.py:/app/app.py
|
||||||
- ./test/sx:/app/sx
|
- ./test/sx:/app/sx
|
||||||
@@ -431,6 +441,7 @@ services:
|
|||||||
- ./shared:/app/shared
|
- ./shared:/app/shared
|
||||||
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
||||||
- ./spec:/app/spec:ro
|
- ./spec:/app/spec:ro
|
||||||
|
- ./lib:/app/lib:ro
|
||||||
- ./web:/app/web:ro
|
- ./web:/app/web:ro
|
||||||
- ./sx/app.py:/app/app.py
|
- ./sx/app.py:/app/app.py
|
||||||
- ./sx/sxc:/app/sxc
|
- ./sx/sxc:/app/sxc
|
||||||
@@ -469,6 +480,7 @@ services:
|
|||||||
- ./shared:/app/shared
|
- ./shared:/app/shared
|
||||||
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
||||||
- ./spec:/app/spec:ro
|
- ./spec:/app/spec:ro
|
||||||
|
- ./lib:/app/lib:ro
|
||||||
- ./web:/app/web:ro
|
- ./web:/app/web:ro
|
||||||
- ./artdag/core:/app/artdag/core
|
- ./artdag/core:/app/artdag/core
|
||||||
- ./artdag/l1/tests:/app/artdag/l1/tests
|
- ./artdag/l1/tests:/app/artdag/l1/tests
|
||||||
@@ -497,6 +509,7 @@ services:
|
|||||||
- ./shared:/app/shared
|
- ./shared:/app/shared
|
||||||
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
||||||
- ./spec:/app/spec:ro
|
- ./spec:/app/spec:ro
|
||||||
|
- ./lib:/app/lib:ro
|
||||||
- ./web:/app/web:ro
|
- ./web:/app/web:ro
|
||||||
- ./artdag:/app/artdag
|
- ./artdag:/app/artdag
|
||||||
profiles:
|
profiles:
|
||||||
|
|||||||
@@ -70,9 +70,10 @@ def compile_ref_to_js(
|
|||||||
"""
|
"""
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
# Source directories: core spec and web framework
|
# Source directories: core spec, standard library, web framework
|
||||||
_source_dirs = [
|
_source_dirs = [
|
||||||
os.path.join(_PROJECT, "spec"), # Core spec
|
os.path.join(_PROJECT, "spec"), # Core language spec
|
||||||
|
os.path.join(_PROJECT, "lib"), # Standard library (stdlib, compiler, vm, ...)
|
||||||
os.path.join(_PROJECT, "web"), # Web framework
|
os.path.join(_PROJECT, "web"), # Web framework
|
||||||
]
|
]
|
||||||
bridge = _get_bridge()
|
bridge = _get_bridge()
|
||||||
|
|||||||
@@ -270,6 +270,7 @@ env["pop-suite"] = function() {
|
|||||||
// Load test framework
|
// Load test framework
|
||||||
const projectDir = path.join(__dirname, "..", "..");
|
const projectDir = path.join(__dirname, "..", "..");
|
||||||
const specTests = path.join(projectDir, "spec", "tests");
|
const specTests = path.join(projectDir, "spec", "tests");
|
||||||
|
const libTests = path.join(projectDir, "lib", "tests");
|
||||||
const webTests = path.join(projectDir, "web", "tests");
|
const webTests = path.join(projectDir, "web", "tests");
|
||||||
|
|
||||||
const frameworkSrc = fs.readFileSync(path.join(specTests, "test-framework.sx"), "utf8");
|
const frameworkSrc = fs.readFileSync(path.join(specTests, "test-framework.sx"), "utf8");
|
||||||
@@ -278,17 +279,17 @@ for (const expr of frameworkExprs) {
|
|||||||
Sx.eval(expr, env);
|
Sx.eval(expr, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load compiler + VM spec when running full tests
|
// Load compiler + VM from lib/ when running full tests
|
||||||
if (fullBuild) {
|
if (fullBuild) {
|
||||||
const specDir = path.join(projectDir, "spec");
|
const libDir = path.join(projectDir, "lib");
|
||||||
for (const specFile of ["bytecode.sx", "compiler.sx", "vm.sx"]) {
|
for (const libFile of ["bytecode.sx", "compiler.sx", "vm.sx"]) {
|
||||||
const specPath = path.join(specDir, specFile);
|
const libPath = path.join(libDir, libFile);
|
||||||
if (fs.existsSync(specPath)) {
|
if (fs.existsSync(libPath)) {
|
||||||
const src = fs.readFileSync(specPath, "utf8");
|
const src = fs.readFileSync(libPath, "utf8");
|
||||||
const exprs = Sx.parse(src);
|
const exprs = Sx.parse(src);
|
||||||
for (const expr of exprs) {
|
for (const expr of exprs) {
|
||||||
try { Sx.eval(expr, env); } catch (e) {
|
try { Sx.eval(expr, env); } catch (e) {
|
||||||
console.error(`Error loading ${specFile}: ${e.message}`);
|
console.error(`Error loading ${libFile}: ${e.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -300,28 +301,32 @@ const args = process.argv.slice(2).filter(a => !a.startsWith("--"));
|
|||||||
let testFiles = [];
|
let testFiles = [];
|
||||||
|
|
||||||
if (args.length > 0) {
|
if (args.length > 0) {
|
||||||
// Specific test files
|
// Specific test files — search spec, lib, and web test dirs
|
||||||
for (const arg of args) {
|
for (const arg of args) {
|
||||||
const name = arg.endsWith(".sx") ? arg : `${arg}.sx`;
|
const name = arg.endsWith(".sx") ? arg : `${arg}.sx`;
|
||||||
const specPath = path.join(specTests, name);
|
const specPath = path.join(specTests, name);
|
||||||
|
const libPath = path.join(libTests, name);
|
||||||
const webPath = path.join(webTests, name);
|
const webPath = path.join(webTests, name);
|
||||||
if (fs.existsSync(specPath)) testFiles.push(specPath);
|
if (fs.existsSync(specPath)) testFiles.push(specPath);
|
||||||
|
else if (fs.existsSync(libPath)) testFiles.push(libPath);
|
||||||
else if (fs.existsSync(webPath)) testFiles.push(webPath);
|
else if (fs.existsSync(webPath)) testFiles.push(webPath);
|
||||||
else console.error(`Test file not found: ${name}`);
|
else console.error(`Test file not found: ${name}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Tests requiring optional modules (only run with --full)
|
// All spec tests (core language — always run)
|
||||||
const requiresFull = new Set(["test-continuations.sx", "test-continuations-advanced.sx", "test-types.sx", "test-freeze.sx", "test-vm.sx"]);
|
|
||||||
// All spec tests
|
|
||||||
for (const f of fs.readdirSync(specTests).sort()) {
|
for (const f of fs.readdirSync(specTests).sort()) {
|
||||||
if (f.startsWith("test-") && f.endsWith(".sx") && f !== "test-framework.sx") {
|
if (f.startsWith("test-") && f.endsWith(".sx") && f !== "test-framework.sx") {
|
||||||
if (!fullBuild && requiresFull.has(f)) {
|
|
||||||
console.log(`Skipping ${f} (requires --full)`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
testFiles.push(path.join(specTests, f));
|
testFiles.push(path.join(specTests, f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Library tests (only with --full — require compiler, vm, signals, etc.)
|
||||||
|
if (fullBuild) {
|
||||||
|
for (const f of fs.readdirSync(libTests).sort()) {
|
||||||
|
if (f.startsWith("test-") && f.endsWith(".sx")) {
|
||||||
|
testFiles.push(path.join(libTests, f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run tests
|
// Run tests
|
||||||
|
|||||||
@@ -386,12 +386,13 @@ let () =
|
|||||||
in
|
in
|
||||||
let root = find_root (Sys.getcwd ()) in
|
let root = find_root (Sys.getcwd ()) in
|
||||||
let spec p = Filename.concat (Filename.concat root "spec") p 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 web p = Filename.concat (Filename.concat root "web") p in
|
||||||
|
|
||||||
let env = make_integration_env () in
|
let env = make_integration_env () in
|
||||||
|
|
||||||
(* Load spec + adapters *)
|
(* Load spec + lib + adapters *)
|
||||||
Printf.printf "Loading spec + adapters...\n%!";
|
Printf.printf "Loading spec + lib + adapters...\n%!";
|
||||||
let load path =
|
let load path =
|
||||||
if Sys.file_exists path then begin
|
if Sys.file_exists path then begin
|
||||||
let exprs = Sx_parser.parse_file path in
|
let exprs = Sx_parser.parse_file path in
|
||||||
@@ -405,6 +406,7 @@ let () =
|
|||||||
load (web "signals.sx");
|
load (web "signals.sx");
|
||||||
load (web "adapter-html.sx");
|
load (web "adapter-html.sx");
|
||||||
load (web "adapter-sx.sx");
|
load (web "adapter-sx.sx");
|
||||||
|
ignore lib; (* available for future library loading *)
|
||||||
|
|
||||||
(* Helper: render SX source string to HTML *)
|
(* Helper: render SX source string to HTML *)
|
||||||
let render_html src =
|
let render_html src =
|
||||||
|
|||||||
@@ -734,10 +734,11 @@ let run_spec_tests env test_files =
|
|||||||
Printf.printf "\nLoading test framework...\n%!";
|
Printf.printf "\nLoading test framework...\n%!";
|
||||||
load_and_eval framework_path;
|
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 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 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
|
let path = Filename.concat dir name in
|
||||||
if Sys.file_exists path then begin
|
if Sys.file_exists path then begin
|
||||||
Printf.printf "Loading %s...\n%!" name;
|
Printf.printf "Loading %s...\n%!" name;
|
||||||
@@ -746,36 +747,47 @@ let run_spec_tests env test_files =
|
|||||||
end
|
end
|
||||||
in
|
in
|
||||||
(* Render adapter for test-render-html.sx *)
|
(* Render adapter for test-render-html.sx *)
|
||||||
load_spec "render.sx" spec_dir;
|
load_module "render.sx" spec_dir;
|
||||||
load_spec "adapter-html.sx" web_dir;
|
load_module "adapter-html.sx" web_dir;
|
||||||
(* Compiler + VM for test-vm.sx *)
|
(* Library modules for lib/tests/ *)
|
||||||
load_spec "bytecode.sx" spec_dir;
|
load_module "bytecode.sx" lib_dir;
|
||||||
load_spec "compiler.sx" spec_dir;
|
load_module "compiler.sx" lib_dir;
|
||||||
load_spec "vm.sx" spec_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 files = if test_files = [] then begin
|
||||||
let entries = Sys.readdir spec_tests_dir in
|
(* Spec tests (core language — always run) *)
|
||||||
Array.sort String.compare entries;
|
let spec_entries = Sys.readdir spec_tests_dir in
|
||||||
let requires_full = ["test-continuations.sx"; "test-types.sx"; "test-freeze.sx";
|
Array.sort String.compare spec_entries;
|
||||||
"test-continuations-advanced.sx"; "test-signals-advanced.sx";
|
let spec_files = Array.to_list spec_entries
|
||||||
"test-vm.sx"] in
|
|
||||||
Array.to_list entries
|
|
||||||
|> List.filter (fun f ->
|
|> List.filter (fun f ->
|
||||||
String.length f > 5 &&
|
String.length f > 5 &&
|
||||||
String.sub f 0 5 = "test-" &&
|
String.sub f 0 5 = "test-" &&
|
||||||
Filename.check_suffix f ".sx" &&
|
Filename.check_suffix f ".sx" &&
|
||||||
f <> "test-framework.sx" &&
|
f <> "test-framework.sx")
|
||||||
not (List.mem f requires_full))
|
|> List.map (fun f -> Filename.concat spec_tests_dir f)
|
||||||
|
in
|
||||||
|
spec_files
|
||||||
end else
|
end else
|
||||||
|
(* Specific test files — search all test dirs *)
|
||||||
List.map (fun name ->
|
List.map (fun name ->
|
||||||
if Filename.check_suffix name ".sx" then name
|
let name = if Filename.check_suffix name ".sx" then name else name ^ ".sx" in
|
||||||
else name ^ ".sx") test_files
|
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
|
in
|
||||||
|
|
||||||
List.iter (fun name ->
|
List.iter (fun path ->
|
||||||
let path = Filename.concat spec_tests_dir name in
|
|
||||||
if Sys.file_exists path then begin
|
if Sys.file_exists path then begin
|
||||||
|
let name = Filename.basename path in
|
||||||
Printf.printf "\n%s\n" (String.make 60 '=');
|
Printf.printf "\n%s\n" (String.make 60 '=');
|
||||||
Printf.printf "Running %s\n" name;
|
Printf.printf "Running %s\n" name;
|
||||||
Printf.printf "%s\n%!" (String.make 60 '=');
|
Printf.printf "%s\n%!" (String.make 60 '=');
|
||||||
|
|||||||
@@ -1174,18 +1174,20 @@ let cli_load_files env files =
|
|||||||
let cli_mode mode =
|
let cli_mode mode =
|
||||||
let env = make_server_env () in
|
let env = make_server_env () in
|
||||||
(* Load spec + adapter files for aser modes *)
|
(* 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 web_base = try Sys.getenv "SX_WEB_DIR" with Not_found -> "web" in
|
||||||
let spec_files = [
|
let render_files = [
|
||||||
Filename.concat base "parser.sx";
|
Filename.concat spec_base "parser.sx";
|
||||||
Filename.concat base "render.sx";
|
Filename.concat spec_base "render.sx";
|
||||||
Filename.concat web_base "adapter-html.sx";
|
Filename.concat web_base "adapter-html.sx";
|
||||||
Filename.concat web_base "adapter-sx.sx";
|
Filename.concat web_base "adapter-sx.sx";
|
||||||
Filename.concat web_base "web-forms.sx";
|
Filename.concat web_base "web-forms.sx";
|
||||||
] in
|
] 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
|
(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 *)
|
(* Load any files passed via --load *)
|
||||||
let load_files = ref [] in
|
let load_files = ref [] in
|
||||||
let args = Array.to_list Sys.argv in
|
let args = Array.to_list Sys.argv in
|
||||||
@@ -1256,13 +1258,14 @@ let cli_mode mode =
|
|||||||
|
|
||||||
let test_mode () =
|
let test_mode () =
|
||||||
let env = make_server_env () in
|
let env = make_server_env () in
|
||||||
(* Load full spec + adapter stack *)
|
(* Load spec + lib + adapter stack *)
|
||||||
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 web_base = try Sys.getenv "SX_WEB_DIR" with Not_found -> "web" in
|
||||||
let files = [
|
let files = [
|
||||||
Filename.concat base "parser.sx";
|
Filename.concat spec_base "parser.sx";
|
||||||
Filename.concat base "render.sx";
|
Filename.concat spec_base "render.sx";
|
||||||
Filename.concat base "compiler.sx";
|
Filename.concat lib_base "compiler.sx";
|
||||||
Filename.concat web_base "signals.sx";
|
Filename.concat web_base "signals.sx";
|
||||||
Filename.concat web_base "adapter-html.sx";
|
Filename.concat web_base "adapter-html.sx";
|
||||||
Filename.concat web_base "adapter-sx.sx";
|
Filename.concat web_base "adapter-sx.sx";
|
||||||
|
|||||||
@@ -1448,6 +1448,7 @@ def compile_ref_to_py(
|
|||||||
_project = os.path.abspath(os.path.join(ref_dir, "..", "..", ".."))
|
_project = os.path.abspath(os.path.join(ref_dir, "..", "..", ".."))
|
||||||
_source_dirs = [
|
_source_dirs = [
|
||||||
os.path.join(_project, "spec"),
|
os.path.join(_project, "spec"),
|
||||||
|
os.path.join(_project, "lib"),
|
||||||
os.path.join(_project, "web"),
|
os.path.join(_project, "web"),
|
||||||
ref_dir,
|
ref_dir,
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
|
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
|
||||||
var SX_VERSION = "2026-03-24T22:31:01Z";
|
var SX_VERSION = "2026-03-24T22:56:21Z";
|
||||||
|
|
||||||
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
||||||
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
||||||
|
|||||||
@@ -367,17 +367,24 @@ class OcamlBridge:
|
|||||||
# Collect files to load
|
# Collect files to load
|
||||||
all_files: list[str] = []
|
all_files: list[str] = []
|
||||||
|
|
||||||
# Spec files needed by aser + bytecode compiler
|
# Core spec files
|
||||||
spec_dir = os.path.join(os.path.dirname(__file__), "../../spec")
|
spec_dir = os.path.join(os.path.dirname(__file__), "../../spec")
|
||||||
for spec_file in ["parser.sx", "render.sx", "bytecode.sx", "compiler.sx"]:
|
for spec_file in ["parser.sx", "render.sx"]:
|
||||||
path = os.path.normpath(os.path.join(spec_dir, spec_file))
|
path = os.path.normpath(os.path.join(spec_dir, spec_file))
|
||||||
if os.path.isfile(path):
|
if os.path.isfile(path):
|
||||||
all_files.append(path)
|
all_files.append(path)
|
||||||
|
|
||||||
|
# Library files (compiler, vm, freeze — written in the language)
|
||||||
|
lib_dir = os.path.join(os.path.dirname(__file__), "../../lib")
|
||||||
|
for lib_file in ["bytecode.sx", "compiler.sx"]:
|
||||||
|
path = os.path.normpath(os.path.join(lib_dir, lib_file))
|
||||||
|
if os.path.isfile(path):
|
||||||
|
all_files.append(path)
|
||||||
|
|
||||||
# All directories loaded into the Python env
|
# All directories loaded into the Python env
|
||||||
all_dirs = list(set(_watched_dirs) | _dirs_from_cache)
|
all_dirs = list(set(_watched_dirs) | _dirs_from_cache)
|
||||||
|
|
||||||
# Isomorphic libraries: signals, rendering, freeze scopes, web forms
|
# Isomorphic libraries: signals, rendering, web forms
|
||||||
web_dir = os.path.join(os.path.dirname(__file__), "../../web")
|
web_dir = os.path.join(os.path.dirname(__file__), "../../web")
|
||||||
if os.path.isdir(web_dir):
|
if os.path.isdir(web_dir):
|
||||||
for web_file in ["signals.sx", "adapter-html.sx", "adapter-sx.sx",
|
for web_file in ["signals.sx", "adapter-html.sx", "adapter-sx.sx",
|
||||||
@@ -385,9 +392,9 @@ class OcamlBridge:
|
|||||||
path = os.path.normpath(os.path.join(web_dir, web_file))
|
path = os.path.normpath(os.path.join(web_dir, web_file))
|
||||||
if os.path.isfile(path):
|
if os.path.isfile(path):
|
||||||
all_files.append(path)
|
all_files.append(path)
|
||||||
# Spec library files (loaded after adapters)
|
# Library files loaded after adapters (depend on scope primitives)
|
||||||
for spec_lib in ["freeze.sx"]:
|
for lib_file in ["freeze.sx"]:
|
||||||
path = os.path.normpath(os.path.join(spec_dir, spec_lib))
|
path = os.path.normpath(os.path.join(lib_dir, lib_file))
|
||||||
if os.path.isfile(path):
|
if os.path.isfile(path):
|
||||||
all_files.append(path)
|
all_files.append(path)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user