From 2def3e274930165bca49ade8aab528f5fd18c107 Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Fri, 24 Jun 2022 05:50:10 +0300 Subject: [PATCH] more work on .iter(..), now mostly uniform, still needs more testing and possibly unification... Signed-off-by: Alex A. Naanou --- Array.js | 14 +++++- generator.js | 117 +++++++++++++++++++++++++++------------------------ 2 files changed, 75 insertions(+), 56 deletions(-) diff --git a/Array.js b/Array.js index f25f787..647e12d 100644 --- a/Array.js +++ b/Array.js @@ -489,8 +489,18 @@ object.Mixin('ArrayProtoMixin', 'soft', { // -> iterator // // XXX should this take an argument and be like map?? - iter: function*(){ - yield* this }, + iter: function*(handler=undefined){ + if(handler){ + var i = 0 + for(var e of this){ + var res = handler.call(this, e, i++) + if(typeof(res) == 'object' + && Symbol.iterator in res){ + yield* res + } else { + yield res } } + } else { + yield* this }}, // Stoppable iteration... diff --git a/generator.js b/generator.js index 38c4d26..26ceb96 100644 --- a/generator.js +++ b/generator.js @@ -84,6 +84,53 @@ var ITERATOR_PROTOTYPES = [ +//--------------------------------------------------------------------- + +var stoppable = +module.stoppable = +function(func){ + return Object.assign( + func instanceof Generator ? + // NOTE: the only difference between Generator/AsyncGenerator + // versions of this is the async keyword -- keep them + // in sync... + function*(){ + try{ + yield* func.call(this, ...arguments) + } catch(err){ + if(err === STOP){ + return + } else if(err instanceof STOP){ + yield err.value + return } + throw err } } + : func instanceof AsyncGenerator ? + // NOTE: the only difference between Generator/AsyncGenerator + // versions of this is the async keyword -- keep them + // in sync... + async function*(){ + try{ + yield* func.call(this, ...arguments) + } catch(err){ + if(err === STOP){ + return + } else if(err instanceof STOP){ + yield err.value + return } + throw err } } + : function(){ + try{ + return func.call(this, ...arguments) + } catch(err){ + if(err === STOP){ + return + } else if(err instanceof STOP){ + return err.value } + throw err } }, + { toString: function(){ + return func.toString() }, }) } + + //--------------------------------------------------------------------- // generic generator wrapper... @@ -91,7 +138,8 @@ var ITERATOR_PROTOTYPES = [ var __iter = module.__iter = function*(lst=[]){ - if(typeof(lst) == 'object' && Symbol.iterator in lst){ + if(typeof(lst) == 'object' + && Symbol.iterator in lst){ yield* lst } else { yield lst } } @@ -101,7 +149,7 @@ function*(lst=[]){ var iter = module.iter = Generator.iter = - function(lst=[]){ + stoppable(function(lst=[]){ // handler -> generator-constructor... if(typeof(lst) == 'function'){ // we need to be callable... @@ -112,7 +160,7 @@ Generator.iter = return function*(){ yield* that(...arguments).iter(lst) } } // no handler -> generator instance... - return module.__iter(lst) } + return module.__iter(lst) }) // NOTE: we need .iter(..) to both return generators if passed an iterable // and genereator constructos if passed a function... @@ -201,51 +249,6 @@ var makePromise = function(name){ return that(...arguments)[name](func) } } } -var stoppable = -module.stoppable = -function(func){ - return Object.assign( - func instanceof Generator ? - // NOTE: the only difference between Generator/AsyncGenerator - // versions of this is the async keyword -- keep them - // in sync... - function*(){ - try{ - yield* func.call(this, ...arguments) - } catch(err){ - if(err === STOP){ - return - } else if(err instanceof STOP){ - yield err.value - return } - throw err } } - : func instanceof AsyncGenerator ? - // NOTE: the only difference between Generator/AsyncGenerator - // versions of this is the async keyword -- keep them - // in sync... - async function*(){ - try{ - yield* func.call(this, ...arguments) - } catch(err){ - if(err === STOP){ - return - } else if(err instanceof STOP){ - yield err.value - return } - throw err } } - : function(){ - try{ - return func.call(this, ...arguments) - } catch(err){ - if(err === STOP){ - return - } else if(err instanceof STOP){ - return err.value } - throw err } }, - { toString: function(){ - return func.toString() }, }) } - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - var GeneratorMixin = @@ -332,7 +335,7 @@ var GeneratorProtoMixin = module.GeneratorProtoMixin = object.Mixin('GeneratorProtoMixin', 'soft', { // XXX use module.iter(..) ??? - iter: function*(handler){ + iter: stoppable(function*(handler){ if(handler){ var i = 0 for(var elem of this){ @@ -346,7 +349,7 @@ object.Mixin('GeneratorProtoMixin', 'soft', { yield res }} // no handler... } else { - yield* this } }, + yield* this } }), //*/ at: function(i){ @@ -546,10 +549,16 @@ object.Mixin('AsyncGeneratorProtoMixin', 'soft', { // XXX might be a good idea to use this approach above... iter: stoppable(async function*(handler=undefined){ var i = 0 - for await(var e of this){ - yield* handler ? - handler.call(this, e, i++) - : [e] } }), + if(handler){ + for await(var e of this){ + var res = handler.call(this, e, i++) + if(typeof(res) == 'object' + && Symbol.iterator in res){ + yield* res + } else { + yield res } } + } else { + yield* this } }), map: async function*(func){ yield* this.iter(function(elem, i){