Files
scriptc/tests/corpus/native-method-values.js
T
Chris Tate 7d5a471c67 Compile renderer values and callbacks natively
- Preserve unbound class methods, call-time receivers, and bound callback arguments.
- Keep native factory results, fallback functions, and mutable JavaScript renderer state intact.
- Support live Error.cause assignment, deletion, and property descriptors across aliases.
2026-09-28 13:54:28 -05:00

92 lines
3.7 KiB
JavaScript

class Parser {
value = 3;
options = this.setOptions;
setOptions(value) { this.value = value; return this; }
otherOptions(value) { this.value = value + 10; return this; }
constant() { return 12; }
describe(prefix = "parser") { return `${prefix}:${this.value}`; }
countArgs(first) { return arguments.length; }
join(prefix, ...parts) { return prefix + parts.join(":"); }
fail() { throw new Error("method failed"); }
}
const parser = new Parser();
console.log(parser.options(4) === parser, parser.value);
const second = new Parser();
second.options = parser.options;
console.log(second.options(7) === second, second.value, parser.value);
console.log(parser.options === parser.setOptions, parser.options === second.options);
const detached = parser.options;
try { detached(5); } catch (error) { console.log(error.name); }
const constant = parser.constant;
console.log(constant());
function call(method, receiver, ...args) { return method.apply(receiver, args); }
console.log(call(parser.describe, second), call(parser.describe, second, "other"));
console.log(call(parser.countArgs, undefined, 1, 2, 3), call(parser.join, parser, "parts:", 1, "two"));
try { call(parser.fail, second); } catch (error) { console.log(error.message); }
console.log(call(parser.describe, parser));
console.log(parser.describe.call(second, "called"));
console.log(parser.describe.apply(second, ["applied"]));
const bound = parser.describe.bind(second, "bound");
console.log(bound(), bound.call(parser), bound.bind(parser)());
const restBound = parser.join.bind(parser, "bound:", 1);
console.log(restBound("two", 3));
try { parser.fail.bind(parser)(); } catch (error) { console.log(error.message); }
console.log(bound());
function bindAgain(method, receiver) { return method.bind(receiver, "indirect"); }
console.log(bindAgain(parser.describe, second)());
let effects = "";
function receiver() { effects += "receiver;"; return parser; }
function argument() { effects += "argument;"; parser.options = second.otherOptions; return 9; }
console.log(receiver().options(argument()) === parser, effects, parser.value);
const dynamic = { first: 17, method: function() { return this.first; }, nested: function() { return detached(1); } };
function invoke(object) { return object.method(); }
console.log(invoke(dynamic));
try { dynamic.nested(); } catch (error) { console.log(error.name); }
console.log(invoke(dynamic));
class Base {
value = 10;
method() { return `base:${this.value}`; }
inherited() { return this.value; }
}
class Derived extends Base {
method() { return `derived:${this.value}`; }
}
class Further extends Derived {
method() { return `further:${this.value}`; }
}
/** @type {Base} */
const baseView = new Derived();
const derived = new Derived();
const base = new Base();
const selected = baseView.method;
console.log(selected === derived.method, selected === base.method);
console.log(call(selected, derived), call(base.method, derived), call(baseView.inherited, derived));
const further = new Further();
console.log(call(selected, further), further.method());
class Left {
value = "left";
leftOnly = true;
/** @type {*} */
callback;
read(suffix) { return this.value + suffix; }
constructor() { this.callback = this.read; }
}
class Right {
value = "right";
rightOnly = true;
/** @type {*} */
callback;
read(suffix) { return this.value + suffix; }
constructor() { this.callback = this.read; }
}
const left = new Left();
const right = new Right();
let selectedCalls = 0;
function select(rightArm) { selectedCalls++; return rightArm ? right : left; }
function replace() { left.callback = () => "replacement"; return "!"; }
console.log(select(false).callback(replace()), selectedCalls);
console.log(select(true).callback("?"), selectedCalls);
console.log(select(false).callback("ignored"), selectedCalls);