diff --git a/compile.ts b/compile.ts index 4df1177..db05759 100755 --- a/compile.ts +++ b/compile.ts @@ -1895,7 +1895,8 @@ class Compiler { } let outDefs = typeof info.out === "number" ? [info.out] : info.out; outDefs?.forEach((v, i) => { - args[v] = outs[i] || nilReg; + // First out is reserved for control value if executing branching instructions that opts into it + args[v] = outs[info.firstArgControlFlow ? i + 1 : i] || nilReg; }); if (info.exec != null) { @@ -2344,14 +2345,23 @@ class Compiler { ); } }); - - if (decl.initializer && ts.isCallExpression(decl.initializer)) { - return this.compileCall(decl.initializer, outs); - } else { - this.#error( - "only call expression are valid for array initializer", - decl, - ); + if (decl.initializer) { + if (ts.isCallExpression(decl.initializer)) { + return this.compileCall(decl.initializer, outs); + } else if (ts.isPropertyAccessExpression(decl.initializer)) { + return this.compileResolvedCall( + decl, + decl.initializer.name.text, + decl.initializer.expression, + [], + outs, + ); + } else { + this.#error( + "only call expression are valid for array initializer", + decl, + ); + } } } else { this.#error("Unable to bind object", decl); diff --git a/scripts/geninstr.ts b/scripts/geninstr.ts index 5cd2f16..47ecf77 100644 --- a/scripts/geninstr.ts +++ b/scripts/geninstr.ts @@ -78,6 +78,7 @@ interface GenInfo { inArgs: [number, ...ArgInfo][]; outArgs: [number, ...ArgInfo][]; execArgs: [number, ...ArgInfo][]; + firstArgControlFlow?: boolean; } interface CompileInfo { @@ -91,6 +92,7 @@ interface CompileInfo { special?: "txt" | "bp"; c?: number; bp?: boolean; + firstArgControlFlow?: boolean; } const instructions = gameData.instructions as unknown as { @@ -232,6 +234,9 @@ function generateCompile(genInfo: GenInfo) { if (genInfo.bp) { info.bp = genInfo.bp; } + if (genInfo.firstArgControlFlow) { + info.firstArgControlFlow = true; + } compileInfos[genInfo.js] = info; } @@ -353,21 +358,30 @@ ${indent}`; } function makeConditionType(genInfo: GenInfo, returnType: string): string { - if (genInfo.outArgs.length > 0) { - return `${returnType} | undefined`; - } const values = [...Object.values(genInfo.conditions!)]; + let conditionType: string; if (values.every((v) => typeof v == "boolean")) { - return "boolean"; + conditionType = "boolean"; + } else { + conditionType = values + .filter((v) => typeof v === "string") + .map((v) => `"${v}"`) + .join(" | "); + if (values.some((v) => typeof v !== "string")) { + conditionType = `${conditionType} | undefined`; + } } - returnType = values - .filter((v) => typeof v === "string") - .map((v) => `"${v}"`) - .join(" | "); - if (values.some((v) => typeof v !== "string")) { - return `${returnType} | undefined`; + + if (genInfo.outArgs.length > 0) { + if (genInfo.firstArgControlFlow) { + returnType = returnType.replace(/^\[|\]$/g, ""); + return `[${conditionType}, ${returnType}]`; + } else { + return `${returnType} | undefined`; + } + } else { + return conditionType; } - return returnType; } function uniqify(params: ParamInfo[]) { @@ -427,6 +441,7 @@ fs.writeFileSync( c?: number; sub?: string; bp?: boolean; + firstArgControlFlow?: boolean; } export const methods: { [key: string]: MethodInfo } = ${JSON.stringify( compileInfos, @@ -739,6 +754,7 @@ interface InstrInfo { outArgs?: number[]; execArgs?: number[]; optional?: number; + firstArgControlFlow?: boolean; } export const instructions:{[key:string]:InstrInfo} = ${JSON.stringify( decompileInfos, diff --git a/scripts/overrides.json b/scripts/overrides.json index 4705b0b..da651ca 100644 --- a/scripts/overrides.json +++ b/scripts/overrides.json @@ -57,6 +57,11 @@ "B": false }, "outArgs": [] + }, + { + "js": "selectNearest", + "type": "function", + "firstArgControlFlow": true } ], "type": "operator" diff --git a/tests/__snapshots__/compile.test.ts.snap b/tests/__snapshots__/compile.test.ts.snap index 51479bc..564c336 100644 --- a/tests/__snapshots__/compile.test.ts.snap +++ b/tests/__snapshots__/compile.test.ts.snap @@ -134,6 +134,25 @@ exports[`call_with_computation.ts 1`] = ` .ret " `; +exports[`first_arg_control_flow.ts 1`] = ` +"foo: + .name "foo" + .pname p1, "v" + select_nearest :l1, :l2, p1, signal, A + jump :l3 +l1: + notify A, $txt="A is closest" + jump :l0 +l2: + notify A, $txt="B is closest" + jump :l0 +l3: + notify $txt="Default branch" + jump :l0 +l0: + .ret " +`; + exports[`if_unit_type.ts 1`] = ` "test: .name "test" diff --git a/tests/first_arg_control_flow.ts b/tests/first_arg_control_flow.ts new file mode 100644 index 0000000..2faf214 --- /dev/null +++ b/tests/first_arg_control_flow.ts @@ -0,0 +1,14 @@ +export function foo(v: Value) { + let [branch, nearest] = selectNearest(v, signal); + switch (branch) { + case "A": + notify("A is closest", nearest); + break; + case "B": + notify("B is closest", nearest); + break; + default: + notify("Default branch"); + break; + } +}