UNPKG

scontainers

Version:

A container/collection/iterator library for JavaScript, comfortable to use, performant and versatile.

404 lines (301 loc) 13 kB
"use strict"; function _implSymbol(target, sym, value) { Object.defineProperty(target, sym, { value, configurable: true }); return target[sym]; } function _getSymbol(targetSymName, ...traitSets) { let symbol; traitSets.forEach(traitSet => { const sym = traitSet[targetSymName]; if (typeof sym === 'symbol') { if (!!symbol && symbol !== sym) { throw new Error(`Symbol ${targetSymName} offered by multiple trait sets.`); } symbol = sym; } }); if (!symbol) { throw new Error(`No trait set is providing symbol ${targetSymName}.`); } return symbol; } function _testTraitSet(traitSet) { if (!traitSet || typeof traitSet === 'boolean' || typeof traitSet === 'number' || typeof traitSet === 'string') { throw new Error(`${traitSet} cannot be used as a trait set.`); } } const { deriveProtocolsFromGenerators } = require('./derived_generators.js'); const { assert, traits, options, semantics, KVN } = require('../utils.js'); _testTraitSet(traits.utils); _testTraitSet(traits.descriptors); _testTraitSet(traits.semantics); const _InnerCollection = _getSymbol("InnerCollection", traits.utils, traits.descriptors, traits.semantics); const _extractKeys = _getSymbol("extractKeys", traits.utils, traits.descriptors, traits.semantics); const _implTraits = _getSymbol("implTraits", traits.utils, traits.descriptors, traits.semantics); const _addTraitFactories2 = _getSymbol("addTraitFactories", traits.utils, traits.descriptors, traits.semantics); const _implCoreGenerators = _getSymbol("implCoreGenerators", traits.utils, traits.descriptors, traits.semantics); _implSymbol(Object.prototype, _implCoreGenerators, function (compilerConfiguration) { if (!options.generation) { return; } if (this[_InnerCollection]) { compileProtocolsForTransformation.call(this, compilerConfiguration); } else { compileProtocolsForRootType.call(this, compilerConfiguration); } // deriving all the remaining protocol generators deriveCoreProtocolGenerators.call(this); // deriving non-core protocols from our protocol generators deriveProtocolsFromGenerators.call(this); }); function compileProtocolsForRootType(compilerConfiguration) { const Collection = this; assert(Collection, `compileProtocolsForRootType() must be called on an object`); const check = (cond, err) => { assert(cond, `${Collection.name}.compileProtocolsForTransformation(): ${err}`); }; // taking the non-protocol data from `configuration` (e.g. `nStage` and `stage`) let { nthUnchecked, getUnchecked } = compilerConfiguration[_extractKeys](Object.keys({ nthUnchecked: null, getUnchecked: null })); // deriving the missing non-protocol functions we can derive { _testTraitSet(traits.generators); const _keyToN = _getSymbol("keyToN", traits.utils, traits.descriptors, traits.semantics, traits.generators); if (nthUnchecked) { check(!getUnchecked, `either supply \`nthUnchecked\` or \`getUnchecked\``); getUnchecked = function (key) { const n = this[_keyToN](key); return nthUnchecked.call(this, n); }; } } // everything in `compilerConfiguration` should be protocol generator factories: assigning them to `this` traits.generators[_implTraits](this, compilerConfiguration); // deriving the other core protocol generator factories we can derive from the non-protocol data { _testTraitSet(traits.generators); const _addTraitFactories = _getSymbol("addTraitFactories", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _nToKey = _getSymbol("nToKey", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _keyToN2 = _getSymbol("keyToN", traits.utils, traits.descriptors, traits.semantics, traits.generators); traits.generators[_addTraitFactories](this, { nthKVN() { if (nthUnchecked) { return function (n) { /* this.body // ._Straits.statement( this.assert( semantics.id(`Number`)._Straits.member(`isInteger`)._Straits.call( n ) ) ) // ._Straits.if( semantics.or( n._Straits.lt( 0 ), n._Straits.ge( this._Straits.len() ) ), /* ._Straits.if( n._Straits.lt( this._Straits.len() ), // semantics.return() this.body = semantics.block() ._Straits.statement( semantics.lit(this.Type.name) ) ); */ return new KVN(this[_nToKey](n), nthUnchecked.call(this, n), n); }; } }, getKVN() { if (getUnchecked) { if (Collection[_keyToN2]) { return function (key) { /* this.pushStatement( semantics.if( this._Straits.hasKey(key).note(), semantics.return() ) ); */ return new KVN(key, getUnchecked.call(this, key), this[_keyToN2](key)); }; } else { return function (key) { return new KVN(key, getUnchecked.call(this, key)); }; } } } }); } } // implements collection protocols for the type `this` whose parent type is `ParentType`, // generating functions using `compilerConfiguration` function compileProtocolsForTransformation(compilerConfiguration) { assert(this, `compileProtocolsForTransformation() must be called on an object`); const check = (cond, err) => { assert(cond, `${this.name}.compileProtocolsForTransformation(): ${err}`); }; const Collection = this; const ParentType = this[_InnerCollection]; check(ParentType, `need to specify the ParentType`); // taking the non-protocol data from `compilerConfiguration` (e.g. `nStage` and `stage`) /* // TODO: once the rest parameter syntax is standard, we should do this: let {stage, nStage, kStage, indexToParentIndex, nToParentN, keyToParentKey, ...compConf} = compilerConfiguration; compilerConfiguration = compConf; */ let { stage, nStage, kStage, indexToParentIndex, nToParentN, keyToParentKey } = compilerConfiguration[_extractKeys](Object.keys({ stage: null, nStage: null, kStage: null, indexToParentIndex: null, nToParentN: null, keyToParentKey: null })); // deriving the missing non-protocol functions we can derive { check(!!stage === !!indexToParentIndex && !!nStage === !!nToParentN && !!kStage === !!keyToParentKey, `\`*Stage\` needs to match \`*ToParent*\``); if (stage) { check(!nStage && !kStage, `either supply \`stage\` or \`nStage\` or \`kStage\``); nStage = stage; kStage = stage; } if (indexToParentIndex) { check(!nToParentN && !keyToParentKey, `either supply \`indexToParentIndex\` or \`nToParentN\` or \`keyToParentKey\``); nToParentN = indexToParentIndex; keyToParentKey = indexToParentIndex; } } // all the remaining stuff in `compilerConfiguration` should be protocol generator factories: assigning them to `this` traits.generators[_addTraitFactories2](this, compilerConfiguration); // deriving the other core protocol generator factories we can derive from the non-protocol data { _testTraitSet(traits.generators); const _addTraitFactories3 = _getSymbol("addTraitFactories", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _mappingOnly = _getSymbol("mappingOnly", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _len = _getSymbol("len", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _nToKey2 = _getSymbol("nToKey", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _nthKVN = _getSymbol("nthKVN", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _getKVN = _getSymbol("getKVN", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _keyToN3 = _getSymbol("keyToN", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _loop = _getSymbol("loop", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _standardIteration = _getSymbol("standardIteration", traits.utils, traits.descriptors, traits.semantics, traits.generators); traits.generators[_addTraitFactories3](Collection, { len() { if (Collection[_mappingOnly] && ParentType[_len]) { return function () { return this.inner[_len](); }; } }, nToKey() { if (nToParentN && ParentType[_nToKey2]) { return function (n) { const parentN = nToParentN.call(this, n); return this.inner[_nToKey2](parentN); }; } }, nthKVN() { if (nStage && ParentType[_nthKVN]) { return function (n) { const parentN = nToParentN.call(this, n); const parentKVN = this.inner[_nthKVN](parentN); parentKVN.n = n; return nStage.call(this, parentKVN); }; } }, getKVN() { if (kStage && ParentType[_getKVN]) { return function (key) { const parentKey = keyToParentKey.call(this, key); const parentKVN = this.inner[_getKVN](parentKey); return kStage.call(this, parentKVN); }; } }, hasKey() { if (kStage && ParentType[_getKVN]) { return function (key) { const parentKey = keyToParentKey.call(this, key); const parentKVN = this.inner[_getKVN](parentKey); kStage.call(this, parentKVN); return true; }; } }, keyToN() { if (keyToParentKey && ParentType[_keyToN3]) { return function (key) { const parentKey = keyToParentKey.call(this, key); return this.inner[_keyToN3](parentKey); }; } }, loop() { if (ParentType[_loop] && this[_standardIteration]) { return function () { const kvn = this.inner[_loop](); return kStage.call(this, kvn); }; } } }); } } function deriveCoreProtocolGenerators() { assert(this, `deriveCoreProtocolGenerators() must be called on an object`); _testTraitSet(traits.generators); const _addTraitFactories4 = _getSymbol("addTraitFactories", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _nthKVN2 = _getSymbol("nthKVN", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _keyToN4 = _getSymbol("keyToN", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _member = _getSymbol("member", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _call = _getSymbol("call", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _ge = _getSymbol("ge", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _lt = _getSymbol("lt", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _len2 = _getSymbol("len", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _setNth = _getSymbol("setNth", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _standardIteration2 = _getSymbol("standardIteration", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _for = _getSymbol("for", traits.utils, traits.descriptors, traits.semantics, traits.generators); const _increment = _getSymbol("increment", traits.utils, traits.descriptors, traits.semantics, traits.generators); traits.generators[_addTraitFactories4](this, { getKVN() { if (this[_nthKVN2] && this[_keyToN4]) { return function (key) { const n = this[_keyToN4](key); return this[_nthKVN2](n); }; } }, hasKey() { if (this[_keyToN4]) { return function (key) { const n = this[_keyToN4](key); return semantics.and(semantics.id(`Number`)[_member](`isInteger`)[_call](n), n[_ge](0), n[_lt](this[_len2]())); }; } }, set() { if (this[_setNth] && this[_keyToN4]) { return function (key, value) { const n = this[_keyToN4](key); return this[_setNth](n, value); }; } }, loop() { if (this[_nthKVN2] && this[_standardIteration2]) { return function (generator) { const i = this.createUniqueVariable(`i`); const lenVar = this[_len2](); this.body[_for](semantics.declare(i, 0, `var`), i[_lt](lenVar), i[_increment](), this.body = semantics.block()); return this[_nthKVN2](i); }; } } }); }