Compare commits

..

No commits in common. "dispatcher_refactor" and "main" have entirely different histories.

9 changed files with 52 additions and 159 deletions

View File

@ -1,9 +1,6 @@
import * as Complex from './native.js' import * as Complex from './native.js'
import * as complex from './arithmetic.js' import * as complex from './arithmetic.js'
import {$$typeMetadata} from 'ts-macros'
export { complex } export { complex }
export {Complex} export {Complex}
const tryit = $$typeMetadata!<typeof complex>(true, true)

View File

@ -2,7 +2,7 @@ import {Complex} from './type.js'
import type { import type {
Dependencies, Signature, Returns, RealType, AliasOf Dependencies, Signature, Returns, RealType, AliasOf
} from '../interfaces/type.js' } from '../interfaces/type.js'
import {$reflectGen, GENERIC} from '../interfaces/type.js' import {$reflect} from '../interfaces/type.js'
declare module "../interfaces/type" { declare module "../interfaces/type" {
interface Signatures<T> { interface Signatures<T> {
@ -98,11 +98,7 @@ export const sqrt =
return dep.divideReal(num, denom) return dep.divideReal(num, denom)
} }
export interface GenericImplementations<T> { $reflect!([
kilroy: "was here"
}
$reflectGen!(GENERIC, [
add, addReal, unaryMinus, conj, subtract, multiply, absquare, divideReal, add, addReal, unaryMinus, conj, subtract, multiply, absquare, divideReal,
reciprocal, divide, sqrt reciprocal, divide, sqrt
]) ])

View File

@ -1,6 +1,6 @@
import {Complex} from './type.js' import {Complex} from './type.js'
import type {Dependencies, Signature} from '../interfaces/type.js' import type {Dependencies, Signature} from '../interfaces/type.js'
import {$reflectGen, GENERIC, CONCRETE} from '../interfaces/type.js' import {$reflect} from '../interfaces/type.js'
export const isReal = export const isReal =
<T>(dep: Dependencies<'add' | 'equal' | 'isReal', T>): <T>(dep: Dependencies<'add' | 'equal' | 'isReal', T>):
@ -10,5 +10,4 @@ export const isReal =
export const isSquare = (): Signature<'isSquare', Complex<unknown>> => export const isSquare = (): Signature<'isSquare', Complex<unknown>> =>
z => true // FIXME: not correct for Complex<bigint> once we get there z => true // FIXME: not correct for Complex<bigint> once we get there
$reflectGen!(GENERIC, [isReal]) $reflect!([isReal, isSquare])
$reflectGen!(CONCRETE, [isSquare])

View File

@ -6,7 +6,6 @@
*/ */
import {parseReflectedType, ImplementationDef} from './parseReflectedType.js' import {parseReflectedType, ImplementationDef} from './parseReflectedType.js'
import type {ValueIntersectionByKeyUnion} from '../interfaces/type.js'
// First helper types and functions for the Dispatcher // First helper types and functions for the Dispatcher
@ -36,103 +35,50 @@ type TypeSpecification = {
infer?: (d: DependenciesType) => (z: unknown) => TypeName infer?: (d: DependenciesType) => (z: unknown) => TypeName
} }
type Callable = (...args: any) => any type SpecObject = Record<string, Function | TypeSpecification>
type SpecObject = Record<string, Callable | TypeSpecification>
type SpecificationsGroup = Record<string, SpecObject> type SpecificationsGroup = Record<string, SpecObject>
// Find all of the keys of an object that are functions but not aliases export class Dispatcher {
// to another operation installSpecification(
type BaseOperations<Obj extends SpecObject> = name: string,
{[K in keyof Obj]: defn: ImplementationDef,
Obj[K] extends Callable behavior: Function // possible todo: constrain this type based
? ReturnType<Obj[K]>['aliasOf'] extends (string | undefined) // on the signature, return type, and dependencies. Not sure if
? never // that's really possible, though.
: K extends string ? K : never ) {
: never console.log('Pretending to install', name, 'with signatures')
}[keyof Obj] for (const signature of defn.fn.signatures) {
// Gather all of the operations specified in a SpecificationsGroup console.log(' ', signature.args, '=>', signature.returns)
type DispatcherOperations<G extends SpecificationsGroup> = }
{[K in keyof G]: BaseOperations<G[K]>}[keyof G] if (defn.fn.aliasOf) {
// Get the type of a given operation in a SpecObject: console.log(' As an alias of', defn.fn.aliasOf)
type BaseOperationSignature< }
Obj extends SpecObject, //TODO: implement me
Name extends BaseOperations<Obj> }
> = ValueIntersectionByKeyUnion< installType(name: TypeName, typespec: TypeSpecification) {
{[K in keyof Obj]: console.log('Pretending to install type', name, typespec)
Obj[K] extends Callable //TODO: implement me
? K extends Name }
? ReturnType<Obj[K]> constructor(collection: SpecificationsGroup) {
: ReturnType<Obj[K]>['aliasOf'] extends (Name | undefined) const implementations = []
? ReturnType<Obj[K]> : unknown for (const key in collection) {
: unknown console.log('Working on', key)
}, for (const identifier in collection[key]) {
keyof Obj> const item = collection[key][identifier]
// Get the type of a given operation in a SpecificationsGroup if (typeof item === 'function') {
type OperationSignature< implementations.push([key, identifier, item])
G extends SpecificationsGroup, } else {
Name extends DispatcherOperations<G> console.log('Handling type', key, ':', identifier)
> = ValueIntersectionByKeyUnion< this.installType(
{[K in keyof G]: item.name, collection[key][identifier] as TypeSpecification)
Name extends BaseOperations<G[K]> }
? BaseOperationSignature<G[K], Name>
: unknown},
keyof G>
// Put it all together into the typing of the dispatcher
type DispatcherInterface<G extends SpecificationsGroup> =
{[Op in DispatcherOperations<G>]: OperationSignature<G, Op>}
export function createDispatcher<G extends SpecificationsGroup>(
collection: G): DispatcherInterface<G>
{
const implementations = []
const types = {} // who knows what the type of this will be
const behaviors = {} // ditto
for (const key in collection) {
console.log('Working on', key)
for (const identifier in collection[key]) {
const item = collection[key][identifier]
if (typeof item === 'function') {
implementations.push([key, identifier, item])
} else {
console.log('Handling type', key, ':', identifier)
installType( // In this design, installType would modify
// types by side effect; maybe Jos prefers some other
// factoring of this?
types, item.name,
collection[key][identifier] as TypeSpecification)
} }
} }
for (const trio of implementations) {
const [k, id, imp] = trio
console.log('Handling implementation', id, 'from', k)
this.installSpecification(
id, parseReflectedType(id, imp.reflectedType), imp)
}
} }
for (const trio of implementations) {
const [k, id, imp] = trio
console.log('Handling implementation', id, 'from', k)
installSpecification(
behaviors, id, parseReflectedType(id, imp.reflectedType), imp)
}
return {} as DispatcherInterface<G>
}
function installType(
types: Object, name: TypeName, typespec: TypeSpecification)
{
console.log('Pretending to install type', name, typespec)
//TODO: implement me
}
function installSpecification(
behaviors: Object, // Same issue as mentioned above with side effects...
name: string,
defn: ImplementationDef,
specification: Function // possible todo: constrain this type based
// on the signature, return type, and dependencies. Not sure if
// that's really possible, though.
) {
console.log('Pretending to install', name, 'with signatures')
for (const signature of defn.fn.signatures) {
console.log(' ', signature.args, '=>', signature.returns)
}
if (defn.fn.aliasOf) {
console.log(' As an alias of', defn.fn.aliasOf)
}
//TODO: implement me
} }

