Files
scriptc/tests/corpus/logical-assignment-values.ts
Chris Tate b40a6f6079 feat(compiler): lower frontend collections and string transforms natively
- Keep generic bindings and short-circuit writes scoped to their native execution context.
- Compile Map and Set copies, tuple callbacks and searches, and string-pattern replacement.
- Exercise production frontend registries without Node and preserve mutation, identity, and evaluation order.
2026-09-28 14:38:05 -05:00

97 lines
3.2 KiB
TypeScript

export {};
let effects = "";
function rhs(value: number): number { effects += "R"; return value; }
let number = 0;
console.log(number &&= rhs(1), number, effects);
console.log(number ||= rhs(2), number, effects);
console.log(number ||= rhs(3), number, effects);
console.log(number &&= rhs(4), number, effects);
number = NaN;
console.log(number ||= rhs(5), number, effects);
number = -0;
console.log(number &&= rhs(6), Object.is(number, -0), effects);
let text = "";
console.log(text ||= "filled", text);
console.log(text &&= "changed", text);
let flag = false;
console.log(flag &&= true, flag);
console.log(flag ||= true, flag);
console.log(flag &&= false, flag);
function optional(value: string | undefined): string | undefined {
value &&= "changed";
console.log("and", value);
value ||= "default";
return value;
}
console.log(optional(undefined), optional(""), optional("present"));
// Evaluation of the reference precedes its single read. The setter runs
// only when the selected branch actually assigns, and the result is the
// RHS value even when the setter stores a different value.
class Cell {
stored = 0;
get value(): number { effects += "G"; return this.stored; }
set value(value: number) { effects += "S"; this.stored = value + 10; }
}
const cell = new Cell();
function receiver(): Cell { effects += "O"; return cell; }
effects = "";
console.log(receiver().value &&= rhs(1), cell.stored, effects);
effects = "";
console.log(receiver().value ||= rhs(2), cell.stored, effects);
effects = "";
console.log(receiver().value ||= rhs(3), cell.stored, effects);
effects = "";
console.log(receiver().value &&= rhs(4), cell.stored, effects);
const values = [0, 2];
function array(): number[] { effects += "A"; return values; }
function key(value: number): number { effects += "K"; return value; }
effects = "";
console.log(array()[key(0)] ||= rhs(7), values[0], effects);
effects = "";
console.log(array()[key(1)] &&= rhs(8), values[1], effects);
effects = "";
console.log(array()[key(9)] &&= rhs(9), values.length, effects);
effects = "";
console.log(array()[key(9)] ||= rhs(10), values.length, effects);
// The receiver remains the one evaluated before the RHS changes its alias.
let active = [0];
const original = active;
function replace(): number { active = [20]; return 30; }
console.log(active[0] ||= replace(), original[0], active[0]);
function captured(): void {
let value = "";
const fill = (): string => value ||= "capture";
console.log(fill(), fill(), value);
}
captured();
function fail(): number { effects += "T"; throw new Error("rhs"); }
let preserved = 0;
effects = "";
try { preserved ||= fail(); }
catch (error) { if (error instanceof Error) console.log(error.message); }
console.log(preserved, effects);
preserved = 2;
effects = "";
console.log(preserved ||= fail(), effects);
// A forward captured binding still checks TDZ before deciding whether to
// evaluate the RHS. Neither logical operator can initialize its empty box.
function forward(): void {
const write = (): void => { value ||= rhs(40); };
effects = "";
try { write(); }
catch (error) { if (error instanceof Error) console.log(error.name, effects); }
let value = 0;
write();
console.log(value, effects);
}
forward();