@@ -2,15 +2,106 @@ package io.github.reactivecircus.cocoon.compiler
22
33import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
44import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
5+ import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
6+ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
57import org.jetbrains.kotlin.cli.common.messages.MessageCollector
8+ import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
9+ import org.jetbrains.kotlin.ir.IrStatement
10+ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
11+ import org.jetbrains.kotlin.ir.builders.declarations.buildFun
12+ import org.jetbrains.kotlin.ir.builders.irBlock
13+ import org.jetbrains.kotlin.ir.builders.irCall
14+ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
15+ import org.jetbrains.kotlin.ir.declarations.IrFunction
16+ import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
17+ import org.jetbrains.kotlin.ir.declarations.createBlockBody
18+ import org.jetbrains.kotlin.ir.expressions.IrExpression
19+ import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
20+ import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionExpressionImpl
21+ import org.jetbrains.kotlin.ir.symbols.UnsafeDuringIrConstructionAPI
22+ import org.jetbrains.kotlin.ir.types.IrType
23+ import org.jetbrains.kotlin.ir.util.dump
24+ import org.jetbrains.kotlin.ir.util.hasAnnotation
25+ import org.jetbrains.kotlin.ir.util.statements
626import org.jetbrains.kotlin.name.CallableId
727import org.jetbrains.kotlin.name.ClassId
28+ import org.jetbrains.kotlin.name.SpecialNames
829
930internal class CocoonFunctionTransformer (
1031 private val pluginContext : IrPluginContext ,
1132 private val messageCollector : MessageCollector ,
12- private val annotationName : ClassId ,
13- private val wrappingFunctionName : CallableId ,
33+ private val annotation : ClassId ,
34+ private val wrappingFunction : CallableId ,
1435) : IrElementTransformerVoidWithContext() {
1536
37+ @OptIn(UnsafeDuringIrConstructionAPI ::class )
38+ override fun visitFunctionNew (declaration : IrFunction ): IrStatement {
39+ if (! declaration.hasAnnotation(annotation) || declaration.body == null ) {
40+ return super .visitFunctionNew(declaration)
41+ }
42+
43+ // TODO check for $composer and report error
44+
45+ val originalBody = declaration.body!!
46+
47+ declaration.body = pluginContext.irFactory.createBlockBody(
48+ startOffset = originalBody.startOffset,
49+ endOffset = originalBody.endOffset,
50+ ).apply {
51+ val wrappingFunction = pluginContext.referenceFunctions(wrappingFunction).single()
52+ val irBuilder = DeclarationIrBuilder (pluginContext, declaration.symbol)
53+
54+ // TODO move up and check early:
55+ // - must have at least 1 param
56+ // - last must be kotlin.Function0<kotlin.Unit>)
57+ // - move to FIR?
58+ val wrappingFunctionParameters = wrappingFunction.owner.parameters
59+
60+ statements.add(
61+ irBuilder.irBlock {
62+ + irCall(wrappingFunction).apply {
63+ val lambdaExpression = pluginContext.createLambdaIrFunctionExpression(
64+ lambdaReturnType = wrappingFunctionParameters.last().type,
65+ ) {
66+ parent = declaration
67+ body = pluginContext.irFactory.createBlockBody(
68+ startOffset,
69+ endOffset,
70+ originalBody.statements,
71+ )
72+ }
73+ arguments[wrappingFunctionParameters.size - 1 ] = lambdaExpression
74+ }
75+ }
76+ )
77+ }
78+
79+ log(" Transformed function IR: \n ${declaration.dump()} " )
80+
81+ return super .visitFunctionNew(declaration)
82+ }
83+
84+ private fun IrPluginContext.createLambdaIrFunctionExpression (
85+ lambdaReturnType : IrType ,
86+ block : IrSimpleFunction .() -> Unit = {},
87+ ): IrExpression {
88+ val lambda = irFactory.buildFun {
89+ name = SpecialNames .ANONYMOUS
90+ origin = IrDeclarationOrigin .LOCAL_FUNCTION_FOR_LAMBDA
91+ visibility = DescriptorVisibilities .LOCAL
92+ returnType = lambdaReturnType
93+ }.apply (block)
94+
95+ return IrFunctionExpressionImpl (
96+ startOffset = UNDEFINED_OFFSET ,
97+ endOffset = UNDEFINED_OFFSET ,
98+ type = lambda.returnType,
99+ function = lambda,
100+ origin = IrStatementOrigin .LAMBDA ,
101+ )
102+ }
103+
104+ private fun log (message : String ) {
105+ messageCollector.report(CompilerMessageSeverity .LOGGING , " Cocoon Compiler Plugin (IR) - $message " )
106+ }
16107}
0 commit comments