done with this theming stuff for now.

This commit is contained in:
ed
2026-08-15 01:15:43 -04:00
parent d23b6a2a36
commit 1a5b618484
10 changed files with 290 additions and 69 deletions
+38 -3
View File
@@ -45,7 +45,7 @@ test("classifyDocument separates CPU, GTE, GPU, and component domains", () => {
workspace.macros.set("load_word", "cpu");
workspace.macros.set("gte_cmdw_rtpt", "gte");
workspace.macros.set("gp1_word_DisplayOn", "gpu");
workspace.macros.set("mac_yield", "component");
workspace.macros.set("mac_yield", "control");
workspace.componentAliases.add("mac_yield");
const source = "load_word(R_T0, R_T1, 0), gte_cmdw_rtpt, gp1_word_DisplayOn(), mac_yield(), C2_MAC0, gte_cr_OFX_Code";
@@ -54,20 +54,55 @@ test("classifyDocument separates CPU, GTE, GPU, and component domains", () => {
assert.equal(byText(result, "load_word")[0].type, "tapeCpuInstruction");
assert.equal(byText(result, "gte_cmdw_rtpt")[0].type, "tapeGteInstruction");
assert.equal(byText(result, "gp1_word_DisplayOn")[0].type, "tapeGpuInstruction");
assert.equal(byText(result, "mac_yield")[0].type, "tapeComponentInstruction");
assert.equal(byText(result, "mac_yield")[0].type, "tapeControlFlow");
assert.equal(byText(result, "C2_MAC0")[0].type, "tapeCop2Register");
assert.equal(byText(result, "gte_cr_OFX_Code")[0].type, "tapeCop2Register");
});
test("component invocations keep the domain resolved from their emitted instructions", () => {
const workspace = createIndex();
workspace.macros.set("mac_load_word_imm", "cpu");
workspace.macros.set("mac_gcmd_push", "gpu");
workspace.macros.set("mac_gte_store_f3", "gte");
workspace.macros.set("mac_load_v3s4", "cpu");
const source = "mac_load_word_imm(dst, imm), mac_gcmd_push(cmd), mac_gte_store_f3(cursor), mac_load_v3s4()";
const result = classifyDocument(source, "C:/x/code/hello_camera/hello_camera.atom.c", workspace);
assert.equal(byText(result, "mac_load_word_imm")[0].type, "tapeCpuInstruction");
assert.equal(byText(result, "mac_gcmd_push")[0].type, "tapeGpuInstruction");
assert.equal(byText(result, "mac_gte_store_f3")[0].type, "tapeGteInstruction");
assert.equal(byText(result, "mac_load_v3s4")[0].type, "tapeCpuInstruction");
});
test("utility macros without a hardware domain use the standard macro token", () => {
const workspace = createIndex();
workspace.macros.set("load_word", "cpu");
workspace.macros.set("assert", "utility");
workspace.macros.set("stringify", "utility");
workspace.macros.set("u4_hi", "utility");
const source = "load_word(R_T0, R_T1, 0), assert(ok), stringify(name), u4_hi(imm)";
const result = classifyDocument(source, "C:/x/code/hello_camera/hello_camera.c", workspace);
assert.equal(byText(result, "load_word")[0].type, "tapeCpuInstruction");
assert.equal(byText(result, "assert")[0].type, "macro");
assert.equal(byText(result, "stringify")[0].type, "macro");
assert.equal(byText(result, "u4_hi")[0].type, "macro");
});
test("document-local declarations override an empty workspace index", () => {
const source = [
"MipsAtomComp_(ac_new_component) { nop };",
"MipsAtomComp_Proc_(ab, { nop })",
"mac_new_component(),",
].join("\n");
const result = classifyDocument(source, "C:/x/code/duffle/math.atom.c", createIndex());
assert.equal(byText(result, "MipsAtomComp_")[0].type, "keyword");
assert.equal(byText(result, "MipsAtomComp_Proc_")[0].type, "keyword");
assert.equal(byText(result, "ac_new_component")[0].type, "tapeComponentName");
assert.equal(byText(result, "mac_new_component")[0].type, "tapeCpuInstruction");
assert.equal(byText(result, "mac_new_component")[0].type, "tapeComponentInstruction");
});
test("classifier returns ordered non-overlapping spans and partial malformed output", () => {
+1 -1
View File
@@ -57,7 +57,7 @@ test("every semantic token has a scope mapping; DSL-specific tokens also have gr
const grammarScopes = collectScopeNames(grammar);
const grammarRequired = new Set([
"tapeAtomKeyword", "tapeAtomName", "tapeComponentKeyword", "tapeComponentName",
"tapeAtomKeyword", "tapeAtomName", "tapeComponentName",
"tapeAnnotation", "tapeBindType", "tapePhase", "tapeLabel",
"tapeDelaySlot", "tapeDuffleType", "keyword",
]);
+60 -3
View File
@@ -26,7 +26,8 @@ test("scanSource discovers current atom and component forms", () => {
assert.equal(result.index.components.has("ac_store_pair"), true);
assert.equal(result.index.componentAliases.has("mac_load_pair"), true);
assert.equal(result.index.componentAliases.has("mac_store_pair"), true);
assert.equal(result.index.macros.get("mac_store_pair"), "cpu");
assert.equal(result.index.macros.get("mac_store_pair"), "component");
assert.equal(result.index.componentCallees.get("mac_store_pair").includes("store_word"), true);
assert.equal(result.index.phases.has("cube_g4"), true);
assert.equal(result.index.registers.get("R_PrimCursor"), "gpr");
assert.deepEqual(result.errors, []);
@@ -58,12 +59,68 @@ test("scanSource discovers binds, labels, registers, typedefs, and macro domains
});
test("domainFromPath uses the declaration file rather than parent directory names", () => {
assert.equal(domainFromPath("C:/x/code/hello_gte/hello_gte.atom.c"), "component");
assert.equal(domainFromPath("C:/x/code/hello_gte/hello_gte.atom.c"), null);
assert.equal(domainFromPath("C:/x/code/duffle/mips.h"), "cpu");
assert.equal(domainFromPath("C:/x/code/duffle/gte.atom.c"), "gte");
assert.equal(domainFromPath("C:/x/code/duffle/gte.h"), "gte");
assert.equal(domainFromPath("C:/x/code/duffle/gp.h"), "gpu");
});
test("component aliases inherit the domain of the instructions they emit", () => {
const headers = mergeIndexes(
scanSource("#define load_word(a,b,c) 1\n#define store_word(a,b,c) 1\n#define shift_aright_var(a,b,c) 1\n#define jump_reg(rd) 1\n", "C:/x/code/duffle/mips.h").index,
scanSource("#define gte_sw(rt, base, off) 1\n", "C:/x/code/duffle/gte.h").index
);
const math = scanSource(
[
"MipsAtomComp_(ac_load_v3s4) { load_word(R_T0, R_T1, 0) };",
"#define mac_load_p3s4 mac_load_v3s4",
].join("\n"),
"C:/x/code/duffle/math.atom.c"
);
const shift = scanSource(
"MipsAtomComp_(ac_shift_aright_var_v3_self) { shift_aright_var(R_T0, R_T0, R_T1) };",
"C:/x/code/duffle/gte.atom.c"
);
const gte = scanSource(
"MipsAtomComp_(ac_gte_store_f3) { gte_sw(C2_SXY0, R_T0, 0) };",
"C:/x/code/duffle/gte.atom.c"
);
const yieldAtom = scanSource(
"MipsAtomComp_(ac_yield) { load_word(R_AtomJmp, R_TapePtr, 0), jump_reg(R_AtomJmp), nop };",
"C:/x/code/duffle/lottes_tape.h"
);
const merged = mergeIndexes(headers, math.index, shift.index, gte.index, yieldAtom.index);
assert.equal(merged.macros.get("mac_load_v3s4"), "cpu");
assert.equal(merged.macros.get("mac_load_p3s4"), "cpu");
assert.equal(merged.macros.get("mac_shift_aright_var_v3_self"), "cpu");
assert.equal(merged.macros.get("mac_gte_store_f3"), "gte");
assert.equal(merged.macros.get("mac_yield"), "control");
});
test("scanSource tags utility header defines as utility, not a hardware domain", () => {
const source = [
"#define assert(cond) ((void)(cond))",
"#define stringify(name) #name",
"#define u4_hi(imm) ((imm) >> 16)",
].join("\n");
const result = scanSource(source, "C:/projects/Pikuma/ps1/code/duffle/dsl.h");
assert.equal(result.index.macros.get("assert"), "utility");
assert.equal(result.index.macros.get("stringify"), "utility");
assert.equal(result.index.macros.get("u4_hi"), "utility");
});
test("mergeIndexes prefers a hardware domain over a later utility define", () => {
const left = createIndex();
left.macros.set("sub_s", "utility");
const right = createIndex();
right.macros.set("sub_s", "cpu");
assert.equal(mergeIndexes(left, right).macros.get("sub_s"), "cpu");
assert.equal(mergeIndexes(right, left).macros.get("sub_s"), "cpu");
});
test("mergeIndexes preserves domain-specific aliases", () => {
const left = createIndex();
left.macros.set("load_word", "cpu");