View File

@ -1,12 +1,8 @@
import {inspect} from 'node:util' import {inspect} from 'node:util'
import {createDispatcher} from './core/Dispatcher.js' import {Dispatcher} from './core/Dispatcher.js'
import * as Specifications from './all.js' import * as Specifications from './all.js'
export Specifications export default new Dispatcher(Specifications)
const math = createDispatcher(Specifications)
export default math
console.log('Made', math.add}
import {Complex} from './Complex/type.js' import {Complex} from './Complex/type.js'
import {absquare as absquare_complex} from './Complex/arithmetic.js' import {absquare as absquare_complex} from './Complex/arithmetic.js'

View File

@ -15,7 +15,7 @@ import {$$typeToString} from 'ts-macros'
* but that's OK, the generic parameter doesn't hurt in those cases. * but that's OK, the generic parameter doesn't hurt in those cases.
****/ ****/
export type ValueIntersectionByKeyUnion<T, TKey extends keyof T> = { type ValueIntersectionByKeyUnion<T, TKey extends keyof T> = {
[P in TKey]: (k: T[P])=>void [P in TKey]: (k: T[P])=>void
} [TKey] extends ((k: infer I)=>void) ? I : never } [TKey] extends ((k: infer I)=>void) ? I : never
@ -77,7 +77,7 @@ type SignatureKey<T> = keyof Signatures<T>
export type Signature<Name extends SignatureKey<T>, T> = Signatures<T>[Name] export type Signature<Name extends SignatureKey<T>, T> = Signatures<T>[Name]
export type Returns<Name extends SignatureKey<T>, T> = export type Returns<Name extends SignatureKey<T>, T> =
ReturnType<Signatures<T>[Name]> ReturnType<Signatures<T>[Name]>
export type Deps<T> = T extends unknown ? { [K in keyof T]: T[K] } : never; type Deps<T> = T extends unknown ? { [K in keyof T]: T[K] } : never;
export type Dependencies<Name extends SignatureKey<T>, T> = export type Dependencies<Name extends SignatureKey<T>, T> =
Deps<{[K in Name]: Signature<K, T>}> Deps<{[K in Name]: Signature<K, T>}>
@ -88,34 +88,3 @@ export function $reflect<ImplTuple>(tup: ImplTuple) {
+[[tup], <T>(elt: T) => +[[tup], <T>(elt: T) =>
elt.reflectedType = $$typeToString!<T>(true, false, true)] elt.reflectedType = $$typeToString!<T>(true, false, true)]
} }
export function $genImps<ImplTuple>(tup: ImplTuple) {
+[[tup], <U>(elt: U) => {
export interface GenericImplementations<T> {
[$$text!(elt)]: typeof elt
}
}]
}
export function $genImpsT<ImplTuple>(tup: ImplTuple) {
+[[tup], <U>(elt: U) => {
export interface GenericImplementations<T> {
[$$text!(elt)]: typeof elt<T>
}
}]
}
export const GENERIC = true
export const CONCRETE = false
export function $reflectGen<ImplTuple>(generic: boolean, tup: ImplTuple) {
+[[tup], <T>(elt: T) => {
elt.reflectedType = $$typeToString!<T>(true, false, true)
if (generic) {
export interface GenericImplementations<T> {
[$$text!(elt)]: typeof elt<T>
}
} else {
export interface GenericImplementations<T> {
[$$text!(elt)]: typeof elt
}
}
}]
}

