GOTOs in JavaScript are now possible

Posted on:

And I'm back with my crazy experiments.

Currently I'm actively playing with Ragel - state machine compiler that generates highly optimized code for streaming lexers, scanners etc. in a set of languages (C, Java, Ruby, C#, ...). Unfortunately, it didn't have support for JavaScript, and I recently implemented it (likely to be included in Ragel 7.0, but it's anyway worth dedicated article).

Now, Ragel can generate code with various levels of optimizations. The least optimized one uses arrays of indices to search through using binary search and jump between, and the more optimized ones use goto instruction for quick jumps directly between states.

For languages such as C or Assembler this works great and generates proper jumps/gotos. However higher-level languages (Java, C#, Ruby, ..., and of course JavaScript) don't have any instruction like that due to "dirt" associated with this operator that discourages it's use for handwritten code - simply because it becomes unmaintainable. But this doesn't matter when our code is anyway generated from other language and result doesn't have to be comprehensible.

JavaScript has a long history of compilation and transpiling from other langs (and across versions of itself), and yet it doesn't have operator that could be used when generating direct jumps. So what's the solution? Of course, to implement own extension to language with the most EVIL feature ever!

And here we go: I forked regenerator - transpiler for resumable generator and async functions. It already had all the needed state analysis and expansion which are easy to reuse, and all that you need is to add new instructions and tell it where they might break code into pieces, to which places you can jump and so on.

For goto statements theirselves I decided to simplify task and not to introduce new syntax, but reuse existing but rare one - labels - so that you can write:

function f() {
  goto: x;
  console.log("do not enter");
  z: console.log(3);
  return 4;
  y: console.log(2);
  goto: z;
  x: console.log(1);
  goto: y;

console.log("Let's do some evil!");
console.log("Result:", f());

And you get in console:

Let's do some evil!
Result: 4

You can play with my fork here: js-goto-transpiler.

DISCLAIMER: I'm not responsible if you decide to use this feature in production and will be fired for using it :)

More posts: