Skip to content

Commit b23828a

Browse files
committed
[Compiler plugin] toDataFrame from support
1 parent b73bd04 commit b23828a

File tree

11 files changed

+392
-10
lines changed

11 files changed

+392
-10
lines changed

core/generated-sources/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/toDataFrame.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ public abstract class CreateDataFrameDsl<T> : TraversePropertiesDsl {
175175
public inline fun <reified R> add(name: String, noinline expression: (T) -> R): Unit =
176176
add(source.map { expression(it) }.toColumn(name, Infer.Nulls))
177177

178+
@Interpretable("ToDataFrameFrom0")
178179
public inline infix fun <reified R> String.from(noinline expression: (T) -> R): Unit =
179180
add(this, expression)
180181

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/toDataFrame.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ public abstract class CreateDataFrameDsl<T> : TraversePropertiesDsl {
175175
public inline fun <reified R> add(name: String, noinline expression: (T) -> R): Unit =
176176
add(source.map { expression(it) }.toColumn(name, Infer.Nulls))
177177

178+
@Interpretable("ToDataFrameFrom0")
178179
public inline infix fun <reified R> String.from(noinline expression: (T) -> R): Unit =
179180
add(this, expression)
180181

plugins/kotlin-dataframe/src/org/jetbrains/kotlinx/dataframe/plugin/analyzeRefinedCallShape.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.fir.types.ConeTypeProjection
2323
import org.jetbrains.kotlin.fir.types.classId
2424
import org.jetbrains.kotlin.fir.types.resolvedType
2525
import org.jetbrains.kotlin.name.Name
26+
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.CreateDataFrameDslImplApproximation
2627
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.PluginDataFrameSchema
2728

2829
fun KotlinTypeFacade.analyzeRefinedCallShape(call: FirFunctionCall, reporter: InterpretationErrorReporter): CallResult? {
@@ -43,17 +44,17 @@ fun KotlinTypeFacade.analyzeRefinedCallShape(call: FirFunctionCall, reporter: In
4344
val lambda = (list.arguments.singleOrNull() as? FirAnonymousFunctionExpression)?.anonymousFunction
4445
val statements = lambda?.body?.statements
4546
if (statements != null) {
46-
val receiver = CreateDataFrameConfiguration()
47-
statements.filterIsInstance<FirFunctionCall>().forEach { call ->
48-
val schemaProcessor = call.loadInterpreter() ?: return@forEach
47+
val receiver = CreateDataFrameDslImplApproximation()
48+
statements.filterIsInstance<FirFunctionCall>().forEach {
49+
val schemaProcessor = it.loadInterpreter() ?: return@forEach
4950
interpret(
50-
call,
51+
it,
5152
schemaProcessor,
52-
mapOf("dsl" to Interpreter.Success(receiver)),
53+
mapOf("dsl" to Interpreter.Success(receiver), "call" to Interpreter.Success(call)),
5354
reporter
5455
)
5556
}
56-
toDataFrame(receiver.maxDepth, call, receiver.traverseConfiguration)
57+
PluginDataFrameSchema(receiver.columns)
5758
} else {
5859
PluginDataFrameSchema(emptyList())
5960
}

plugins/kotlin-dataframe/src/org/jetbrains/kotlinx/dataframe/plugin/impl/api/insert.kt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package org.jetbrains.kotlinx.dataframe.plugin.impl.api
22

3+
import org.jetbrains.kotlin.fir.types.ConeKotlinType
4+
import org.jetbrains.kotlin.fir.types.ConeNullability
5+
import org.jetbrains.kotlin.fir.types.classId
6+
import org.jetbrains.kotlin.fir.types.isNullable
37
import org.jetbrains.kotlinx.dataframe.plugin.impl.AbstractInterpreter
48
import org.jetbrains.kotlinx.dataframe.plugin.impl.Arguments
59
import org.jetbrains.kotlinx.dataframe.plugin.impl.Present
@@ -13,6 +17,8 @@ import org.jetbrains.kotlinx.dataframe.impl.api.GenericColumnsToInsert
1317
import org.jetbrains.kotlinx.dataframe.impl.api.DataFrameLikeContainer
1418
import org.jetbrains.kotlinx.dataframe.impl.api.GenericColumnGroup
1519
import org.jetbrains.kotlinx.dataframe.impl.api.insertImplGenericContainer
20+
import org.jetbrains.kotlinx.dataframe.plugin.extensions.KotlinTypeFacade
21+
import org.jetbrains.kotlinx.dataframe.plugin.extensions.wrap
1622
import org.jetbrains.kotlinx.dataframe.plugin.impl.data.ColumnAccessorApproximation
1723
import org.jetbrains.kotlinx.dataframe.plugin.impl.data.ColumnPathApproximation
1824
import org.jetbrains.kotlinx.dataframe.plugin.impl.data.ColumnWithPathApproximation
@@ -28,6 +34,8 @@ import org.jetbrains.kotlinx.dataframe.plugin.impl.insertClause
2834
import org.jetbrains.kotlinx.dataframe.plugin.impl.kproperty
2935
import org.jetbrains.kotlinx.dataframe.plugin.impl.string
3036
import org.jetbrains.kotlinx.dataframe.plugin.impl.type
37+
import org.jetbrains.kotlinx.dataframe.plugin.pluginDataFrameSchema
38+
import org.jetbrains.kotlinx.dataframe.plugin.utils.Names
3139

3240
/**
3341
* @see DataFrame.insert
@@ -265,6 +273,34 @@ class SimpleColumnGroup(
265273
}
266274
}
267275

276+
fun KotlinTypeFacade.simpleColumnOf(name: String, type: ConeKotlinType): SimpleCol {
277+
return if (type.classId == Names.DATA_ROW_CLASS_ID) {
278+
val schema = pluginDataFrameSchema(type)
279+
val group = SimpleColumnGroup(name, schema.columns(), anyRow)
280+
val column = if (type.isNullable) {
281+
makeNullable(group)
282+
} else {
283+
group
284+
}
285+
column
286+
} else if (type.classId == Names.DF_CLASS_ID && type.nullability == ConeNullability.NOT_NULL) {
287+
val schema = pluginDataFrameSchema(type)
288+
SimpleFrameColumn(name, schema.columns(), anyDataFrame)
289+
} else {
290+
SimpleCol(name, type.wrap())
291+
}
292+
}
293+
294+
private fun KotlinTypeFacade.makeNullable(column: SimpleCol): SimpleCol {
295+
return when (column) {
296+
is SimpleColumnGroup -> {
297+
SimpleColumnGroup(column.name, column.columns().map { makeNullable(column) }, anyRow)
298+
}
299+
is SimpleFrameColumn -> column
300+
else -> SimpleCol(column.name, column.type.changeNullability { true })
301+
}
302+
}
303+
268304
@PublishedApi
269305
internal fun PluginDataFrameSchema.insertImpl(
270306
columns: List<GenericColumnsToInsert<SimpleCol>>,

plugins/kotlin-dataframe/src/org/jetbrains/kotlinx/dataframe/plugin/impl/api/toDataFrame.kt

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,21 @@ import org.jetbrains.kotlinx.dataframe.plugin.extensions.KotlinTypeFacade
4848
import org.jetbrains.kotlinx.dataframe.plugin.impl.AbstractInterpreter
4949
import org.jetbrains.kotlinx.dataframe.plugin.impl.Arguments
5050
import org.jetbrains.kotlinx.dataframe.plugin.impl.Interpreter
51+
import org.jetbrains.kotlinx.dataframe.plugin.impl.Present
52+
import org.jetbrains.kotlinx.dataframe.plugin.impl.type
5153
import java.util.*
5254

5355
class Properties0 : AbstractInterpreter<Unit>() {
54-
val Arguments.dsl: CreateDataFrameConfiguration by arg()
56+
val Arguments.dsl: CreateDataFrameDslImplApproximation by arg()
57+
val Arguments.call: FirFunctionCall by arg()
5558
val Arguments.maxDepth: Int by arg()
56-
val Arguments.body: (Any) -> Unit by arg(lens = Interpreter.Dsl)
59+
val Arguments.body: (Any) -> Unit by arg(lens = Interpreter.Dsl, defaultValue = Present(value = {}))
5760

5861
override fun Arguments.interpret() {
59-
dsl.maxDepth = maxDepth
60-
body(dsl.traverseConfiguration)
62+
dsl.configuration.maxDepth = maxDepth
63+
body(dsl.configuration.traverseConfiguration)
64+
val schema = toDataFrame(dsl.configuration.maxDepth, call, dsl.configuration.traverseConfiguration)
65+
dsl.columns.addAll(schema.columns())
6166
}
6267
}
6368

@@ -238,3 +243,17 @@ internal fun KotlinTypeFacade.toDataFrame(
238243
}
239244
}
240245
}
246+
247+
class CreateDataFrameDslImplApproximation {
248+
val configuration: CreateDataFrameConfiguration = CreateDataFrameConfiguration()
249+
val columns: MutableList<SimpleCol> = mutableListOf()
250+
}
251+
252+
class ToDataFrameFrom : AbstractInterpreter<Unit>() {
253+
val Arguments.dsl: CreateDataFrameDslImplApproximation by arg()
254+
val Arguments.receiver: String by arg()
255+
val Arguments.expression: TypeApproximation by type()
256+
override fun Arguments.interpret() {
257+
dsl.columns += simpleColumnOf(receiver, expression.type)
258+
}
259+
}

plugins/kotlin-dataframe/src/org/jetbrains/kotlinx/dataframe/plugin/interpret.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ fun <T> KotlinTypeFacade.interpret(
8686

8787
val defaultArguments = processor.expectedArguments.filter { it.defaultValue is Present }.map { it.name }.toSet()
8888
val actualArgsMap = refinedArguments.associateBy { it.name.identifier }.toSortedMap()
89+
val conflictingKeys = additionalArguments.keys intersect actualArgsMap.keys
90+
if (conflictingKeys.isNotEmpty()) {
91+
error("Conflicting keys: $conflictingKeys")
92+
}
8993
val expectedArgsMap = processor.expectedArguments
9094
.filterNot { it.name.startsWith("typeArg") }
9195
.associateBy { it.name }.toSortedMap().minus(additionalArguments.keys)

plugins/kotlin-dataframe/src/org/jetbrains/kotlinx/dataframe/plugin/loadInterpreter.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ import org.jetbrains.kotlin.fir.types.classId
6767
import org.jetbrains.kotlin.fir.types.coneType
6868
import org.jetbrains.kotlin.name.ClassId
6969
import org.jetbrains.kotlin.name.Name
70+
import org.jetbrains.kotlinx.dataframe.plugin.impl.api.ToDataFrameFrom
7071

7172
internal fun FirFunctionCall.loadInterpreter(session: FirSession): Interpreter<*>? {
7273
val symbol =
@@ -159,6 +160,7 @@ internal inline fun <reified T> String.load(): T {
159160
"ReadJsonStr" -> ReadJsonStr()
160161
"ReadDelimStr" -> ReadDelimStr()
161162
"GroupByToDataFrame" -> GroupByToDataFrame()
163+
"ToDataFrameFrom0" -> ToDataFrameFrom()
162164
else -> error("$this")
163165
} as T
164166
}

0 commit comments

Comments
 (0)