refactor: separate the generation of a typed-function implementation
This commit is contained in:
parent
5c3716ff99
commit
0fbcbf661e
@ -319,7 +319,8 @@ export default class PocomathInstance {
|
|||||||
`Conflicting definitions of ${signature} for ${name}`)
|
`Conflicting definitions of ${signature} for ${name}`)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
opImps[signature] = behavior
|
// Must avoid aliasing into another instance:
|
||||||
|
opImps[signature] = {uses: behavior.uses, does: behavior.does}
|
||||||
for (const dep of behavior.uses) {
|
for (const dep of behavior.uses) {
|
||||||
const depname = dep.split('(', 1)[0]
|
const depname = dep.split('(', 1)[0]
|
||||||
if (depname === 'self' || this._templateParam(depname)) {
|
if (depname === 'self' || this._templateParam(depname)) {
|
||||||
@ -402,80 +403,90 @@ export default class PocomathInstance {
|
|||||||
}
|
}
|
||||||
Object.defineProperty(this, name, {configurable: true, value: 'limbo'})
|
Object.defineProperty(this, name, {configurable: true, value: 'limbo'})
|
||||||
const tf_imps = {}
|
const tf_imps = {}
|
||||||
for (const [rawSignature, {uses, does}] of usableEntries) {
|
for (const [rawSignature, behavior] of usableEntries) {
|
||||||
/* For now, replace theTemplateParam with 'any' */
|
/* For now, replace theTemplateParam with 'any' */
|
||||||
const signature = rawSignature.replaceAll(theTemplateParam, 'any')
|
const signature = rawSignature.replaceAll(theTemplateParam, 'any')
|
||||||
if (uses.length === 0) {
|
this._addTFimplementation(
|
||||||
tf_imps[signature] = does()
|
tf_imps, signature, behavior.uses, behavior.does)
|
||||||
} else {
|
|
||||||
const refs = {}
|
|
||||||
let full_self_referential = false
|
|
||||||
let part_self_references = []
|
|
||||||
for (const dep of uses) {
|
|
||||||
let [func, needsig] = dep.split(/[()]/)
|
|
||||||
const needTypes = needsig ? typesOfSignature(needsig) : new Set()
|
|
||||||
/* For now, punt on template parameters */
|
|
||||||
if (needTypes.has(theTemplateParam)) needsig = ''
|
|
||||||
if (func === 'self') {
|
|
||||||
if (needsig) {
|
|
||||||
if (full_self_referential) {
|
|
||||||
throw new SyntaxError(
|
|
||||||
'typed-function does not support mixed full and '
|
|
||||||
+ 'partial self-reference')
|
|
||||||
}
|
|
||||||
if (subsetOfKeys(typesOfSignature(needsig), this.Types)) {
|
|
||||||
part_self_references.push(needsig)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (part_self_references.length) {
|
|
||||||
throw new SyntaxError(
|
|
||||||
'typed-function does not support mixed full and '
|
|
||||||
+ 'partial self-reference')
|
|
||||||
}
|
|
||||||
full_self_referential = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this[func] === 'limbo') {
|
|
||||||
/* We are in the midst of bundling func, so have to use
|
|
||||||
* an indirect reference to func. And given that, there's
|
|
||||||
* really no helpful way to extract a specific signature
|
|
||||||
*/
|
|
||||||
const self = this
|
|
||||||
refs[dep] = function () { // is this the most efficient?
|
|
||||||
return self[func].apply(this, arguments)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// can bundle up func, and grab its signature if need be
|
|
||||||
let destination = this[func]
|
|
||||||
if (needsig) {
|
|
||||||
destination = this._typed.find(destination, needsig)
|
|
||||||
}
|
|
||||||
refs[dep] = destination
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (full_self_referential) {
|
|
||||||
tf_imps[signature] = this._typed.referToSelf(self => {
|
|
||||||
refs.self = self
|
|
||||||
return does(refs)
|
|
||||||
})
|
|
||||||
} else if (part_self_references.length) {
|
|
||||||
tf_imps[signature] = this._typed.referTo(
|
|
||||||
...part_self_references, (...impls) => {
|
|
||||||
for (let i = 0; i < part_self_references.length; ++i) {
|
|
||||||
refs[`self(${part_self_references[i]})`] = impls[i]
|
|
||||||
}
|
|
||||||
return does(refs)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
tf_imps[signature] = does(refs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const tf = this._typed(name, tf_imps)
|
const tf = this._typed(name, tf_imps)
|
||||||
Object.defineProperty(this, name, {configurable: true, value: tf})
|
Object.defineProperty(this, name, {configurable: true, value: tf})
|
||||||
return tf
|
return tf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Adapts Pocomath-style behavior specification (uses, does) for signature
|
||||||
|
* to typed-function implementations and inserts the result into plain object
|
||||||
|
* imps
|
||||||
|
*/
|
||||||
|
_addTFimplementation(imps, signature, uses, does) {
|
||||||
|
if (uses.length === 0) {
|
||||||
|
imps[signature] = does()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const refs = {}
|
||||||
|
let full_self_referential = false
|
||||||
|
let part_self_references = []
|
||||||
|
for (const dep of uses) {
|
||||||
|
let [func, needsig] = dep.split(/[()]/)
|
||||||
|
const needTypes = needsig ? typesOfSignature(needsig) : new Set()
|
||||||
|
/* For now, punt on template parameters */
|
||||||
|
if (needTypes.has(theTemplateParam)) needsig = ''
|
||||||
|
if (func === 'self') {
|
||||||
|
if (needsig) {
|
||||||
|
if (full_self_referential) {
|
||||||
|
throw new SyntaxError(
|
||||||
|
'typed-function does not support mixed full and '
|
||||||
|
+ 'partial self-reference')
|
||||||
|
}
|
||||||
|
if (subsetOfKeys(typesOfSignature(needsig), this.Types)) {
|
||||||
|
part_self_references.push(needsig)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (part_self_references.length) {
|
||||||
|
throw new SyntaxError(
|
||||||
|
'typed-function does not support mixed full and '
|
||||||
|
+ 'partial self-reference')
|
||||||
|
}
|
||||||
|
full_self_referential = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this[func] === 'limbo') {
|
||||||
|
/* We are in the midst of bundling func, so have to use
|
||||||
|
* an indirect reference to func. And given that, there's
|
||||||
|
* really no helpful way to extract a specific signature
|
||||||
|
*/
|
||||||
|
const self = this
|
||||||
|
refs[dep] = function () { // is this the most efficient?
|
||||||
|
return self[func].apply(this, arguments)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// can bundle up func, and grab its signature if need be
|
||||||
|
let destination = this[func]
|
||||||
|
if (needsig) {
|
||||||
|
destination = this._typed.find(destination, needsig)
|
||||||
|
}
|
||||||
|
refs[dep] = destination
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (full_self_referential) {
|
||||||
|
imps[signature] = this._typed.referToSelf(self => {
|
||||||
|
refs.self = self
|
||||||
|
return does(refs)
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (part_self_references.length) {
|
||||||
|
imps[signature] = this._typed.referTo(
|
||||||
|
...part_self_references, (...impls) => {
|
||||||
|
for (let i = 0; i < part_self_references.length; ++i) {
|
||||||
|
refs[`self(${part_self_references[i]})`] = impls[i]
|
||||||
|
}
|
||||||
|
return does(refs)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
imps[signature] = does(refs)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user