feat: Return type annotations #53
@ -164,7 +164,7 @@ export default class PocomathInstance {
|
||||
* instantiation can be accomplished by prefixin the signature with an
|
||||
* exclamation point.
|
||||
*/
|
||||
install(ops) {
|
||||
install = Returns('void', function(ops) {
|
||||
if (ops instanceof PocomathInstance) {
|
||||
return _installInstance(ops)
|
||||
}
|
||||
@ -197,7 +197,7 @@ export default class PocomathInstance {
|
||||
}
|
||||
}
|
||||
this._installFunctions(stdFunctions)
|
||||
}
|
||||
})
|
||||
|
||||
/* Merge any number of PocomathInstances or modules: */
|
||||
static merge(name, ...pieces) {
|
||||
@ -209,7 +209,7 @@ export default class PocomathInstance {
|
||||
}
|
||||
|
||||
/* 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)) {
|
||||
this._maybeInstantiate(type)
|
||||
}
|
||||
@ -217,13 +217,20 @@ export default class PocomathInstance {
|
||||
operation = operation.name
|
||||
}
|
||||
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: */
|
||||
chain(value) {
|
||||
return makeChain(value, this, this._chainRepository)
|
||||
}
|
||||
chain = Returns(
|
||||
sig => `Chain<${sig}>`,
|
||||
function(value) {
|
||||
return makeChain(value, this, this._chainRepository)
|
||||
}
|
||||
)
|
||||
|
||||
_installInstance(other) {
|
||||
for (const [type, spec] of Object.entries(other.Types)) {
|
||||
@ -272,9 +279,9 @@ export default class PocomathInstance {
|
||||
for (const name of requiredSet) {
|
||||
for (const type of typeSet) {
|
||||
try {
|
||||
const modName = `../${type}/${name}.mjs`
|
||||
const mod = await import(modName)
|
||||
this.install(mod)
|
||||
const moduleName = `../${type}/${name}.mjs`
|
||||
const module = await import(moduleName)
|
||||
this.install(module)
|
||||
} catch (err) {
|
||||
if (!(err.message.includes('find'))) {
|
||||
// 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
|
||||
* the corresponding changes to the _typed object immediately
|
||||
*/
|
||||
installType(type, spec) {
|
||||
installType = Returns('void', function(type, spec) {
|
||||
const parts = type.split(/[<,>]/)
|
||||
if (this._templateParam(parts[0])) {
|
||||
throw new SyntaxError(
|
||||
@ -415,7 +422,7 @@ export default class PocomathInstance {
|
||||
const imp = {}
|
||||
imp[type] = {uses: new Set(), does: () => Returns('string', () => type)}
|
||||
this._installFunctions({typeOf: imp})
|
||||
}
|
||||
})
|
||||
|
||||
_addSubtypeTo(sup, sub) {
|
||||
if (this.isSubtypeOf(sub, sup)) return
|
||||
@ -428,47 +435,48 @@ export default class PocomathInstance {
|
||||
}
|
||||
|
||||
/* 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)
|
||||
}
|
||||
})
|
||||
|
||||
/* 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
|
||||
return this._priorTypes[typeB].has(typeA)
|
||||
}
|
||||
})
|
||||
|
||||
/* Returns a list of the subtypes of a given type, in topological sorted
|
||||
* order (i.e, no type on the list contains one that comes after it).
|
||||
/* Returns a list of the strict ubtypes of a given type, in topological
|
||||
* 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?
|
||||
}
|
||||
})
|
||||
|
||||
/* Returns a list of the supertypes of a given type, starting with itself,
|
||||
* in topological order
|
||||
*/
|
||||
supertypesOf(type) {
|
||||
supertypesOf = Returns('Array<string>', function(type) {
|
||||
const supList = []
|
||||
while (type) {
|
||||
supList.push(type)
|
||||
type = this.Types[type].refines
|
||||
}
|
||||
return supList
|
||||
}
|
||||
})
|
||||
|
||||
/* Returns the most refined type containing all the types in the array,
|
||||
* with '' standing for the empty type for convenience. If the second
|
||||
* argument `convert` is true, a convertible type is considered a
|
||||
* a subtype (defaults to false).
|
||||
*/
|
||||
joinTypes(types, convert) {
|
||||
joinTypes = Returns('string', function(types, convert) {
|
||||
let join = ''
|
||||
for (const type of types) {
|
||||
join = this._joinTypes(join, type, convert)
|
||||
}
|
||||
return join
|
||||
}
|
||||
})
|
||||
|
||||
/* helper for above */
|
||||
_joinTypes(typeA, typeB, convert) {
|
||||
if (!typeA) return typeB
|
||||
@ -500,9 +508,9 @@ export default class PocomathInstance {
|
||||
/* Returns a list of all types that have been mentioned in the
|
||||
* 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))
|
||||
}
|
||||
})
|
||||
|
||||
/* Used internally to install a template type */
|
||||
_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,
|
||||
* 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
|
||||
if (depth > this._maxDepthSeen ) {
|
||||
// don't bother with types much deeper thant we have seen
|
||||
@ -1204,7 +1212,7 @@ export default class PocomathInstance {
|
||||
}
|
||||
this.installType(wantsType, newTypeSpec)
|
||||
return wantsType
|
||||
}
|
||||
})
|
||||
|
||||
_findSubtypeImpl(name, imps, neededSig) {
|
||||
if (neededSig in imps) return neededSig
|
||||
|
@ -34,6 +34,10 @@ describe('The default full pocomath instance "math"', () => {
|
||||
math.add(3, math.complex(2.5, 1)), math.complex(5.5, 1))
|
||||
assert.strictEqual(
|
||||
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', () => {
|
||||
|
Loading…
Reference in New Issue
Block a user