Generates the Scala.js IR for a compilation unit This method iterates over all the class and interface definitions found in the compilation unit and emits their IR (.sjsir).
Generates the Scala.js IR for a compilation unit This method iterates over all the class and interface definitions found in the compilation unit and emits their IR (.sjsir).
Some classes are never actually emitted:
Some classes representing anonymous functions are not actually emitted.
Instead, a temporary representation of their apply
method is built
and recorded, so that it can be inlined as a JavaScript anonymous
function in the method that instantiates it.
Other ClassDefs are emitted according to their nature:
* Raw JS type (<: js.Any) -> genRawJSClassData()
* Interface -> genInterface()
* Implementation class -> genImplClass()
* Normal class -> genClass()
Ensures that the value of the given tree is boxed.
Ensures that the value of the given tree is boxed.
Tree to be boxed if needed.
The type of expr
as it was entering
the posterasure phase.
Turn a JavaScript expression of type Unit into a statement
Extracts a value typed as Any to the given type after posterasure.
Extracts a value typed as Any to the given type after posterasure.
Tree to be extracted.
The type of expr
as it was entering
the posterasure phase.
Gen and record JS code for a raw JS function class.
Gen and record JS code for a raw JS function class.
This is called when emitting a ClassDef that represents an anonymous
class extending js.FunctionN
. These are generated by the SAM
synthesizer when the target type is a js.FunctionN
. Since JS
functions are not classes, we deconstruct the ClassDef, then
reconstruct it to be a genuine Closure.
Compared to tryGenAndRecordAnonFunctionClass()
, this function must
always succeed, because we really cannot afford keeping them as
anonymous classes. The good news is that it can do so, because the
body of SAM lambdas is hoisted in the enclosing class. Hence, the
apply() method is just a forwarder to calling that hoisted method.
From a class looking like this:
final class <anon>(outer, capture1, ..., captureM) extends js.FunctionN[...] { def apply(param1, ..., paramN) = { outer.lambdaImpl(param1, ..., paramN, capture1, ..., captureM) } } new <anon>(o, c1, ..., cM)
we generate a function maker that emits:
lambda<o, c1, ..., cM>[notype]( outer, capture1, ..., captureM, param1, ..., paramN) { outer.lambdaImpl(param1, ..., paramN, capture1, ..., captureM) }
The function maker is recorded in translatedAnonFunctions
to be
fetched later by the translation for New.
Gen JS code for an Apply node (method call)
Gen JS code for an Apply node (method call)
There's a whole bunch of varieties of Apply nodes: regular method calls, super calls, constructor calls, isInstanceOf/asInstanceOf, primitives, JS calls, etc. They are further dispatched in here.
Gen JS code for a call to a Scala method.
Gen JS code for a call to a Scala method. This also registers that the given method is called by the current method in the method info builder.
Gen JS code for a call to a Scala method.
Gen JS code for a call to a Scala method. This also registers that the given method is called by the current method in the method info builder.
Gen JS code for an array literal.
Gen JS code for an asInstanceOf cast (for reference types only)
Gen the IR ClassDef for a class definition (maybe a module class).
Gen definitions for the fields of a class.
Gen definitions for the fields of a class. The fields are initialized with the zero of their types.
Gen JS code for a conversion between primitive value types
Gen JS code for a call to Any.==
Gen JS code for a tree in expression position (in the IR).
Gen the IR ClassDef for an implementation class (of a trait).
Gen the IR ClassDef for an interface definition.
Gen JS code for an isInstanceOf test (for reference types only)
Gen JS code for LabelDef The only LabelDefs that can reach here are the desugaring of while and do..while loops.
Gen JS code for LabelDef The only LabelDefs that can reach here are the desugaring of while and do..while loops. All other LabelDefs (for tail calls or matches) are caught upstream and transformed in ad hoc ways.
So here we recognize all the possible forms of trees that can result of while or do..while loops, and we reconstruct the loop for emission to JS.
Generate loading of a module value Can be given either the module symbol, or its module class symbol.
Gen JS code for a Match, i.e., a switch-able pattern match Eventually, this is compiled into a JS switch construct.
Gen JS code for a Match, i.e., a switch-able pattern match
Eventually, this is compiled into a JS switch construct. But because
we can be in expression position, and a JS switch cannot be given a
meaning in expression position, we emit a JS "match" construct (which
does not need the break
s in each case. JSDesugaring
will transform
that in a switch.
Some caveat here. It may happen that there is a guard in here, despite the fact that switches cannot have guards (in the JVM nor in JS). The JVM backend emits a jump to the default clause when a guard is not fulfilled. We cannot do that. Instead, currently we duplicate the body of the default case in the else branch of the guard test.
Generate exporter methods for a class
Generate exporter methods for a class
symbol of class we export for
symbols exporter methods that have been encountered in the class' tree. This is not the same as classSym.info.delcs since inherited concrete methods from traits should be in this param, too
Generates the MethodDef of a (non-constructor) method
Generates the MethodDef of a (non-constructor) method
Most normal methods are emitted straightforwardly. If the result type is Unit, then the body is emitted as a statement. Otherwise, it is emitted as an expression.
The additional complexity of this method handles the transformation of
a peculiarity of recursive tail calls: the local ValDef that replaces
this
.
Gen JS code for a method definition in a class or in an impl class.
Gen JS code for a method definition in a class or in an impl class.
On the JS side, method names are mangled to encode the full signature
of the Scala method, as described in JSEncoding
, to support
overloading.
Some methods are not emitted at all: * Primitives, since they are never actually called * Abstract methods * Constructors of hijacked classes * Trivial constructors, which only call their super constructor, with the same signature, and the same arguments. The JVM needs these constructors, but not JavaScript. Since there are lots of them, we take the trouble of recognizing and removing them.
Constructors are emitted by generating their body as a statement, then
return this
.
Other (normal) methods are emitted with genMethodBody()
.
Generate the exporter proxy for a named export
Generate the exporter proxy for a named export
Gen JS code for a call to a Scala class constructor.
Gen JS code for a call to a Scala class constructor.
This also registers that the given class is instantiated by the current method, and that the given constructor is called, in the method info builder.
Gen JS code for creating a new Array: new Array[T](length)
For multidimensional arrays (dimensions > 1), the arguments can
specify up to dimensions
lengths for the first dimensions of the
array.
Gen the IR ClassDef for a raw JS class or trait.
Generates reflective proxy methods for methods in sym
Generates reflective proxy methods for methods in sym
Reflective calls don't depend on the return type, so it's hard to generate calls without using runtime reflection to list the methods. We generate a method to be used for reflective calls (without return type in the name).
There are cases where non-trivial overloads cause ambiguous situations:
object A { def foo(x: Option[Int]): String def foo(x: Option[String]): Int }
This is completely legal code, but due to the same erased parameter type of the
foo
overloads, they cannot be disambiguated in a reflective call, as the exact return type is unknown at the call site.
Cases like the upper currently fail on the JVM backend at runtime. The Scala.js backend uses the following rules for selection (which will also cause runtime failures):
- If a proxy with the same signature (method name and parameters) exists in the superclass, no proxy is generated (proxy is inherited) - If no proxy exists in the superclass, a proxy is generated for the first method with matching signatures.
foo }}} reflective call, as the exact return type is unknown at the call site.
Cases like the upper currently fail on the JVM backend at runtime. The Scala.js backend uses the following rules for selection (which will also cause runtime failures):
- If a proxy with the same signature (method name and parameters) exists in the superclass, no proxy is generated (proxy is inherited) - If no proxy exists in the superclass, a proxy is generated for the first method with matching signatures.
Gen JS code for a tree in statement position (in the IR).
Gen JS code for a tree in statement or expression position (in the IR).
Gen JS code for a tree in statement or expression position (in the IR).
This is the main transformation method. Each node of the Scala AST is transformed into an equivalent portion of the JS AST.
Gen JS code for a translated match
Gen JS code for a translated match
This implementation relies heavily on the patterns of trees emitted by the current pattern match phase (as of Scala 2.10).
The trees output by the pattern matcher are assumed to follow these
rules:
* Each case LabelDef (in cases
) must not take any argument.
* The last one must be a catch-all (case _ =>) that never falls through.
* Jumps to the matchEnd
are allowed anywhere in the body of the
corresponding case label-defs, but not outside.
* Jumps to case label-defs are restricted to jumping to the very next
case, and only in positions denoted by <jump> in:
<case-body> ::=
If(_, <case-body>, <case-body>)
| Block(_, <case-body>)
| <jump>
| _
These restrictions, together with the fact that we are in statement
position (thanks to the above transformation), mean that they can be
simply replaced by skip
.
To implement jumps to matchEnd
, which have one argument which is the
result of the match, we enclose all the cases in one big labeled block.
Jumps are then compiled as return
s out of the block.
Gen JS code for a try..catch or try..finally block
Gen JS code for a try..catch or try..finally block
try..finally blocks are compiled straightforwardly to try..finally blocks of JS.
try..catch blocks are a bit more subtle, as JS does not have type-based selection of exceptions to catch. We thus encode explicitly the type tests, like in:
try { ... } catch (e) { if (e.isInstanceOf[IOException]) { ... } else if (e.isInstanceOf[Exception]) { ... } else { throw e; // default, re-throw } }
Generate a literal "zero" for the requested type
Gen a boxing operation (tpe is the primitive type)
Gen an unboxing operation (tpe is the primitive type)