Skip to content

Promise Generators #752

@kkirby

Description

@kkirby

Hello.

I have updated LiveScript in a fork to support promise generators. The syntax looks like this:

wait = (time) -> new Promise (fulfill) -> setTimeout fulfill, time

my-promise = ->**
    console.log \helloWorld
    yield wait 1000
    console.log \goodbyeWorld

function my-promise **()
    console.log \helloWorld
    yield wait 1000
    console.log \goodbyeWorld

The compiled code renders as such:

// Generated by LiveScript 1.4.0
(function(){
  var wait, myPromise;
  wait = function(time){
    return new Promise(function(fulfill){
      return setTimeout(fulfill, time);
    });
  };
  myPromise = generatorToPromise$(function*(){
    console.log('helloWorld');
    (yield wait(1000));
    return console.log('goodbyeWorld');
  });
  function tryCatch$(func,context,args){
      try {
          return {
              failed: false,
              value: func.apply(context,args)
          };
      }
      catch(exception){
          return {
              failed: true,
              value: exception
          }
      }
  }
  function generatorToPromise$(func,argumentLength){
      function processGenerator(generator){
          return new Promise(
              function(fulfill,reject){
                  function next(passIn,handler){
                      handler = handler || 'next';
                      var tryCatchResult = tryCatch$(generator[handler],generator,[passIn]);
                      if(tryCatchResult.failed === true){
                          return reject(tryCatchResult.value);
                      }
                      var result = tryCatchResult.value;
                      if(result.done){
                          return fulfill(result.value);
                      }
                      else if(result.value instanceof Promise){
                          result.value.then(
                              next,
                              function(promiseError){
                                  next(promiseError,'throw');
                              }
                          );
                      }
                      else {
                          next(result.value);
                      }
                  }
                  next()
              }
          );
      }
      if(typeof func != 'function' && typeof func.next == 'function'){
          return processGenerator(func)
      }
      else {
          if(typeof argumentLength == 'number'){
              var args = [];
              for(var i = 0; i < argumentLength; i++){
                  args.push('arg'+i);
              }
              args = args.join(',');
              return new Function('processGenerator,func','return function(' + args + '){ return processGenerator(func.call(this,' + args + ')); };')(processGenerator,func);
          }
          else {
              return function(){
                  return processGenerator(func.apply(this,arguments));
              }
          }
      }
  }
}).call(this);

My only big concern is using this along with currying. The issue is that currying requires knowing the arguments length of the function, but since all functions are being wrapped, the argument length would be zero. To work around this, I have opted to pass in the argument length if the function is curried and create a function via a string. It's pretty gross, but I can't immediately think of a better way that works across platforms.

You can check the fork out here: https://github.com/kkirby/LiveScript/tree/generator-promise

If promise generators are desired, but modifications are requested, I'm open for discussion. Otherwise, is this something that could become a part of LiveScript?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions