Files
Chris Tate f818e8fb89 Extend static three.js support to raycasting
- Compile mesh, line, and point picking with perspective and orthographic camera rays.
- Preserve JavaScript override arguments, array identity, and native subclass values across checked calls.
- Specialize package class helpers and handle unsupported JSDoc namepaths.
2026-09-30 00:35:35 -05:00

86 lines
3.1 KiB
JavaScript

import { Base as ImportedBase, ArityBase, arityCounts } from "./base.js";
class Middle extends ImportedBase {}
class Derived extends Middle {
render(value) { console.log("derived", value); }
}
const Expression = class extends ImportedBase {
render(value) { console.log("expression", value); }
};
class Leaf extends Derived {
render(value) { super.render(value); console.log("leaf", value); }
}
function dispatch(receiver, value) { receiver.render(value); }
// An unrelated method with the same name still specializes its argument.
class Standalone {
render(point) { console.log("standalone", point.x + point.y); }
}
class Short extends ArityBase {
render(value) { console.log("short", value); }
defaulted(value) { console.log("short default", value); }
forward(value) { this.render(value); }
}
class Empty extends Short {
render() { console.log("empty"); }
}
class LongAgain extends Short {
render(value, time) { super.render(value); console.log("long again", value, time); }
}
export function exercise() {
new ImportedBase().dispatch("base call");
new Derived().dispatch(7);
new Leaf().dispatch("leaf call");
new Expression().dispatch("expression call");
dispatch(new Derived(), "helper call");
new Standalone().render({ x: 2, y: 3 });
new ArityBase().dispatch("base");
new Short().dispatch("short");
new Empty().dispatch("empty");
new LongAgain().dispatch("long");
new Short().render("direct");
new Empty().render();
new LongAgain().render("direct", 9);
new LongAgain().forward("omitted");
new ArityBase().dispatchDefault("base");
new Short().dispatchDefault("derived");
new Short().defaulted("direct");
arityCounts();
}
class Pair {
constructor(x, y) { this.x = x; this.y = y; }
/** @param {Pair} other */
add(other) { this.x += other.x; this.y += other.y; return this; }
}
class Triple {
constructor(x, y, z) { this.x = x; this.y = y; this.z = z; }
}
class Helpers {
/** @param {Pair} target @param {Pair} other @returns {Pair} */
static combine(target, other) { target.x += other.x; target.y += other.y; return target; }
}
class InheritedHelpers extends Helpers {}
class OverriddenHelpers extends Helpers {
static combine(target, other) { target.x -= other.x; target.y -= other.y; return target; }
}
export function structuralMethods() {
const pair = new Pair(1, 2);
const triple = new Triple(3, 4, 5);
console.log('instance', pair.add(triple) === pair, pair.x, pair.y);
console.log('static', Helpers.combine(triple, pair) === triple, triple.x, triple.y, triple.z);
console.log('inherited', InheritedHelpers.combine(triple, pair) === triple, triple.x);
console.log('overridden', OverriddenHelpers.combine(triple, pair) === triple, triple.x);
const combine = Helpers.combine;
console.log('static value', combine(pair, pair) === pair, pair.x, pair.y);
const add = pair.add;
try { add(pair); } catch (error) { console.log('unbound', error instanceof TypeError); }
const rows = [triple, new Triple(1, 0, 0)];
function compare(a, b) { return a.x - b.x; }
console.log('sort', rows.sort(compare) === rows, rows[0].x, rows[1].x);
}