jsx/JSX — pull request #303 by wasabiz (2014-03-05 12:27:23+00:00)
Title: Yield expression

# Abstract
This pull-request adds a simple syntax to pass values into a generator. As of this writing JSX has generators which only support produce outputs. In almost all cases generators are required, even if only 'generating' values is supported, they are enough useful in various situations such as incrementally producing values by need via a pipeline. Sometimes, however, the ability to pass information from outside would be more useful. Taking for example `co`, which is making the best use of ES6's generator, they realize async functions by beautiful hack. When you call co with a generator function and a yield expression is invoked inside, co 'injects' a code to run in background the asynchronous task encapsulated in given promise between the yield and its continuation.

# Design
When you make a generator object by calling a generator function, you are allowed to call 'next' method with an optional argument `value`. If the generator object is in suspended state (i.e. neither newborn nor dead), the result of suspending yield expression will be the given value. If it is in newborn state, the value is simply ignored.

```js
function * foo () : int {
var i = yield 0;
var j = yield i;
yield j;
}
foo().next(42); // => 0; generator object neglects 42.
foo().next().next(1) // => 1
foo().next().next(1).next(2) // => 2
```

Since there hasn't been default type parameter in JSX, I designed the type of yield expressions to be same type as the yielding type. But If you want, I'm quite ready to let my design go and change the type to `variant`.

```js
function * foo () : int {
var i = yield 0; // the type of i is automatically inferred to be `int`. Passing information of different type than yielding type is not permitted.
}
```

# Impl

The transformation is performed like below.

- original
```
class _Main {
static function main (args : string[]) : void {
function * sum () : number {
var a = 0;
while (true) {
a += yield a;
}
}

var g = sum();
g.next();	// initial run
for (var i = 1; i < 5; ++i) {
log g.next(i).value; // 1, 3, 6, 10, ...
}
}
}
```

- after transformation
```
function _Main$main$AS(args) {
var sum;
var g;
var i;
function sum() {
var a;
var $generator;
var $return;
var $loop;
$generator = new __jsx_generator_object$0();
function $loop($next) {
var $a1;
var $a0;
var $a5;
var $a4;
var $a3;
while (true) {
switch ($next) {
case 0:
$a1 = 0;
$a0 = a = $a1;
$a0;
$next = 1;
break;
case 1:
$next = ((function ($a2) {
return $a2;
})(true) ? 2 : 3);
break;
case 2:
$a5 = a;
$generator.__value = $a5;
$generator.__next = 4;
return;
case 4:
$a4 = $generator.__value;
$a3 = a += $a4;
$a3;
$next = 1;
break;
case 3:
$generator.__value = $return;
$generator.__next = -1;
return;
}
}
}
$generator.__next = 0;
$generator.__loop = $loop;
return $generator;
}
g = sum();
g.next();
for (i = 1; i < 5; ++i) {
log g.next(i).value;
}
};
```