View File

@ -1,9 +1,4 @@
import {GenericImplementations} from './predicate.js'
import {$$typeToString} from 'ts-macros'
export * from './type.js' export * from './type.js'
export * from './arithmetic.js' export * from './arithmetic.js'
export * from './predicate.js' export * from './predicate.js'
export * from './relational.js' export * from './relational.js'
const test: ReturnType<GenericImplementations<unknown>['isReal']> =
(a: number) => true // = "oops" would fail as desired.

View File

@ -1,11 +1,7 @@
import type {Signature} from '../interfaces/type.js' import type {Signature} from '../interfaces/type.js'
import {$reflectGen, CONCRETE} from '../interfaces/type.js' import {$reflect} from '../interfaces/type.js'
import {$$typeToString} from 'ts-macros'
export const isReal = (): Signature<'isReal', number> => (a) => true export const isReal = (): Signature<'isReal', number> => (a) => true
export const isSquare = (): Signature<'isSquare', number> => (a) => a >= 0 export const isSquare = (): Signature<'isSquare', number> => (a) => a >= 0
export interface GenericImplementations<T> { $reflect!([isReal, isSquare])
kilroy: "was here"
}
$reflectGen!(CONCRETE, [isReal, isSquare])

View File

@ -4,7 +4,6 @@
"rootDir": "./src", "rootDir": "./src",
"outDir": "./build", "outDir": "./build",
"moduleResolution": "nodenext", "moduleResolution": "nodenext",
"declaration": true,
"plugins": [ { "plugins": [ {
"transform": "ts-macros/dist/type-resolve", "transform": "ts-macros/dist/type-resolve",
"transformProgram": true "transformProgram": true