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
68 changes: 68 additions & 0 deletions src/reflect/resources/typeregistry.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,78 @@ export class TypeEntry {
*/
info

/**
* @private
* @type {Map<string, MethodEntry>}
*/
methods = new Map()

/**
* @param {TypeInfo} info
*/
constructor(info) {
this.info = info
}

/**
* @template {unknown[]} T
* @param {string} name
* @param {[...T]} args
* @returns {unknown}
*/
call(name, args) {
const method = this.getMethod(name)

if (method) {
return method.call(args)
}

return undefined

}

/**
* @param {string} name
*/
getMethod(name) {
return this.methods.get(name)
}

/**
* @param {Function} method
*/
setMethod(method) {
this.methods.set(method.name, new MethodEntry(method))
}

/**
* @returns {ReadonlyMap<string, readonly MethodEntry>}
*/
getMethods() {
return this.methods
}
}

export class MethodEntry {

/**
* @type {Function}
*/
method

/**
* @param {Function} method
*/
constructor(method) {
this.method = method
}

/**
* @template {unknown[]} T
* @param {[...T]} [args]
* @returns {unknown}
*/
call(args) {
return this.method(...(args || []))
}
}
7 changes: 6 additions & 1 deletion src/reflect/systems/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
TupleInfo,
TypeInfo
} from '../core/index.js'
import { TypeEntry, TypeRegistry } from '../resources/index.js'
import { MethodEntry, TypeEntry, TypeRegistry } from '../resources/index.js'

/**
* @param {World} world
Expand Down Expand Up @@ -47,11 +47,13 @@ export function registerReflectTypes(world) {
const typeIdArrayId = setTypeId('Array<TypeId>')
const fieldArrayId = typeidGeneric(Array, [Field])
const typeEntryMapId = setTypeId('Map<TypeId,TypeEntry>')
const methodEntryMapId = setTypeId(`Map<TypeId,${MethodEntry.name}>`)

registry.registerTypeId(mapStringNumberId, new MapInfo(typeid(String), typeid(Number)))
registry.registerTypeId(typeIdArrayId, new ArrayInfo(typeIdId))
registry.registerTypeId(fieldArrayId, new ArrayInfo(typeid(Field)))
registry.registerTypeId(typeEntryMapId, new MapInfo(typeIdId, typeid(TypeEntry)))
registry.registerTypeId(methodEntryMapId, new MapInfo(typeIdId, typeid(MethodEntry)))

registry.register(TypeInfo, new OpaqueInfo())
registry.register(Field, new StructInfo({
Expand Down Expand Up @@ -83,6 +85,9 @@ export function registerReflectTypes(world) {
registry.register(TupleInfo, new StructInfo({
elementTypes: new Field(typeIdArrayId)
}))
registry.register(MethodEntry, new StructInfo({
method: new Field(typeid(Function))
}))
registry.register(TypeEntry, new StructInfo({
info: new Field(typeid(TypeInfo))
}))
Expand Down
72 changes: 72 additions & 0 deletions src/reflect/tests/typeentry.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { test, describe } from "node:test";
import { strictEqual } from "node:assert";
import { StructInfo } from "../core/index.js";
import { MethodEntry, TypeEntry } from "../resources/index.js";

describe("Testing `TypeEntry` method registry", () => {
test("`TypeEntry` can set and get methods", () => {
/**
* @param {number} a
* @param {number} b
*/
function add(a, b) {
return a + b;
}

const entry = new TypeEntry(StructInfo.default());
entry.setMethod(add);

const method = entry.getMethod("add");
strictEqual(method instanceof MethodEntry, true);
strictEqual(method?.call([2, 3]), 5);
});

test("`TypeEntry` can call methods by name", () => {
/**
* @param {number} a
* @param {number} b
*/
function multiply(a, b) {
return a * b;
}

const entry = new TypeEntry(StructInfo.default());
entry.setMethod(multiply);

strictEqual(entry.call("multiply", [4, 5]), 20);
});

test("`TypeEntry` can return all methods", () => {
/**
* @param {number} a
* @param {number} b
*/
function add(a, b) {
return a + b;
}

/**
* @param {number} a
* @param {number} b
*/
function multiply(a, b) {
return a + b;
}

const entry = new TypeEntry(StructInfo.default());
entry.setMethod(add);
entry.setMethod(multiply);

const methods = entry.getMethods();
strictEqual(methods.size, 2);
strictEqual(methods.get("add") instanceof MethodEntry, true);
strictEqual(methods.get("multiply") instanceof MethodEntry, true);
});

test("`TypeEntry` returns undefined for missing methods", () => {
const entry = new TypeEntry(StructInfo.default());

strictEqual(entry.call("missing", [1]), undefined);
strictEqual(entry.getMethod("missing"), undefined);
});
});
Loading