Good stuff. This will come in handy if node.js 0.12 takes much longer.
Watching the use of generators in JavaScript and especially node.js is going to be very exciting over the coming years. We're excited at LinkedIn because we write a lot of node.js, and control flow is always being discussed: step, async, stepup, promises, and async generators look to solve a lot of that.
Also, checkout the AGen formal spec[1] for asynchronous generators. Raynos and I put it together recently to encourage interoperability between async generator solutions, and we're both using it in personal projects.[2]
I'd love a synopsis of the algorithm you use to do the transformation. I always thought it was possible but grew weary whenever I thought of having to transform everything (loops, etc) and keep the state. So glad to see that this was done!
I'm hoping to do a more in-depth writeup about this soon, but the basic approach is to hoist all declarations up into the closure of an inner function, so that all variables in the scope of the function persist between .next calls, and then convert any control structures that contain yields to a big switch statement, where the cases are essentially jump targets, controlled by the $ctx.next property.
Very cool. I'm glad you went the whole way and transformed everything, including try/catch. I'm assuming it handles exceptions properly in the dynamic context? Take the following code:
This is pretty great. In the past I've had some awful things to say about generators as compared to more powerful control flow primitives, but this transformation highlights an advantage of generators. The transformed code is tiny and surprisingly readable. If someone wanted coroutines that could yield from subroutines, or (heaven forbid) shift+reset, this sort of transformation of basic-blocks-and-gotos into loops-and-cases would no longer be sufficient. Generators hit a sort of sweet spot.
Do you think it is worth the extra complexity of browser-detecting and loading the original JS if the browser has actual ES6 generator support? Firefox has it now without requiring any flags. Chrome(/Opera)/Node require --harmony or --harmony-generators.
I might recommend against the additional complexity for most use cases, since the generated code is only 1.5x slower, but I fully expect/hope that Facebook will decide to bite that complexity bullet for the speed gains in newer browsers. Betting on the future of JS is very much the ethos here.
Any interest at FB to sponsor the JSC implementation? That would leave IE as the odd one out... (If anyone reading works at Microsoft, politely ask the IE team to prioritize ES6 generators :))
I love Continuum, and I think it takes the right approach for implementing all of ES6, if that's what you want. I just didn't think I could pitch the idea of using a virtual virtual machine to my team, so I took the more conservative approach.
While I would love the rest of es6 the only things I really really want for the project I am working on are generators and sandboxes.
I tried implementing sandboxing a little while back by cleaning the global namespace after every tick and freezing all the built in prototypes, but I still don't know enough about the dirty details of js to know if I am doing it properly in a way that will actually be fast.
I am reluctant to use with but a friend of mine suggested that it is possible to use it to avoid polluting the global namespace. This in combination with freezing all the global prototypes might be enough to do what I want.
Have you thought about this at all? Is there already a library for this that would do what I want? I wouldn't mind running the code in a worker to restrict access to the dom apis.
Interesting suggestion. Although Traceur's generator support is arguably more limited, I have to admit their code is currently better tested than regenerator's, so I think I want to give this repo some time to mature before exploring whether the Traceur team wants to use it.
This is hand-wavy for sure, but I don't think Emitter.prototype.emit is called more than once per AST node, and the number of cases should be less than the number of calls to .emit, so there should be fewer cases than AST nodes (which is a statically knowable number).
You should make a browserify transform (https://github.com/substack/node-browserify) so that it can easily be put into a pipeline to convert generator code to es5 code. Folks using browserify will be able to use it very easily.
Thank you! This is so exciting. I've been wanting to try things like go style concurrency (http://swannodette.github.io/2013/08/24/es6-generators-and-c...) in the browser, and this seems like it will help us get there. Granted, haven't tried it yet, and really understand nothing about any of this, but ... Anyway, hooray :)
This is similar to my asyncscript pet project[1] (that was met with much resistance on the Node.js mailing list as it was Yet Another CPS Framework). It drew inspiration from the way that C# creates the state machines for "yield" and "await". The project is dead (it only dealt with async calls and I never got round to "enumeration generators"), but if you are wondering how regenerator works I have a nice explanation at the bottom of readme.md.
I couldn't find information why generator functions in JS require '*' in the syntax (ES6 spec/wiki just states this as a fact, but no rationale). Does anybody know?
Python manages to work fine without ugly wart in the syntax, and it seems to me that presence of `yield` keyword in body is enough at syntactical level to tell compiler that the function is a generator.
It means you can have generator functions that contain no yield statements, which is not as crazy as it sounds. I've had to do `if False: yield` before in Python to trick the language into treating a function as a generator. An unyielding generator behaves so differently from a similar-looking non-generator function that the extra syntax seems more than appropriate to me.
The asterisk also makes it trivial (using regular expressions) to tell whether a string of code contains any generator functions.
"Explicit is better than implicit" is a rule of thumb that Python supposedly values, but neglects to follow here!
Watching the use of generators in JavaScript and especially node.js is going to be very exciting over the coming years. We're excited at LinkedIn because we write a lot of node.js, and control flow is always being discussed: step, async, stepup, promises, and async generators look to solve a lot of that.
Also, checkout the AGen formal spec[1] for asynchronous generators. Raynos and I put it together recently to encourage interoperability between async generator solutions, and we're both using it in personal projects.[2]
[1] https://github.com/AsynchronousGenerators/agen-spec
[2] https://github.com/Raynos/gens