scontainers
Version:
A container/collection/iterator library for JavaScript, comfortable to use, performant and versatile.
404 lines (301 loc) • 13 kB
JavaScript
;
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);
};
}
}
});
}