feat: Return type annotations (#53)
Provides the infrastructure to allow annotating the return types of functions, and does so for essentially every operation in the system (the only known exceptions being add, multiply, etc., on arbitrarily many arguments). One main infrastructure enhancements are bounded template types, e.g. `T:number` being a template parameter where T can take on the type `number` or any subtype thereof. A main internal enhancement is that base template types are no longer added to the typed universe; rather, there is a secondary, "meta" typed universe where they live. The primary point/purpose of this change is then the necessary search order for implementations can be much better modeled by typed-function's search order, using the `onMismatch` facility to redirect the search from fully instantiated implementations to the generic catchall implementations for each template (these catchalls live in the meta universe). Numerous other small improvements and bugfixes were encountered along the way. Co-authored-by: Glen Whitney <glen@studioinfinity.org> Reviewed-on: #53
This commit is contained in:
parent
207ac4330b
commit
31add66f4c
80 changed files with 1502 additions and 606 deletions
File diff suppressed because it is too large
Load diff
34
src/core/Returns.mjs
Normal file
34
src/core/Returns.mjs
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* Annotate a function with its return type */
|
||||
|
||||
/* Unfortunately JavaScript is missing a way to cleanly clone a function
|
||||
* object, see https://stackoverflow.com/questions/1833588
|
||||
*/
|
||||
|
||||
const clonedFrom = Symbol('the original function this one was cloned from')
|
||||
function cloneFunction(fn) {
|
||||
const behavior = fn[clonedFrom] || fn // don't nest clones
|
||||
const theClone = function () { return behavior.apply(this, arguments) }
|
||||
Object.assign(theClone, fn)
|
||||
theClone[clonedFrom] = body
|
||||
Object.defineProperty(
|
||||
theClone, 'name', {value: fn.name, configurable: true })
|
||||
return theClone
|
||||
}
|
||||
|
||||
export function Returns(type, fn) {
|
||||
if ('returns' in fn) fn = cloneFunction(fn)
|
||||
fn.returns = type
|
||||
return fn
|
||||
}
|
||||
|
||||
export function returnTypeOf(fn, signature, pmInstance) {
|
||||
const typeOfReturns = typeof fn.returns
|
||||
if (typeOfReturns === 'undefined') return 'any'
|
||||
if (typeOfReturns === 'string') return fn.returns
|
||||
// not sure if we will need a function to determine the return type,
|
||||
// but allow it for now:
|
||||
return fn.returns(signature, pmInstance)
|
||||
}
|
||||
|
||||
export default Returns
|
||||
|
|
@ -8,6 +8,8 @@ export function subsetOfKeys(set, obj) {
|
|||
|
||||
/* Returns a list of the types mentioned in a typed-function signature */
|
||||
export function typeListOfSignature(signature) {
|
||||
signature = signature.trim()
|
||||
if (!signature) return []
|
||||
return signature.split(',').map(s => s.trim())
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue