@@ -34,7 +34,6 @@ import org.jetbrains.kotlinx.dataframe.codeGen.TypeCastGenerator
3434import org.jetbrains.kotlinx.dataframe.codeGen.ValidFieldName
3535import org.jetbrains.kotlinx.dataframe.codeGen.toNullable
3636import org.jetbrains.kotlinx.dataframe.columns.ColumnGroup
37- import org.jetbrains.kotlinx.dataframe.columns.ColumnPath
3837import org.jetbrains.kotlinx.dataframe.impl.toSnakeCase
3938import org.jetbrains.kotlinx.dataframe.keywords.HardKeywords
4039import org.jetbrains.kotlinx.dataframe.keywords.ModifierKeywords
@@ -502,83 +501,131 @@ internal class CodeGeneratorImpl(typeRendering: TypeRenderingStrategy = FullyQua
502501 nestedMarkerNameProvider,
503502 )
504503 val marker = context.process(schema, isOpen, visibility)
505- val declarations = mutableListOf<Code >()
506- context.generatedMarkers.forEach { itMarker ->
507- val declaration = if (asDataClass) {
508- generateClasses(itMarker)
509- } else {
510- generateInterface(itMarker, fields, readDfMethod.takeIf { marker == itMarker })
511- }
512- declarations.add(declaration)
513- if (extensionProperties) {
504+ // see [org.jetbrains.kotlinx.dataframe.codeGen.MatchSchemeTests.marker is reused]
505+ val code = if (extensionProperties) {
506+ val declarations = mutableListOf<Code >()
507+ context.generatedMarkers.forEach { itMarker ->
508+ val declaration = if (asDataClass) {
509+ generateClasses(itMarker)
510+ } else {
511+ generateInterface(itMarker, fields, readDfMethod = readDfMethod.takeIf { marker == itMarker })
512+ }
513+ declarations.add(declaration)
514514 declarations.add(generateExtensionProperties(itMarker, withNullable = false ))
515515 }
516+ createCodeWithTypeCastGenerator(declarations.joinToString(" \n\n " ), marker.name)
517+ } else if (context.generatedMarkers.isEmpty()) {
518+ createCodeWithTypeCastGenerator(" " , marker.name)
519+ } else {
520+ val nested = context.generatedMarkers.filterNot { it == marker }
521+ .map { itMarker ->
522+ if (asDataClass) {
523+ generateClasses(itMarker)
524+ } else {
525+ generateInterface(itMarker, fields)
526+ }
527+ }
528+
529+ val rootDeclaration = if (asDataClass) {
530+ generateClasses(marker, nested, readDfMethod)
531+ } else {
532+ generateInterface(marker, fields, nested, readDfMethod)
533+ }
534+ createCodeWithTypeCastGenerator(rootDeclaration, marker.name)
516535 }
517- val code = createCodeWithTypeCastGenerator(declarations.joinToString( " \n\n " ), marker.name)
536+
518537 return CodeGenResult (code, context.generatedMarkers)
519538 }
520539
521- private fun generateInterface (marker : Marker , fields : Boolean , readDfMethod : DefaultReadDfMethod ? = null): Code {
540+ private fun generateInterface (
541+ marker : Marker ,
542+ fields : Boolean ,
543+ nested : List <Code > = emptyList(),
544+ readDfMethod : DefaultReadDfMethod ? = null,
545+ ): Code {
522546 val annotationName = DataSchema ::class .simpleName
523-
524547 val visibility = renderTopLevelDeclarationVisibility(marker)
525548 val propertyVisibility = renderInternalDeclarationVisibility(marker)
526549
527550 val header =
528551 " @$annotationName${if (marker.isOpen) " " else " (isOpen = false)" } \n ${visibility} interface ${marker.name} "
529- val baseInterfacesDeclaration =
530- if (marker.superMarkers.isNotEmpty()) {
531- " : " + marker.superMarkers
532- .map { it.value.name + it.value.typeArguments }
533- .joinToString()
534- } else {
535- " "
536- }
537- val resultDeclarations = mutableListOf<String >()
538-
539- val fieldsDeclaration = if (fields) renderFields(marker, propertyVisibility).join() else " "
552+ val baseInterfaces = if (marker.superMarkers.isNotEmpty()) {
553+ " : " + marker.superMarkers.values.joinToString { it.name + it.typeArguments }
554+ } else {
555+ " "
556+ }
540557
541- val readDfMethodDeclaration = readDfMethod?.toDeclaration( marker, propertyVisibility)
558+ val fieldsCode = ( if (fields) renderFields( marker, propertyVisibility) else emptyList()).joinToString( " \n " )
542559
543- val body = if (fieldsDeclaration.isNotBlank () || readDfMethodDeclaration?.isNotBlank () == true ) {
560+ val body = if (fieldsCode.isNotEmpty () || nested.isNotEmpty () || readDfMethod != null ) {
544561 buildString {
545562 append(" {\n " )
546- append(fieldsDeclaration)
547- if (readDfMethodDeclaration != null ) {
548- append(" \n " )
549- val companionObject = buildCodeBlock {
550- add(" " )
551- indent()
552- indent()
553- add(readDfMethodDeclaration)
554- }
555- append(companionObject.toString())
556- }
563+ appendNestedDeclarations(
564+ fieldsCode = fieldsCode.takeIf { it.isNotEmpty() },
565+ nestedDeclarationsCode = nested,
566+ readDfMethod?.let { renderReadDfMethod(it, marker, propertyVisibility) },
567+ )
557568 append(" \n }" )
558569 }
559570 } else {
560571 " { }"
561572 }
562- resultDeclarations.add(header + baseInterfacesDeclaration + body)
563- return resultDeclarations.join()
573+ return header + baseInterfaces + body
564574 }
565575
566- private fun generateClasses (marker : Marker ): Code {
576+ private fun generateClasses (
577+ marker : Marker ,
578+ nested : List <Code > = emptyList(),
579+ readDfMethod : DefaultReadDfMethod ? = null,
580+ ): Code {
567581 val annotationName = DataSchema ::class .simpleName
568-
569582 val visibility = renderTopLevelDeclarationVisibility(marker)
570583 val propertyVisibility = renderInternalDeclarationVisibility(marker)
571- val header =
572- " @$annotationName \n ${visibility} data class ${marker.name} ("
573584
574- val fieldsDeclaration = renderFields(marker, propertyVisibility).joinToString(" ,\n " )
585+ val header = " @$annotationName \n ${visibility} data class ${marker.name} ("
586+ val fieldsCode = renderFields(marker, propertyVisibility).joinToString(" ,\n " )
587+
575588 return buildString {
576589 appendLine(header)
577- appendLine(fieldsDeclaration )
590+ appendLine(fieldsCode )
578591 append(" )" )
592+
593+ if (nested.isNotEmpty() || readDfMethod != null ) {
594+ append(" {\n " )
595+ appendNestedDeclarations(
596+ fieldsCode = null ,
597+ nested,
598+ readDfMethod?.let {
599+ renderReadDfMethod(it, marker, propertyVisibility)
600+ },
601+ )
602+ append(" \n }" )
603+ }
579604 }
580605 }
581606
607+ private fun StringBuilder.appendNestedDeclarations (
608+ fieldsCode : Code ? = null,
609+ nestedDeclarationsCode : List <Code >,
610+ readDfMethodCode : Code ? ,
611+ ) {
612+ val contents = mutableListOf<String >()
613+
614+ if (fieldsCode != null ) {
615+ contents + = fieldsCode
616+ }
617+
618+ if (nestedDeclarationsCode.isNotEmpty()) {
619+ contents + = nestedDeclarationsCode.joinToString(" \n\n " ) { it.prependIndent(" " ) }
620+ }
621+
622+ if (readDfMethodCode != null ) {
623+ contents + = readDfMethodCode
624+ }
625+
626+ append(contents.joinToString(" \n\n " ))
627+ }
628+
582629 private fun renderFields (marker : Marker , propertyVisibility : String ): List <String > =
583630 marker.fields.map {
584631 val override = if (it.overrides) " override " else " "
@@ -591,6 +638,14 @@ internal class CodeGeneratorImpl(typeRendering: TypeRenderingStrategy = FullyQua
591638 val fieldType = it.renderFieldType()
592639 " $columnNameAnnotation ${propertyVisibility}${override } val ${it.fieldName.quotedIfNeeded} : $fieldType "
593640 }
641+
642+ private fun renderReadDfMethod (readDfMethod : DefaultReadDfMethod , marker : Marker , propertyVisibility : String ) =
643+ buildCodeBlock {
644+ add(" " )
645+ indent()
646+ indent()
647+ add(readDfMethod.toDeclaration(marker, propertyVisibility))
648+ }.toString()
594649}
595650
596651public fun CodeWithTypeCastGenerator.toStandaloneSnippet (packageName : String , additionalImports : List <String >): String =
0 commit comments