[JS IR BE] Implement vararg in JS BE

This commit is contained in:
Roman Artemev
2018-05-10 15:03:37 +03:00
parent 84447d59e1
commit 6d29aab5e2
3 changed files with 91 additions and 0 deletions
@@ -526,6 +526,47 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : FunctionLowerin
return KeptResult
}
override fun visitVararg(expression: IrVararg, data: VisitData): VisitResult {
var decomposed = 0
val arguments = expression.elements.map {
val expr = (it as? IrSpreadElement)?.expression ?: it as IrExpression
Pair(it, expr.accept(this, data).applyIfChanged { decomposed++ })
}
if (decomposed == 0) return KeptResult
val newStatements = mutableListOf<IrStatement>()
val newArguments = arguments.map { (original, result) ->
if (decomposed == 0) original
else {
val originalExpression = (original as? IrSpreadElement)?.expression ?: original as IrExpression
val newExpression = result.runIfChangedOrDefault(originalExpression) {
newStatements += statements
decomposed--
resultValue
}
val wrapVar = makeTempVar(expression.varargElementType)
newStatements += JsIrBuilder.buildVar(wrapVar).apply { initializer = newExpression }
val newValue = JsIrBuilder.buildGetValue(wrapVar)
if (original is IrSpreadElement) {
IrSpreadElementImpl(original.startOffset, original.endOffset, newValue)
} else {
newValue
}
}
}
val newExpression = IrVarargImpl(
expression.startOffset,
expression.endOffset,
expression.type,
expression.varargElementType,
newArguments)
return DecomposedResult(newStatements, newExpression)
}
override fun visitStringConcatenation(expression: IrStringConcatenation, data: VisitData): VisitResult {
var decomposed = 0
@@ -19,6 +19,53 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsExpression, JsGenerationContext> {
override fun visitVararg(expression: IrVararg, context: JsGenerationContext): JsExpression {
// TODO: perform the dark magic below in the separated lowering
if (expression.elements.size == 1) {
val element = expression.elements[0]
if (element is IrSpreadElement) {
// special case, invoke slice()
val expr = element.expression.accept(this, context)
return JsInvocation(JsNameRef(Namer.SLICE_FUNCTION, expr))
}
}
var arrayLiteralElements = mutableListOf<JsExpression>()
val concatArguments = mutableListOf<JsExpression>()
var qualifier: JsExpression? = null
expression.elements.forEach {
if (it is IrSpreadElement) {
val expr = it.expression.accept(this, context)
if (qualifier == null) {
if (arrayLiteralElements.isEmpty()) {
qualifier = JsNameRef(Namer.CONCAT_FUNCTION, expr)
} else {
val dispatch = JsArrayLiteral(arrayLiteralElements)
arrayLiteralElements = mutableListOf()
qualifier = JsNameRef(Namer.CONCAT_FUNCTION, dispatch)
concatArguments.add(expr)
}
} else {
if (arrayLiteralElements.isNotEmpty()) {
concatArguments.add(JsArrayLiteral(arrayLiteralElements))
arrayLiteralElements = mutableListOf()
}
concatArguments.add(expr)
}
} else {
arrayLiteralElements.add(it.accept(this, context))
}
}
return qualifier?.let {
if (arrayLiteralElements.isNotEmpty()) {
concatArguments.add(JsArrayLiteral(arrayLiteralElements))
}
return JsInvocation(it, concatArguments)
} ?: JsArrayLiteral(arrayLiteralElements)
}
override fun visitExpressionBody(body: IrExpressionBody, context: JsGenerationContext): JsExpression =
body.expression.accept(this, context)
@@ -34,6 +34,9 @@ object Namer {
val CALL_FUNCTION = "call"
val APPLY_FUNCTION = "apply"
val SLICE_FUNCTION = "slice"
val CONCAT_FUNCTION = "concat"
val UNREACHABLE_NAME = "\$unreachable"
val OUTER_FIELD_NAME = "\$outer"