[JS IR BE] Intrinsicify kotlin.js.js
This commit is contained in:
@@ -9,11 +9,13 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getFunctions
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.js.resolve.JsPlatform.builtIns
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.KotlinTypeFactory
|
||||
@@ -78,6 +80,7 @@ class JsIntrinsics(private val module: ModuleDescriptor, private val irBuiltIns:
|
||||
|
||||
val jsObjectCreate: IrSimpleFunction = defineObjectCreateIntrinsic()
|
||||
|
||||
val jsCode = module.getFunctions(FqName("kotlin.js.js")).singleOrNull()?.let { symbolTable.referenceFunction(it) }
|
||||
|
||||
// Helpers:
|
||||
|
||||
|
||||
+4
-4
@@ -98,15 +98,15 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
override fun visitCall(expression: IrCall, context: JsGenerationContext): JsExpression {
|
||||
val symbol = expression.symbol
|
||||
|
||||
context.staticContext.intrinsics[symbol]?.let {
|
||||
return it(expression, context)
|
||||
}
|
||||
|
||||
val dispatchReceiver = expression.dispatchReceiver?.accept(this, context)
|
||||
val extensionReceiver = expression.extensionReceiver?.accept(this, context)
|
||||
|
||||
val arguments = translateCallArguments(expression, context)
|
||||
|
||||
context.staticContext.intrinsics[symbol]?.let {
|
||||
return it(expression, arguments)
|
||||
}
|
||||
|
||||
return if (symbol is IrConstructorSymbol) {
|
||||
JsNew(JsNameRef((symbol.owner.parent as IrClass).name.asString()), arguments)
|
||||
} else {
|
||||
|
||||
+27
-4
@@ -6,13 +6,14 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIntrinsics
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
|
||||
typealias IrCallTransformer = (IrCall, List<JsExpression>) -> JsExpression
|
||||
typealias IrCallTransformer = (IrCall, context: JsGenerationContext) -> JsExpression
|
||||
|
||||
class JsIntrinsicTransformers(intrinsics: JsIntrinsics) {
|
||||
private val transformers: Map<IrSymbol, IrCallTransformer>
|
||||
@@ -64,6 +65,16 @@ class JsIntrinsicTransformers(intrinsics: JsIntrinsics) {
|
||||
JsInvocation(Namer.JS_OBJECT_CREATE_FUNCTION, prototype)
|
||||
|
||||
}
|
||||
|
||||
addIfNotNull(intrinsics.jsCode) { call, context ->
|
||||
val jsCode = translateJsCode(call, context.currentScope)
|
||||
|
||||
when (jsCode) {
|
||||
is JsExpression -> jsCode
|
||||
// TODO don't generate function for this case
|
||||
else -> JsInvocation(JsFunction(context.currentScope, jsCode as? JsBlock ?: JsBlock(jsCode as JsStatement), ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,14 +85,26 @@ private fun MutableMap<IrSymbol, IrCallTransformer>.add(function: IrFunction, t:
|
||||
put(function.symbol, t)
|
||||
}
|
||||
|
||||
private fun MutableMap<IrSymbol, IrCallTransformer>.addIfNotNull(symbol: IrSymbol?, t: IrCallTransformer) {
|
||||
if (symbol == null) return
|
||||
put(symbol, t)
|
||||
}
|
||||
|
||||
private fun MutableMap<IrSymbol, IrCallTransformer>.binOp(function: IrFunction, op: JsBinaryOperator) {
|
||||
put(function.symbol, { _, args -> JsBinaryOperation(op, args[0], args[1]) })
|
||||
withTranslatedArgs(function) { JsBinaryOperation(op, it[0], it[1]) }
|
||||
}
|
||||
|
||||
private fun MutableMap<IrSymbol, IrCallTransformer>.prefixOp(function: IrFunction, op: JsUnaryOperator) {
|
||||
put(function.symbol, { _, args -> JsPrefixOperation(op, args[0]) })
|
||||
withTranslatedArgs(function) { JsPrefixOperation(op, it[0]) }
|
||||
}
|
||||
|
||||
private fun MutableMap<IrSymbol, IrCallTransformer>.postfixOp(function: IrFunction, op: JsUnaryOperator) {
|
||||
put(function.symbol, { _, args -> JsPostfixOperation(op, args[0]) })
|
||||
withTranslatedArgs(function) { JsPostfixOperation(op, it[0]) }
|
||||
}
|
||||
|
||||
private inline fun MutableMap<IrSymbol, IrCallTransformer>.withTranslatedArgs(
|
||||
function: IrFunction,
|
||||
crossinline t: (List<JsExpression>) -> JsExpression
|
||||
) {
|
||||
put(function.symbol) { call, context -> t(translateCallArguments(call, context)) }
|
||||
}
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
|
||||
import com.google.gwt.dev.js.ThrowExceptionOnErrorReporter
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.parser.parse
|
||||
|
||||
fun translateJsCode(call: IrCall, scope: JsScope): JsNode {
|
||||
//TODO check non simple compile time constants (expressions)
|
||||
|
||||
val arg = call.getValueArgument(0) as? IrConst<*>
|
||||
val kind = arg?.kind as? IrConstKind.String ?: error("Parameter of js function must be compile time String constant")
|
||||
|
||||
val statements = parseJsCode(kind.valueOf(arg), JsFunctionScope(scope, "<js-code>")).orEmpty()
|
||||
val size = statements.size
|
||||
|
||||
return when (size) {
|
||||
0 -> JsEmpty
|
||||
1 -> statements[0].let { if (it is JsExpressionStatement) it.expression else it }
|
||||
else -> JsBlock(statements)
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseJsCode(jsCode: String, currentScope: JsScope): List<JsStatement>? {
|
||||
// Parser can change local or global scope.
|
||||
// In case of js we want to keep new local names,
|
||||
// but no new global ones.
|
||||
assert(currentScope is JsFunctionScope) { "Usage of js outside of function is unexpected" }
|
||||
val temporaryRootScope = JsRootScope(JsProgram())
|
||||
val scope = DelegatingJsFunctionScopeWithTemporaryParent(currentScope as JsFunctionScope, temporaryRootScope)
|
||||
|
||||
// TODO write debug info, see how it's done in CallExpressionTranslator.parseJsCode
|
||||
|
||||
return parse(jsCode, ThrowExceptionOnErrorReporter, scope, "<js-code>")
|
||||
}
|
||||
+14
-1
@@ -6,7 +6,12 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.utils
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
val IrFunctionSymbol.kind get() = descriptor.kind
|
||||
|
||||
@@ -26,4 +31,12 @@ val IrClassSymbol.kind get() = descriptor.kind
|
||||
|
||||
val IrClassSymbol.modality get() = descriptor.modality
|
||||
|
||||
val IrClassSymbol.isAny get() = KotlinBuiltIns.isAny(descriptor)
|
||||
val IrClassSymbol.isAny get() = KotlinBuiltIns.isAny(descriptor)
|
||||
|
||||
fun ModuleDescriptor.getFunctions(fqName: FqName): List<FunctionDescriptor> {
|
||||
return getFunctions(fqName.parent(), fqName.shortName())
|
||||
}
|
||||
|
||||
fun ModuleDescriptor.getFunctions(packageFqName: FqName, name: Name): List<FunctionDescriptor> {
|
||||
return getPackage(packageFqName).memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND).toList()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user