2020-11-09 06:22:32 +03:00
|
|
|
/**********************************************************************
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
**********************************************/ /* c8 ignore next 2 */
|
|
|
|
|
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
|
|
|
|
|
(function(require){ var module={} // make module AMD/node compatible...
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
2020-11-10 17:40:32 +03:00
|
|
|
var object = require('ig-object')
|
2020-11-09 06:22:32 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************/
|
2020-11-10 03:04:04 +03:00
|
|
|
// The generator hirearchy in JS is a bit complicated.
|
|
|
|
|
//
|
|
|
|
|
// Consider the following:
|
|
|
|
|
//
|
|
|
|
|
// // this is the generator function (i.e. the constructor)
|
|
|
|
|
// var Iter = function*(lst){
|
|
|
|
|
// for(var e of lst){
|
|
|
|
|
// yield e }}
|
|
|
|
|
//
|
|
|
|
|
// // this is the generator instance (constructod instance)...
|
|
|
|
|
// var iter = Iter([1,2,3])
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// In this module we need to add methods to be visible from either Iter
|
|
|
|
|
// or iter from the above example, so we need the access the prototypes
|
|
|
|
|
// of each of them.
|
|
|
|
|
//
|
|
|
|
|
// GeneratorPrototype
|
|
|
|
|
// is the prototype of the generator construcotrs (i.e. Iter(..)
|
|
|
|
|
// from the above example)
|
|
|
|
|
//
|
|
|
|
|
// GeneratorPrototype.prototype
|
|
|
|
|
// is the generator instance prototype (i.e. iter for the above
|
|
|
|
|
// code)
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// Also the following applies:
|
|
|
|
|
//
|
|
|
|
|
// iter instanceof Iter // -> true
|
|
|
|
|
//
|
|
|
|
|
// Iter instanceof Generator
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// NOTE: there appears no way to test if iter is instnace of some
|
|
|
|
|
// generic Generator...
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
var GeneratorPrototype =
|
|
|
|
|
(function*(){}).constructor.prototype
|
|
|
|
|
|
|
|
|
|
var Generator =
|
|
|
|
|
module.Generator =
|
|
|
|
|
(function*(){}).constructor
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
|
|
|
|
// generic generator wrapper...
|
|
|
|
|
var iter =
|
|
|
|
|
module.iter =
|
2020-11-10 17:40:32 +03:00
|
|
|
function*(lst=[]){
|
2020-11-10 03:04:04 +03:00
|
|
|
for(var e of lst){
|
|
|
|
|
yield e } }
|
2020-11-09 06:22:32 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------
|
2020-11-10 03:04:04 +03:00
|
|
|
// GeneratorPrototype "class" methods...
|
2020-11-09 06:22:32 +03:00
|
|
|
//
|
|
|
|
|
// the following are the same:
|
|
|
|
|
// 1) Wrapper
|
|
|
|
|
// var combined = function(...args){
|
|
|
|
|
// return someGenerator(...args)
|
|
|
|
|
// .filter(function(e){ ... })
|
|
|
|
|
// .map(function(e){ ... }) }
|
|
|
|
|
//
|
|
|
|
|
// combined( .. )
|
|
|
|
|
//
|
|
|
|
|
// 2) Static generator methods...
|
|
|
|
|
// var combined = someGenerator
|
|
|
|
|
// .filter(function(e){ ... })
|
|
|
|
|
// .map(function(e){ ... })
|
|
|
|
|
//
|
|
|
|
|
// combined( .. )
|
|
|
|
|
//
|
|
|
|
|
|
2020-11-10 17:40:32 +03:00
|
|
|
// XXX this needs to be of the correct type... (???)
|
2020-11-09 06:22:32 +03:00
|
|
|
var makeGenerator = function(name){
|
|
|
|
|
return function(...args){
|
|
|
|
|
var that = this
|
2020-11-10 17:40:32 +03:00
|
|
|
return Object.assign(
|
|
|
|
|
function*(){
|
|
|
|
|
yield* that(...arguments)[name](...args) },
|
|
|
|
|
{ toString: function(){
|
|
|
|
|
return [
|
|
|
|
|
that.toString(),
|
|
|
|
|
// XXX need to normalize args better...
|
|
|
|
|
`.${ name }(${ args.join(', ') })`,
|
|
|
|
|
].join('\n ') }, }) } }
|
|
|
|
|
// XXX do a better doc...
|
2020-11-10 01:58:51 +03:00
|
|
|
var makePromise = function(name){
|
|
|
|
|
return function(...args){
|
|
|
|
|
var that = this
|
|
|
|
|
return function(){
|
|
|
|
|
return that(...arguments)[name](func) } } }
|
|
|
|
|
|
2020-11-09 06:22:32 +03:00
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
2020-11-10 03:04:04 +03:00
|
|
|
// XXX should this be a generator???
|
|
|
|
|
GeneratorPrototype.at = makeGenerator('at')
|
2020-11-10 17:40:32 +03:00
|
|
|
|
2020-11-10 03:04:04 +03:00
|
|
|
GeneratorPrototype.slice = makeGenerator('slice')
|
|
|
|
|
GeneratorPrototype.flat = makeGenerator('flat')
|
2020-11-10 17:40:32 +03:00
|
|
|
|
|
|
|
|
GeneratorPrototype.map = makeGenerator('map')
|
|
|
|
|
GeneratorPrototype.filter = makeGenerator('filter')
|
|
|
|
|
GeneratorPrototype.reduce = makeGenerator('reduce')
|
|
|
|
|
|
|
|
|
|
// non-generators...
|
|
|
|
|
//
|
2020-11-10 03:04:04 +03:00
|
|
|
GeneratorPrototype.toArray = function(){
|
2020-11-09 06:22:32 +03:00
|
|
|
var that = this
|
2020-11-10 17:40:32 +03:00
|
|
|
return Object.assign(
|
|
|
|
|
function(){
|
|
|
|
|
return that(...arguments).toArray() },
|
|
|
|
|
{ toString: function(){
|
|
|
|
|
return that.toString()
|
|
|
|
|
+ '\n .toString()'}, }) }
|
2020-11-10 03:04:04 +03:00
|
|
|
GeneratorPrototype.pop = function(){
|
|
|
|
|
var that = this
|
2020-11-10 17:40:32 +03:00
|
|
|
return Object.assign(
|
|
|
|
|
function(){
|
|
|
|
|
return that(...arguments).toArray().pop() },
|
|
|
|
|
{ toString: function(){
|
|
|
|
|
return that.toString()
|
|
|
|
|
+ '\n .pop()'}, }) }
|
2020-11-10 03:04:04 +03:00
|
|
|
GeneratorPrototype.shift = function(){
|
|
|
|
|
var that = this
|
2020-11-10 17:40:32 +03:00
|
|
|
return Object.assign(
|
|
|
|
|
function(){
|
|
|
|
|
return that(...arguments).toArray().shift() },
|
|
|
|
|
{ toString: function(){
|
|
|
|
|
return that.toString()
|
|
|
|
|
+ '\n .shift()'}, }) }
|
2020-11-10 01:58:51 +03:00
|
|
|
|
2020-11-10 17:40:32 +03:00
|
|
|
// promises...
|
|
|
|
|
//
|
2020-11-10 03:04:04 +03:00
|
|
|
GeneratorPrototype.then = makePromise('then')
|
|
|
|
|
GeneratorPrototype.catch = makePromise('catch')
|
|
|
|
|
GeneratorPrototype.finally = makePromise('finally')
|
2020-11-10 01:58:51 +03:00
|
|
|
|
2020-11-09 06:22:32 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------
|
2020-11-10 03:04:04 +03:00
|
|
|
// GeneratorPrototype instance methods...
|
2020-11-09 06:22:32 +03:00
|
|
|
|
2020-11-10 03:04:04 +03:00
|
|
|
// XXX should this be a generator???
|
|
|
|
|
GeneratorPrototype.prototype.at = function*(i){
|
2020-11-10 01:58:51 +03:00
|
|
|
// sanity check...
|
|
|
|
|
if(i < 0){
|
|
|
|
|
throw new Error('.at(..): '
|
|
|
|
|
+'generator index can\'t be a negative value.')}
|
2020-11-09 06:22:32 +03:00
|
|
|
for(var e of this){
|
2020-11-10 01:58:51 +03:00
|
|
|
if(i-- == 0){
|
|
|
|
|
yield e
|
|
|
|
|
return } } },
|
|
|
|
|
|
|
|
|
|
// NOTE: this is different from Array's .slice(..) in that it does not
|
|
|
|
|
// support negative indexes -- this is done because there is no way
|
|
|
|
|
// to judge the length of a generator untill it is fully done...
|
2020-11-10 03:04:04 +03:00
|
|
|
GeneratorPrototype.prototype.slice = function*(from=0, to=Infity){
|
2020-11-10 01:58:51 +03:00
|
|
|
// sanity check...
|
|
|
|
|
if(from < 0 || to < 0){
|
|
|
|
|
throw new Error('.slice(..): '
|
|
|
|
|
+'generator form/to indexes can\'t be negative values.')}
|
2020-11-09 06:22:32 +03:00
|
|
|
var i = 0
|
|
|
|
|
for(var e of this){
|
2020-11-10 01:58:51 +03:00
|
|
|
// stop at end of seq...
|
|
|
|
|
if(i >= to){
|
|
|
|
|
return }
|
|
|
|
|
// only yield from from...
|
|
|
|
|
if(i >= from){
|
|
|
|
|
yield e }
|
|
|
|
|
i++ } },
|
2020-11-10 17:40:32 +03:00
|
|
|
// XXX do we need a version that'll expand generators???
|
2020-11-10 03:04:04 +03:00
|
|
|
GeneratorPrototype.prototype.flat = function*(depth=1){
|
2020-11-09 06:22:32 +03:00
|
|
|
if(depth == 0){
|
|
|
|
|
return this }
|
|
|
|
|
for(var e of this){
|
2020-11-10 17:40:32 +03:00
|
|
|
// expand array...
|
2020-11-09 06:22:32 +03:00
|
|
|
if(e instanceof Array){
|
|
|
|
|
for(var i=0; i < e.length; i++){
|
|
|
|
|
if(depth <= 1){
|
|
|
|
|
yield e[i]
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
yield* typeof(e[i].flat) == 'function' ?
|
|
|
|
|
e[i].flat(depth-1)
|
|
|
|
|
: e[i] } }
|
2020-11-10 17:40:32 +03:00
|
|
|
// item as-is...
|
2020-11-09 06:22:32 +03:00
|
|
|
} else {
|
|
|
|
|
yield e } } }
|
|
|
|
|
|
2020-11-10 03:04:04 +03:00
|
|
|
GeneratorPrototype.prototype.map = function*(func){
|
2020-11-10 01:58:51 +03:00
|
|
|
var i = 0
|
|
|
|
|
for(var e of this){
|
|
|
|
|
yield func(e, i++, this) } }
|
2020-11-10 03:04:04 +03:00
|
|
|
GeneratorPrototype.prototype.filter = function*(func){
|
2020-11-10 01:58:51 +03:00
|
|
|
var i = 0
|
|
|
|
|
for(var e of this){
|
|
|
|
|
if(func(e, i++, this)){
|
|
|
|
|
yield e } } }
|
2020-11-10 03:04:04 +03:00
|
|
|
GeneratorPrototype.prototype.reduce = function*(func, res){
|
2020-11-10 01:58:51 +03:00
|
|
|
var i = 0
|
|
|
|
|
for(var e of this){
|
|
|
|
|
res = func(res, e, i++, this) }
|
|
|
|
|
yield res }
|
|
|
|
|
|
2020-11-10 17:40:32 +03:00
|
|
|
// non-generators...
|
|
|
|
|
//
|
|
|
|
|
GeneratorPrototype.prototype.toArray = function(){
|
|
|
|
|
return [...this] }
|
|
|
|
|
GeneratorPrototype.prototype.pop = function(){
|
|
|
|
|
return [...this].pop() }
|
|
|
|
|
GeneratorPrototype.prototype.shift = function(){
|
|
|
|
|
return [...this].shift() }
|
|
|
|
|
|
|
|
|
|
// promises...
|
2020-11-10 01:58:51 +03:00
|
|
|
//
|
|
|
|
|
// XXX how do we handle reject(..) / .catch(..)???
|
2020-11-10 03:04:04 +03:00
|
|
|
GeneratorPrototype.prototype.promise = function(){
|
2020-11-10 01:58:51 +03:00
|
|
|
var that = this
|
|
|
|
|
return new Promise(function(resolve){
|
|
|
|
|
resolve([...that]) }) }
|
2020-11-10 03:04:04 +03:00
|
|
|
GeneratorPrototype.prototype.then = function(func){
|
2020-11-10 01:58:51 +03:00
|
|
|
return this.promise().then(func) }
|
2020-11-10 03:04:04 +03:00
|
|
|
GeneratorPrototype.prototype.catch = function(func){
|
2020-11-10 01:58:51 +03:00
|
|
|
return this.promise().catch(func) }
|
2020-11-10 03:04:04 +03:00
|
|
|
GeneratorPrototype.prototype.finally = function(func){
|
2020-11-10 01:58:51 +03:00
|
|
|
return this.promise().finally(func) }
|
2020-11-09 06:22:32 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
|
* vim:set ts=4 sw=4 : */ return module })
|