feat: Return type annotations #53
@ -164,7 +164,7 @@ export default class PocomathInstance {
|
|||||||
* instantiation can be accomplished by prefixin the signature with an
|
* instantiation can be accomplished by prefixin the signature with an
|
||||||
* exclamation point.
|
* exclamation point.
|
||||||
*/
|
*/
|
||||||
install(ops) {
|
install = Returns('void', function(ops) {
|
||||||
if (ops instanceof PocomathInstance) {
|
if (ops instanceof PocomathInstance) {
|
||||||
return _installInstance(ops)
|
return _installInstance(ops)
|
||||||
}
|
}
|
||||||
@ -197,7 +197,7 @@ export default class PocomathInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._installFunctions(stdFunctions)
|
this._installFunctions(stdFunctions)
|
||||||
}
|
})
|
||||||
|
|
||||||
/* Merge any number of PocomathInstances or modules: */
|
/* Merge any number of PocomathInstances or modules: */
|
||||||
static merge(name, ...pieces) {
|
static merge(name, ...pieces) {
|
||||||
@ -209,7 +209,7 @@ export default class PocomathInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Determine the return type of an operation given an input signature */
|
/* Determine the return type of an operation given an input signature */
|
||||||
returnTypeOf(operation, signature) {
|
returnTypeOf = Returns('string', function(operation, signature) {
|
||||||
for (const type of typeListOfSignature(signature)) {
|
for (const type of typeListOfSignature(signature)) {
|
||||||
this._maybeInstantiate(type)
|
this._maybeInstantiate(type)
|
||||||
}
|
}
|
||||||
@ -217,13 +217,20 @@ export default class PocomathInstance {
|
|||||||
operation = operation.name
|
operation = operation.name
|
||||||
}
|
}
|
||||||
const details = this._pocoFindSignature(operation, signature)
|
const details = this._pocoFindSignature(operation, signature)
|
||||||
return returnTypeOf(details.fn, signature, this)
|
if (details) {
|
||||||
}
|
return returnTypeOf(details.fn, signature, this)
|
||||||
|
}
|
||||||
|
console.log('Checking return type of', operation)
|
||||||
|
return returnTypeOf(this[operation], signature, this)
|
||||||
|
})
|
||||||
|
|
||||||
/* Return a chain object for this instance with a given value: */
|
/* Return a chain object for this instance with a given value: */
|
||||||
chain(value) {
|
chain = Returns(
|
||||||
return makeChain(value, this, this._chainRepository)
|
sig => `Chain<${sig}>`,
|
||||||
}
|
function(value) {
|
||||||
|
return makeChain(value, this, this._chainRepository)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
_installInstance(other) {
|
_installInstance(other) {
|
||||||
for (const [type, spec] of Object.entries(other.Types)) {
|
for (const [type, spec] of Object.entries(other.Types)) {
|
||||||
@ -272,9 +279,9 @@ export default class PocomathInstance {
|
|||||||
for (const name of requiredSet) {
|
for (const name of requiredSet) {
|
||||||
for (const type of typeSet) {
|
for (const type of typeSet) {
|
||||||
try {
|
try {
|
||||||
const modName = `../${type}/${name}.mjs`
|
const moduleName = `../${type}/${name}.mjs`
|
||||||
const mod = await import(modName)
|
const module = await import(moduleName)
|
||||||
this.install(mod)
|
this.install(module)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (!(err.message.includes('find'))) {
|
if (!(err.message.includes('find'))) {
|
||||||
// Not just a error because module doesn't exist
|
// Not just a error because module doesn't exist
|
||||||
@ -315,7 +322,7 @@ export default class PocomathInstance {
|
|||||||
* Implementation note: unlike _installFunctions below, we can make
|
* Implementation note: unlike _installFunctions below, we can make
|
||||||
* the corresponding changes to the _typed object immediately
|
* the corresponding changes to the _typed object immediately
|
||||||
*/
|
*/
|
||||||
installType(type, spec) {
|
installType = Returns('void', function(type, spec) {
|
||||||
const parts = type.split(/[<,>]/)
|
const parts = type.split(/[<,>]/)
|
||||||
if (this._templateParam(parts[0])) {
|
if (this._templateParam(parts[0])) {
|
||||||
throw new SyntaxError(
|
throw new SyntaxError(
|
||||||
@ -415,7 +422,7 @@ export default class PocomathInstance {
|
|||||||
const imp = {}
|
const imp = {}
|
||||||
imp[type] = {uses: new Set(), does: () => Returns('string', () => type)}
|
imp[type] = {uses: new Set(), does: () => Returns('string', () => type)}
|
||||||
this._installFunctions({typeOf: imp})
|
this._installFunctions({typeOf: imp})
|
||||||
}
|
})
|
||||||
|
|
||||||
_addSubtypeTo(sup, sub) {
|
_addSubtypeTo(sup, sub) {
|
||||||
if (this.isSubtypeOf(sub, sup)) return
|
if (this.isSubtypeOf(sub, sup)) return
|
||||||
@ -428,47 +435,48 @@ export default class PocomathInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Returns true if typeA is a subtype of type B */
|
/* Returns true if typeA is a subtype of type B */
|
||||||
isSubtypeOf(typeA, typeB) {
|
isSubtypeOf = Returns('boolean', function(typeA, typeB) {
|
||||||
return this._subtypes[typeB].includes(typeA)
|
return this._subtypes[typeB].includes(typeA)
|
||||||
}
|
})
|
||||||
|
|
||||||
/* Returns true if typeA is a subtype of or converts to type B */
|
/* Returns true if typeA is a subtype of or converts to type B */
|
||||||
isPriorTo(typeA, typeB) {
|
isPriorTo = Returns('boolean', function(typeA, typeB) {
|
||||||
if (!(typeB in this._priorTypes)) return false
|
if (!(typeB in this._priorTypes)) return false
|
||||||
return this._priorTypes[typeB].has(typeA)
|
return this._priorTypes[typeB].has(typeA)
|
||||||
}
|
})
|
||||||
|
|
||||||
/* Returns a list of the subtypes of a given type, in topological sorted
|
/* Returns a list of the strict ubtypes of a given type, in topological
|
||||||
* order (i.e, no type on the list contains one that comes after it).
|
* sorted order (i.e, no type on the list contains one that comes after it).
|
||||||
*/
|
*/
|
||||||
subtypesOf(type) {
|
subtypesOf = Returns('Array<string>', function(type) {
|
||||||
return this._subtypes[type] // should we clone?
|
return this._subtypes[type] // should we clone?
|
||||||
}
|
})
|
||||||
|
|
||||||
/* Returns a list of the supertypes of a given type, starting with itself,
|
/* Returns a list of the supertypes of a given type, starting with itself,
|
||||||
* in topological order
|
* in topological order
|
||||||
*/
|
*/
|
||||||
supertypesOf(type) {
|
supertypesOf = Returns('Array<string>', function(type) {
|
||||||
const supList = []
|
const supList = []
|
||||||
while (type) {
|
while (type) {
|
||||||
supList.push(type)
|
supList.push(type)
|
||||||
type = this.Types[type].refines
|
type = this.Types[type].refines
|
||||||
}
|
}
|
||||||
return supList
|
return supList
|
||||||
}
|
})
|
||||||
|
|
||||||
/* Returns the most refined type containing all the types in the array,
|
/* Returns the most refined type containing all the types in the array,
|
||||||
* with '' standing for the empty type for convenience. If the second
|
* with '' standing for the empty type for convenience. If the second
|
||||||
* argument `convert` is true, a convertible type is considered a
|
* argument `convert` is true, a convertible type is considered a
|
||||||
* a subtype (defaults to false).
|
* a subtype (defaults to false).
|
||||||
*/
|
*/
|
||||||
joinTypes(types, convert) {
|
joinTypes = Returns('string', function(types, convert) {
|
||||||
let join = ''
|
let join = ''
|
||||||
for (const type of types) {
|
for (const type of types) {
|
||||||
join = this._joinTypes(join, type, convert)
|
join = this._joinTypes(join, type, convert)
|
||||||
}
|
}
|
||||||
return join
|
return join
|
||||||
}
|
})
|
||||||
|
|
||||||
/* helper for above */
|
/* helper for above */
|
||||||
_joinTypes(typeA, typeB, convert) {
|
_joinTypes(typeA, typeB, convert) {
|
||||||
if (!typeA) return typeB
|
if (!typeA) return typeB
|
||||||
@ -500,9 +508,9 @@ export default class PocomathInstance {
|
|||||||
/* Returns a list of all types that have been mentioned in the
|
/* Returns a list of all types that have been mentioned in the
|
||||||
* signatures of operations, but which have not actually been installed:
|
* signatures of operations, but which have not actually been installed:
|
||||||
*/
|
*/
|
||||||
undefinedTypes() {
|
undefinedTypes = Returns('Array<string>', function() {
|
||||||
return Array.from(this._seenTypes).filter(t => !(t in this.Types))
|
return Array.from(this._seenTypes).filter(t => !(t in this.Types))
|
||||||
}
|
})
|
||||||
|
|
||||||
/* Used internally to install a template type */
|
/* Used internally to install a template type */
|
||||||
_installTemplateType(type, spec) {
|
_installTemplateType(type, spec) {
|
||||||
@ -1137,7 +1145,7 @@ export default class PocomathInstance {
|
|||||||
* Returns the name of the type if added, false if it was already there,
|
* Returns the name of the type if added, false if it was already there,
|
||||||
* and undefined if the type is declined (because of being nested too deep).
|
* and undefined if the type is declined (because of being nested too deep).
|
||||||
*/
|
*/
|
||||||
instantiateTemplate(base, instantiator) {
|
instantiateTemplate = Returns('void', function(base, instantiator) {
|
||||||
const depth = instantiator.split('<').length
|
const depth = instantiator.split('<').length
|
||||||
if (depth > this._maxDepthSeen ) {
|
if (depth > this._maxDepthSeen ) {
|
||||||
// don't bother with types much deeper thant we have seen
|
// don't bother with types much deeper thant we have seen
|
||||||
@ -1204,7 +1212,7 @@ export default class PocomathInstance {
|
|||||||
}
|
}
|
||||||
this.installType(wantsType, newTypeSpec)
|
this.installType(wantsType, newTypeSpec)
|
||||||
return wantsType
|
return wantsType
|
||||||
}
|
})
|
||||||
|
|
||||||
_findSubtypeImpl(name, imps, neededSig) {
|
_findSubtypeImpl(name, imps, neededSig) {
|
||||||
if (neededSig in imps) return neededSig
|
if (neededSig in imps) return neededSig
|
||||||
@ -1305,7 +1313,7 @@ export default class PocomathInstance {
|
|||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
_pocoresolve(name, sig, typedFunction) {
|
_pocoresolve(name, sig, typedFunction) {
|
||||||
if (!this._typed.isTypedFunction(typedFunction)) {
|
if (!this._typed.isTypedFunction(typedFunction)) {
|
||||||
typedFunction = this[name]
|
typedFunction = this[name]
|
||||||
|
@ -13,8 +13,8 @@ export const floor = {
|
|||||||
* be separately activated
|
* be separately activated
|
||||||
*/
|
*/
|
||||||
bigint: () => Returns('bigint', x => x),
|
bigint: () => Returns('bigint', x => x),
|
||||||
NumInt: () => Returns('NumInt', x => x),
|
NumInt: () => Returns('NumInt', x => x),
|
||||||
'Complex<bigint>': () => Returns('Complex<bigint>', x => x),
|
'Complex<bigint>': () => Returns('Complex<bigint>', x => x),
|
||||||
|
|
||||||
number: ({'equalTT(number,number)': eq}) => Returns('NumInt', n => {
|
number: ({'equalTT(number,number)': eq}) => Returns('NumInt', n => {
|
||||||
if (eq(n, Math.round(n))) return Math.round(n)
|
if (eq(n, Math.round(n))) return Math.round(n)
|
||||||
|
@ -34,6 +34,10 @@ describe('The default full pocomath instance "math"', () => {
|
|||||||
math.add(3, math.complex(2.5, 1)), math.complex(5.5, 1))
|
math.add(3, math.complex(2.5, 1)), math.complex(5.5, 1))
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
math.returnTypeOf('add', 'Complex<number>,NumInt'), 'Complex<number>')
|
math.returnTypeOf('add', 'Complex<number>,NumInt'), 'Complex<number>')
|
||||||
|
assert.strictEqual(
|
||||||
|
math.returnTypeOf('chain', 'bigint'), 'Chain<bigint>')
|
||||||
|
assert.strictEqual(
|
||||||
|
math.returnTypeOf('returnTypeOf', 'string,string'), 'string')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can subtract numbers', () => {
|
it('can subtract numbers', () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user