Desugaring of the IR (herein called Extended-JS) to regular ES5 JavaScript
Defines methods to emit Scala.
Defines methods to emit Scala.js classes to JavaScript code. The results are not desugared. Only the class *structure* is decomposed to a lower representation in the IR. The output of all these methods should be further desugared before being emitted as JavaScript code.
Desugaring of the IR (herein called Extended-JS) to regular ES5 JavaScript
Extended-JS is a non-existent language that is a superset of JavaScript with Scala-esque constructs. Most notably, most constructs can be used in expression position. Extended-JS also features ES6-like classes.
GenJSCode emits Extended-JS because it is *much* easier not to deal with the expression position issue in there. But of course, in the end, we need to output genuine JavaScript code.
JSDesugaring desugars a statement of Extended-JS into genuine ES5 JavaScript code.
The general idea is two-folded: 1) Unnest complex constructs in "argument position": When a complex construct is used in a non-rhs expression position (argument to a function, operand, condition of an if, etc.), that we call "argument position", declare a variable before the statement, assign the complex construct to it and then use that variable in the argument position instead. 2) Push LHS's inside complex RHS's: When an rhs is a complex construct, push the lhs inside the complex construct. Are considered lhs: * Assign, i.e.,
x =
* VarDef, i.e.,var x =
* Return, i.e.,return
* (EmptyTree is also used as a trick for code reuse) In fact, think that, in this context, LHS means: what to do with the result of evaluating the RHS.Typical example, consider the method call:
obj.meth({ var x = foo(42); x*x });
According to rule 1), the block that is passed as a parameter to obj.meth is first extracted in a synthetic var:
var x$1 = { var x = foo(42); x*x } obj.meth(x$1);
Then, according to rule 2), the lhs
var x$1 =
is pushed inside the block:{ var x = foo(42); var x$1 = x*x; } obj.meth(x$1);
Because bare blocks are non-significant in JS, this is equivalent to
var x = foo(42); var x$1 = x*x; obj.meth(x$1);
JSDesugaring does all this in a single pass, but it helps to think that: * Rule 1) is implemented by unnest(), and used most notably in * transformStat() for statement-only constructs * pushLhsInto() for statement-or-expression constructs * Rule 2) is implemented by pushLhsInto() * Emitting the class structure is delegated to ScalaJSClassEmitter.