diff --git a/src/core/PocomathInstance.mjs b/src/core/PocomathInstance.mjs index 901514b..0a589ca 100644 --- a/src/core/PocomathInstance.mjs +++ b/src/core/PocomathInstance.mjs @@ -319,7 +319,8 @@ export default class PocomathInstance { `Conflicting definitions of ${signature} for ${name}`) } } else { - opImps[signature] = behavior + // Must avoid aliasing into another instance: + opImps[signature] = {uses: behavior.uses, does: behavior.does} for (const dep of behavior.uses) { const depname = dep.split('(', 1)[0] if (depname === 'self' || this._templateParam(depname)) { @@ -402,80 +403,90 @@ export default class PocomathInstance { } Object.defineProperty(this, name, {configurable: true, value: 'limbo'}) const tf_imps = {} - for (const [rawSignature, {uses, does}] of usableEntries) { + for (const [rawSignature, behavior] of usableEntries) { /* For now, replace theTemplateParam with 'any' */ const signature = rawSignature.replaceAll(theTemplateParam, 'any') - if (uses.length === 0) { - tf_imps[signature] = 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) - } - } + this._addTFimplementation( + tf_imps, signature, behavior.uses, behavior.does) } const tf = this._typed(name, tf_imps) Object.defineProperty(this, name, {configurable: true, value: 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) + } }