feat(PocomathInstance): Add importDependencies to follow the dependency graph

This commit is contained in:
Glen Whitney 2022-07-22 19:40:29 -07:00
parent 0fba6544b4
commit e48d927b5f
2 changed files with 54 additions and 1 deletions

View File

@ -6,7 +6,7 @@ export default class PocomathInstance {
* in that if a new top-level PocomathInstance method is added, its name * in that if a new top-level PocomathInstance method is added, its name
* must be added to this list. * must be added to this list.
*/ */
static reserved = new Set(['install']) static reserved = new Set(['install', 'importDependencies'])
constructor(name) { constructor(name) {
this.name = name this.name = name
@ -52,6 +52,43 @@ export default class PocomathInstance {
for (const key in ops) this._installOp(key, ops[key]) for (const key in ops) this._installOp(key, ops[key])
} }
/**
* Import (and install) all dependencies of previously installed functions,
* for the specified types.
*
* @param {string[]} types A list of type names
*/
async importDependencies(types) {
const doneSet = new Set(['self']) // nothing to do for self dependencies
while (true) {
const requiredSet = new Set()
/* Grab all of the known deps */
for (const func in this._imps) {
if (func === 'Types') continue
for (const definition of Object.values(this._imps[func])) {
for (const dependency of definition[0]) {
const depName = dependency.split('(',1)[0]
if (doneSet.has(depName)) continue
requiredSet.add(depName)
}
}
}
if (requiredSet.size === 0) break
for (const name of requiredSet) {
for (const type of types) {
try {
const modName = `../${type}/${name}.mjs`
const mod = await import(modName)
this.install(mod)
} catch (err) {
// No such module, but that's OK
}
}
doneSet.add(name)
}
}
}
/* Used internally by install, see the documentation there */ /* Used internally by install, see the documentation there */
_installOp(name, implementations) { _installOp(name, implementations) {
if (name.charAt(0) === '_') { if (name.charAt(0) === '_') {

View File

@ -6,7 +6,9 @@ import * as numberAdd from '../src/number/add.mjs'
import * as complex from '../src/complex/all.mjs' import * as complex from '../src/complex/all.mjs'
import * as complexAdd from '../src/complex/add.mjs' import * as complexAdd from '../src/complex/add.mjs'
import * as complexNegate from '../src/complex/negate.mjs' import * as complexNegate from '../src/complex/negate.mjs'
import * as complexComplex from '../src/complex/complex.mjs'
import * as concreteSubtract from '../src/generic/subtract.concrete.mjs' import * as concreteSubtract from '../src/generic/subtract.concrete.mjs'
import * as genericSubtract from '../src/generic/subtract.mjs'
import extendToComplex from '../src/complex/extendToComplex.mjs' import extendToComplex from '../src/complex/extendToComplex.mjs'
const bw = new PocomathInstance('backwards') const bw = new PocomathInstance('backwards')
@ -62,4 +64,18 @@ describe('A custom instance', () => {
ok.install(concreteSubtract) ok.install(concreteSubtract)
assert.strictEqual(ok.subtract(7, 5), 2) assert.strictEqual(ok.subtract(7, 5), 2)
}) })
it("can load generics and then import their dependences", async function () {
const chase = new PocomathInstance('Chase Dependencies')
chase.install(genericSubtract)
chase.install(complexComplex) // for convenience to build complex numbers
await chase.importDependencies(['bigint', 'complex'])
/* Now we have an instance that supports subtraction for Gaussian
integers.
*/
assert.deepStrictEqual(
chase.subtract(chase.complex(3n, 2n), chase.complex(2n, 5n)),
math.complex(1n, -3n))
})
}) })