Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/codegen/expressions/calls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1170,6 +1170,20 @@ export class CallExpressionGenerator {
return coerced;
}

// FFI null-string coercion: `declare function f(): string` returning NULL
// from C should round-trip to TS as the empty string so `result === ""`
// works reliably. Only applied to user-declared extern functions (not
// internal runtime calls, which rely on NULL sentinels internally).
if (returnType === "i8*" && func && func.declare) {
const emptyStr = this.ctx.stringGen.doCreateStringConstant("");
const isNull = this.ctx.nextTemp();
this.ctx.emit(`${isNull} = icmp eq i8* ${temp}, null`);
const coerced = this.ctx.nextTemp();
this.ctx.emit(`${coerced} = select i1 ${isNull}, i8* ${emptyStr}, i8* ${temp}`);
this.ctx.setVariableType(coerced, "i8*");
return coerced;
}

return temp;
}

Expand Down
3 changes: 3 additions & 0 deletions src/codegen/infrastructure/assignment-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,9 @@ export class AssignmentGenerator {
value: string,
memberAccessValue: MemberAccessAssignmentNode,
): void {
if (value.startsWith("__lambda_")) {
value = `@${value}`;
}
if (fiTsType) {
const enumResult = this.isEnumType(fiTsType);
if (enumResult) {
Expand Down
3 changes: 2 additions & 1 deletion src/parser-ts/handlers/expressions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,8 @@ function transformCallExpression(
};
} else if (
ts.isCallExpression(node.expression) ||
ts.isParenthesizedExpression(node.expression)
ts.isParenthesizedExpression(node.expression) ||
ts.isElementAccessExpression(node.expression)
) {
const callee = transformExpression(node.expression, checker);
return {
Expand Down
12 changes: 12 additions & 0 deletions tests/fixtures/classes/class-arrow-field-in-ctor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// @test-description: issue #587 — arrow literal assigned to class field inside ctor body
class Foo {
cb: (x: number) => number;
constructor() {
this.cb = (x) => x * 2;
}
}

const f = new Foo();
if (f.cb(21) === 42) {
console.log("TEST_PASSED");
}
12 changes: 12 additions & 0 deletions tests/fixtures/edge-cases/call-element-access-callee.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// @test-description: issue #589 — parser accepts arr[i](args) as a call expression (ElementAccessExpression callee)
// @test-compile-error: Immediately invoked function expressions
function doubler(x: number): number {
return x * 2;
}
function plusOne(x: number): number {
return x + 1;
}

const fns = [doubler, plusOne];
const a = fns[0](10);
console.log(a);
9 changes: 9 additions & 0 deletions tests/fixtures/edge-cases/ffi-null-string-to-empty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// @test-description: issue #591 — NULL char* from FFI round-trips to TS as empty string
declare function getenv(name: string): string;

const v = getenv("__CHADSCRIPT_TEST_VAR_THAT_DOES_NOT_EXIST_91237__");
if (v === "") {
console.log("TEST_PASSED");
} else {
console.log("FAIL: got " + v);
}
Loading