fix(coding-agent): rewrite trailing return statement into final expression

A top-level `return value;` in a JS eval cell was previously swallowed:
returnFinalExpression only handled ExpressionStatement, so ReturnStatement
flipped the IIFE wrapper which discarded the value. Rewrite the trailing
return into __omp_set_final_expr__((expr)) so the existing
final-expression channel surfaces the value just like a trailing
expression.
This commit is contained in:
can1357
2026-05-19 19:16:08 +09:00
parent 9a335ece68
commit 7aef1f1cd5
2 changed files with 23 additions and 10 deletions
@@ -303,15 +303,27 @@ function returnFinalExpression(code: string): { source: string; returned: boolea
let lastIndex = body.length - 1;
while (lastIndex >= 0 && body[lastIndex]?.type === "EmptyStatement") lastIndex--;
const last = lastIndex >= 0 ? body[lastIndex] : undefined;
if (last?.type !== "ExpressionStatement") return { source: code, returned: false };
const expression = last as BabelExpressionStatement;
const prefix = code.slice(0, expression.start);
const statement = code.slice(expression.start, expression.end);
const suffix = code.slice(expression.end);
const semicolonMatch = statement.match(/;\s*$/);
const trimmedStatement = semicolonMatch ? statement.slice(0, semicolonMatch.index) : statement;
return { source: `${prefix}__omp_set_final_expr__((${trimmedStatement}));${suffix}`, returned: true };
if (last?.type === "ExpressionStatement") {
const expression = last as BabelExpressionStatement;
const prefix = code.slice(0, expression.start);
const statement = code.slice(expression.start, expression.end);
const suffix = code.slice(expression.end);
const semicolonMatch = statement.match(/;\s*$/);
const trimmedStatement = semicolonMatch ? statement.slice(0, semicolonMatch.index) : statement;
return { source: `${prefix}__omp_set_final_expr__((${trimmedStatement}));${suffix}`, returned: true };
}
if (last?.type === "ReturnStatement") {
// Top-level `return value;` is otherwise swallowed: it forces the cell into an async IIFE
// wrapper that discards the returned value. Rewrite into `__omp_set_final_expr__((expr))`
// so the runtime can surface the value to the caller just like a trailing expression.
const ret = last as unknown as { start: number; end: number; argument?: { start: number; end: number } | null };
if (!ret.argument) return { source: code, returned: false };
const prefix = code.slice(0, ret.start);
const suffix = code.slice(ret.end);
const expr = code.slice(ret.argument.start, ret.argument.end);
return { source: `${prefix}__omp_set_final_expr__((${expr}));${suffix}`, returned: true };
}
return { source: code, returned: false };
}
function isExecutionBoundary(type: string): boolean {
@@ -165,7 +165,8 @@ export class JsRuntime {
const finalValue = this.#finalExpressionValue;
this.#finalExpressionSet = false;
this.#finalExpressionValue = undefined;
return await awaitMaybePromise(finalValue);
const resolved = await awaitMaybePromise(finalValue);
return resolved;
}
return awaited;
}