experiment: Can't put code in declare sections :-)
This commit is contained in:
parent
78f3975d54
commit
2a9039ac67
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,5 +1,9 @@
|
||||
# Emacs backups
|
||||
*~
|
||||
# Typescript
|
||||
# emitted code
|
||||
obj
|
||||
|
||||
# ---> Node
|
||||
# Logs
|
||||
logs
|
||||
|
33
src/complex/type.ts
Normal file
33
src/complex/type.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import {Specifications, joinTypes, typeOfDependency} from '../core/Dispatcher'
|
||||
|
||||
export type Complex<T> = {re: T; im: T;}
|
||||
|
||||
declare module 'Dispatcher' {
|
||||
namespace Specifications {
|
||||
export class ComplexSpecifications {}
|
||||
|
||||
namespace ComplexSpecifications {
|
||||
export class Complex_type<T> {
|
||||
static test = (testT: (z: unknown) => z is T) =>
|
||||
(z: unknown): z is Complex<T> =>
|
||||
typeof z === 'object'
|
||||
&& 're' in z && 'im' in z
|
||||
&& testT(z.re) && testT(z.im);
|
||||
static infer = (dep: typeOfDependency) =>
|
||||
(z: Complex<unknown>) =>
|
||||
joinTypes(dep.typeOf(z.re), dep.typeOf(z.im));
|
||||
static from = {
|
||||
T: (dep: ImplementationType<'zero', [T]>) => (t: T) =>
|
||||
({re: t, im: dep.zero(t)}),
|
||||
Complex: <U>(convert: (from: U) => T) =>
|
||||
(z: Complex<U>) => ({re: convert(z.re), im: convert(z.im)})
|
||||
};
|
||||
}
|
||||
export const complex_1 = <T>(dep: DependencyType<'zero', [T]>) =>
|
||||
(t: T) => ({re: t, im: dep.zero(t)})
|
||||
export const complex_2 = <T>(t: T, u: T) => ({re: t, im: u})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {Specifications}
|
7
src/core/Config.ts
Normal file
7
src/core/Config.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export type Config = {
|
||||
predictable: boolean
|
||||
}
|
||||
|
||||
export type ConfigDependency = {
|
||||
config: Config
|
||||
}
|
109
src/core/Dispatcher.ts
Normal file
109
src/core/Dispatcher.ts
Normal file
@ -0,0 +1,109 @@
|
||||
/* A Dispatcher is a collection of operations that do run-time
|
||||
* dispatch on the types of their arguments. Thus, every individual
|
||||
* method is like a typed-function (from the library by that name),
|
||||
* but they can depend on one another and on ona another's implementations
|
||||
* for specific types (including their own).
|
||||
*/
|
||||
|
||||
type TypeName = string
|
||||
type Parameter = TypeName
|
||||
type Signature = Parameter[]
|
||||
|
||||
export class Specifications {}
|
||||
export type typeOfDependency = {typeOf: (x: unknown) => TypeName}
|
||||
|
||||
//dummy implementation for now
|
||||
export function joinTypes(a: TypeName, b: TypeName) {
|
||||
if (a === b) return a
|
||||
return 'any'
|
||||
}
|
||||
|
||||
// Will need to build this up. Need to start with looping through the keys of
|
||||
// values of keys, and filtering ones that start with Name, then add in
|
||||
// checking the types.
|
||||
|
||||
// Some relevant stuff that worked in the playground:
|
||||
// type KeysMatching<T, N, V> = {[K in keyof T]-?: T[K] extends V ? K extends `${string}${N}${string}` ? K : never : never}[keyof T];
|
||||
// type ValuesMatching<T, V> = {[K in keyof T]: T[K] extends V ? T[K] : never}[keyof T]
|
||||
|
||||
// type SubKeysMatching<T, N, V> = {[K in keyof T]: KeysMatching<T[K], N, V>}[keyof T]
|
||||
// type SubValuesMatching<T, V> = {[K in keyof T]: ValuesMatching<T[K], V>}[keyof T]
|
||||
|
||||
|
||||
// let trial: SubKeysMatching<typeof Bar, 'ng', number | boolean> = 'strange'
|
||||
// let valtrial: SubValuesMatching<typeof Bar, number> = 3
|
||||
|
||||
// type MyFunc = (...args: [string, number]) => any
|
||||
|
||||
// Selecting the proper key for arguments [string, number] is working
|
||||
// let key: KeysMatching<typeof Foo, 'a', MyFunc > = 'bar' // OK, and 'baz' here does fail, as desired
|
||||
|
||||
// The above should have all of the ingredients.
|
||||
type DependenciesType = Record<String, Function>
|
||||
|
||||
type FinalShape<FuncType> =
|
||||
FuncType extends (arg: DependenciesType) => Function
|
||||
? ReturnType<FuncType> : FuncType
|
||||
|
||||
type BeginsWith<Name> = `${Name}${string}`
|
||||
|
||||
type ImmediateDependency<Ob, Name, ParamTuple> =
|
||||
{[K in keyof Ob]: K extends BeginsWith<Name>
|
||||
? FinalShape<Ob[K]> extends (...args: ParamTuple) => any
|
||||
? FinalShape<Ob[K]>
|
||||
: never
|
||||
: never}[keyof Ob]
|
||||
|
||||
type SpecType = typeof Specifications
|
||||
|
||||
export type ImplementationDependency<Name, ParamTuple> =
|
||||
{[S in keyof SpecType]:
|
||||
ImmediateDependency<SpecType[S], Name, ParamTuple>}[keyof SpecType]
|
||||
|
||||
type TypeSpecification = {
|
||||
before?: TypeName[],
|
||||
test: ((x: unknown) => boolean)
|
||||
| ((d: DependenciesType) => (x: unknown) => boolean),
|
||||
from: Record<Typename, Function>,
|
||||
infer?: (d: DependenciesType) => (z: unknown) => TypeName
|
||||
}
|
||||
|
||||
type SpecObject = Record<string, Function | TypeSpecification>
|
||||
export type SpecifcationsGroup = Record<string, SpecObject>
|
||||
|
||||
export class Dispatcher {
|
||||
installSpecification(
|
||||
name: string,
|
||||
signature: Signature,
|
||||
returns: Type,
|
||||
dependencies: Record<string, Signature>,
|
||||
behavior: 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, signature, '=>', returns)
|
||||
//TODO: implement me
|
||||
}
|
||||
installType(name: TypeName, typespec: TypeSpecification) {
|
||||
console.log('Pretending to install type', name, typespec)
|
||||
//TODO: implement me
|
||||
}
|
||||
constructor(collection: SpecificationsGroup) {
|
||||
for (key in collection) {
|
||||
console.log('Working on', key)
|
||||
for (identifier in collection[key]) {
|
||||
console.log('Handling', key, ':', identifier)
|
||||
const parts = identifier.split('_')
|
||||
if (parts[parts.length - 1] === 'type') {
|
||||
parts.pop()
|
||||
const name = parts.join('_')
|
||||
installType(name, collection[key][identifier])
|
||||
} else {
|
||||
const name = parts[0]
|
||||
installSpecification(
|
||||
name, ['dunno'], 'unsure', {}, collection[key][identifier])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
5
src/index.ts
Normal file
5
src/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import Dispatcher from 'core/Dispatcher'
|
||||
import Complex from 'complex/type'
|
||||
import Specifications from 'number/arithmetic'
|
||||
|
||||
export default new Dispatcher(Specifications)
|
29
src/number/arithmetic.ts
Normal file
29
src/number/arithmetic.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import Specifications from './type'
|
||||
import configDependency from '../core/Config'
|
||||
/// <reference path="../complex/type.ts">
|
||||
|
||||
declare module 'Dispatcher' {
|
||||
namespace Specifications {
|
||||
namespace NumberSpecifications {
|
||||
export const add = (a: number, b: number) => a + b
|
||||
export const unaryMinus = (a: number) => -a
|
||||
export const subtract = (a: number, b: number) => a - b
|
||||
export const multiply = (a: number, b: number) => a * b
|
||||
export const divide = (a: number, b: number) => a / b
|
||||
export const sqrt =
|
||||
(dep: configDependency
|
||||
& ImplementationDependency<'complex', [number,number]>) => {
|
||||
if (dep.config.predictable || !dep.complex) {
|
||||
return (a: number) => isNaN(n) ? NaN : Math.sqrt(n)
|
||||
}
|
||||
return (a: number) => {
|
||||
if (isNaN(n)) return NaN
|
||||
if (n >= 0) return Math.sqrt(n)
|
||||
return dep.complex(0, Math.sqrt(unaryMinus(n)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {Specifications}
|
17
src/number/type.ts
Normal file
17
src/number/type.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import Specifications from '../core/Dispatcher'
|
||||
|
||||
declare module 'Dispatcher' {
|
||||
namespace Specifications {
|
||||
export class NumberSpecifications {}
|
||||
namespace NumberSpecifications {
|
||||
export const number_type = {
|
||||
before: ['Complex'],
|
||||
test: (n: unknown): n is number => typeof n === 'number',
|
||||
from: {string: s => +s}
|
||||
}
|
||||
export const zero = (a: number) => 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {Specifications}
|
7
tsconfig.json
Normal file
7
tsconfig.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"rootDir": "./src",
|
||||
"outDir": "./obj"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user