@@ -1184,9 +1184,9 @@ class JSCodeGen()(implicit ctx: Context) {
1184
1184
genCoercion(tree, receiver, code)
1185
1185
else if (code == JSPrimitives .THROW )
1186
1186
genThrow(tree, args)
1187
- else /* if (primitives .isJSPrimitive(code))
1188
- genJSPrimitive(tree, receiver, args, code)
1189
- else*/
1187
+ else if (JSPrimitives .isJSPrimitive(code))
1188
+ genJSPrimitive(tree, args, code, isStat )
1189
+ else
1190
1190
throw new FatalError (s " Unknown primitive: ${tree.symbol.fullName} at: $pos" )
1191
1191
}
1192
1192
@@ -2199,6 +2199,171 @@ class JSCodeGen()(implicit ctx: Context) {
2199
2199
}
2200
2200
}
2201
2201
2202
+ /** Gen JS code for a Scala.js-specific primitive method */
2203
+ private def genJSPrimitive (tree : Apply , args : List [Tree ], code : Int ,
2204
+ isStat : Boolean ): js.Tree = {
2205
+
2206
+ import JSPrimitives ._
2207
+
2208
+ implicit val pos = tree.span
2209
+
2210
+ def genArgs1 : js.Tree = {
2211
+ assert(args.size == 1 ,
2212
+ s " Expected exactly 1 argument for JS primitive $code but got " +
2213
+ s " ${args.size} at $pos" )
2214
+ genExpr(args.head)
2215
+ }
2216
+
2217
+ def genArgs2 : (js.Tree , js.Tree ) = {
2218
+ assert(args.size == 2 ,
2219
+ s " Expected exactly 2 arguments for JS primitive $code but got " +
2220
+ s " ${args.size} at $pos" )
2221
+ (genExpr(args.head), genExpr(args.tail.head))
2222
+ }
2223
+
2224
+ def genArgsVarLength : List [js.TreeOrJSSpread ] =
2225
+ genActualJSArgs(tree.symbol, args)
2226
+
2227
+ def resolveReifiedJSClassSym (arg : Tree ): Symbol = {
2228
+ def fail (): Symbol = {
2229
+ ctx.error(
2230
+ tree.symbol.name.toString + " must be called with a constant " +
2231
+ " classOf[T] representing a class extending js.Any " +
2232
+ " (not a trait nor an object)" ,
2233
+ tree.sourcePos)
2234
+ NoSymbol
2235
+ }
2236
+ arg match {
2237
+ case Literal (value) if value.tag == Constants .ClazzTag =>
2238
+ val classSym = value.typeValue.typeSymbol
2239
+ if (isJSType(classSym) && ! classSym.is(Trait ) && ! classSym.is(ModuleClass ))
2240
+ classSym
2241
+ else
2242
+ fail()
2243
+ case _ =>
2244
+ fail()
2245
+ }
2246
+ }
2247
+
2248
+ (code : @ switch) match {
2249
+ case DYNNEW =>
2250
+ // js.Dynamic.newInstance(clazz)(actualArgs: _*)
2251
+ val (jsClass, actualArgs) = extractFirstArg(genArgsVarLength)
2252
+ js.JSNew (jsClass, actualArgs)
2253
+
2254
+ case ARR_CREATE =>
2255
+ // js.Array(elements: _*)
2256
+ js.JSArrayConstr (genArgsVarLength)
2257
+
2258
+ case CONSTRUCTOROF =>
2259
+ // runtime.constructorOf(clazz)
2260
+ val classSym = resolveReifiedJSClassSym(args.head)
2261
+ if (classSym == NoSymbol )
2262
+ js.Undefined () // compile error emitted by resolveReifiedJSClassSym
2263
+ else
2264
+ genLoadJSConstructor(classSym)
2265
+
2266
+ /*
2267
+ case CREATE_INNER_JS_CLASS | CREATE_LOCAL_JS_CLASS =>
2268
+ // runtime.createInnerJSClass(clazz, superClass)
2269
+ // runtime.createLocalJSClass(clazz, superClass, fakeNewInstances)
2270
+ val classSym = resolveReifiedJSClassSym(args(0))
2271
+ val superClassValue = genExpr(args(1))
2272
+ if (classSym == NoSymbol) {
2273
+ js.Undefined() // compile error emitted by resolveReifiedJSClassSym
2274
+ } else {
2275
+ val captureValues = {
2276
+ if (code == CREATE_INNER_JS_CLASS) {
2277
+ val outer = genThis()
2278
+ List.fill(classSym.info.decls.count(_.isClassConstructor))(outer)
2279
+ } else {
2280
+ val ArrayValue(_, fakeNewInstances) = args(2)
2281
+ fakeNewInstances.flatMap(genCaptureValuesFromFakeNewInstance(_))
2282
+ }
2283
+ }
2284
+ js.CreateJSClass(encodeClassRef(classSym),
2285
+ superClassValue :: captureValues)
2286
+ }
2287
+
2288
+ case WITH_CONTEXTUAL_JS_CLASS_VALUE =>
2289
+ // withContextualJSClassValue(jsclass, inner)
2290
+ val jsClassValue = genExpr(args(0))
2291
+ withScopedVars(
2292
+ contextualJSClassValue := Some(jsClassValue)
2293
+ ) {
2294
+ genStatOrExpr(args(1), isStat)
2295
+ }
2296
+ */
2297
+
2298
+ case LINKING_INFO =>
2299
+ // runtime.linkingInfo
2300
+ js.JSLinkingInfo ()
2301
+
2302
+ case DEBUGGER =>
2303
+ // js.special.debugger()
2304
+ js.Debugger ()
2305
+
2306
+ case UNITVAL =>
2307
+ // BoxedUnit.UNIT, which is the boxed version of ()
2308
+ js.Undefined ()
2309
+
2310
+ case JS_NATIVE =>
2311
+ // js.native
2312
+ ctx.error(
2313
+ " js.native may only be used as stub implementation in facade types" ,
2314
+ tree.sourcePos)
2315
+ js.Undefined ()
2316
+
2317
+ case TYPEOF =>
2318
+ // js.typeOf(arg)
2319
+ val arg = genArgs1
2320
+ genAsInstanceOf(js.JSUnaryOp (js.JSUnaryOp .typeof, arg), defn.StringType )
2321
+
2322
+ case IN =>
2323
+ // js.special.in(arg1, arg2)
2324
+ val (arg1, arg2) = genArgs2
2325
+ js.Unbox (js.JSBinaryOp (js.JSBinaryOp .in, arg1, arg2), 'Z' )
2326
+
2327
+ case INSTANCEOF =>
2328
+ // js.special.instanceof(arg1, arg2)
2329
+ val (arg1, arg2) = genArgs2
2330
+ js.Unbox (js.JSBinaryOp (js.JSBinaryOp .instanceof, arg1, arg2), 'Z' )
2331
+
2332
+ case DELETE =>
2333
+ // js.special.delete(arg1, arg2)
2334
+ val (arg1, arg2) = genArgs2
2335
+ js.JSDelete (js.JSBracketSelect (arg1, arg2))
2336
+
2337
+ case FORIN =>
2338
+ /* js.special.forin(arg1, arg2)
2339
+ *
2340
+ * We must generate:
2341
+ *
2342
+ * val obj = arg1
2343
+ * val f = arg2
2344
+ * for (val key in obj) {
2345
+ * f(key)
2346
+ * }
2347
+ *
2348
+ * with temporary vals, because `arg2` must be evaluated only
2349
+ * once, and after `arg1`.
2350
+ */
2351
+ val (arg1, arg2) = genArgs2
2352
+ val objVarDef = js.VarDef (freshLocalIdent(" obj" ), jstpe.AnyType ,
2353
+ mutable = false , arg1)
2354
+ val fVarDef = js.VarDef (freshLocalIdent(" f" ), jstpe.AnyType ,
2355
+ mutable = false , arg2)
2356
+ val keyVarIdent = freshLocalIdent(" key" )
2357
+ val keyVarRef = js.VarRef (keyVarIdent)(jstpe.AnyType )
2358
+ js.Block (
2359
+ objVarDef,
2360
+ fVarDef,
2361
+ js.ForIn (objVarDef.ref, keyVarIdent, {
2362
+ js.JSFunctionApply (fVarDef.ref, List (keyVarRef))
2363
+ }))
2364
+ }
2365
+ }
2366
+
2202
2367
/** Gen actual actual arguments to Scala method call.
2203
2368
* Returns a list of the transformed arguments.
2204
2369
*
0 commit comments