Skip to content

Commit

Permalink
Merge pull request #158 from ephemient/kt/ksp
Browse files Browse the repository at this point in the history
  • Loading branch information
ephemient authored Dec 26, 2024
2 parents ffce364 + 7ebcbed commit 2e22bf1
Show file tree
Hide file tree
Showing 10 changed files with 180 additions and 33 deletions.
3 changes: 2 additions & 1 deletion kt/aoc2024-exe/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import org.gradle.internal.extensions.stdlib.capitalized
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree

plugins {
Expand Down Expand Up @@ -99,7 +100,7 @@ kotlin {

val detektTaskNames = targets.flatMap { target ->
target.compilations.map { compilation ->
"detekt${target.targetName.capitalize()}${compilation.compilationName.capitalize()}"
"detekt${target.targetName.capitalized()}${compilation.compilationName.capitalized()}"
}
}
tasks.check {
Expand Down
15 changes: 14 additions & 1 deletion kt/aoc2024-lib/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import com.google.devtools.ksp.gradle.KspAATask
import com.google.devtools.ksp.gradle.KspTaskNative
import org.gradle.internal.extensions.stdlib.capitalized
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget

plugins {
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.ksp)
alias(libs.plugins.detekt)
}

Expand Down Expand Up @@ -73,7 +79,7 @@ kotlin {

val detektTaskNames = targets.flatMap { target ->
target.compilations.map { compilation ->
"detekt${target.targetName.capitalize()}${compilation.compilationName.capitalize()}"
"detekt${target.targetName.capitalized()}${compilation.compilationName.capitalized()}"
}
}
tasks.check {
Expand Down Expand Up @@ -142,9 +148,16 @@ for ((name, base, usage) in listOf(
}

dependencies {
kotlin.targets.all { if (this !is KotlinMetadataTarget) "ksp${name.capitalized()}"(projects.processor) }
detektPlugins(libs.bundles.detekt.plugins)
}

tasks.withType<Test>().configureEach {
useJUnitPlatform()
}

afterEvaluate {
// Workaround for https://github.com/google/ksp/issues/2267
tasks.withType<KspAATask>().configureEach { setOnlyIf(Specs.satisfyAll()) }
tasks.withType<KspTaskNative>().configureEach { setOnlyIf(Specs.satisfyAll()) }
}
Original file line number Diff line number Diff line change
@@ -1,51 +1,22 @@
package com.github.ephemient.aoc2024

val days: List<Day> = listOf(
Day(1, ::Day1, Day1::part1, Day1::part2),
Day(2, ::Day2, Day2::part1, Day2::part2),
Day(3, ::Day3, Day3::part1, Day3::part2),
Day(4, ::Day4, Day4::part1, Day4::part2),
Day(5, ::Day5, Day5::part1, Day5::part2),
Day(6, ::Day6, Day6::part1, Day6::part2),
Day(7, ::Day7, Day7::part1, Day7::part2),
Day(8, ::Day8, Day8::part1, Day8::part2),
Day(9, ::Day9, Day9::part1, Day9::part2),
Day(10, ::Day10, Day10::part1, Day10::part2),
Day(11, ::Day11, Day11::part1, Day11::part2),
Day(12, ::Day12, Day12::part1, Day12::part2),
Day(13, ::Day13, Day13::part1, Day13::part2),
Day(14, ::Day14, Day14::part1, Day14::part2),
Day(15, ::Day15, Day15::part1, Day15::part2),
Day(16, ::Day16, Day16::part1, Day16::part2),
Day(17, ::Day17, Day17::part1, Day17::part2),
Day(18, ::Day18, Day18::part1, Day18::part2),
Day(19, ::Day19, Day19::solve),
Day(20, ::Day20, Day20::part1, Day20::part2),
Day(21, ::Day21, Day21::part1, Day21::part2),
Day(22, ::Day22, Day22::part1, Day22::part2),
Day(23, ::Day23, Day23::part1, Day23::part2),
Day(24, ::Day24, Day24::part1, Day24::part2),
Day(25, ::Day25, Day25::part1),
)
expect val days: List<Day>

data class Day(
val day: Int,
val parts: Int,
val solver: (String) -> List<suspend () -> Any?>,
val name: String = day.toString(),
val skipByDefault: Boolean = false,
)

fun <T> Day(
day: Int,
create: (String) -> T,
vararg parts: suspend (T) -> Any?,
name: String = day.toString(),
skipByDefault: Boolean = false,
): Day = Day(
day = day,
parts = parts.size,
solver = { with(create(it)) { parts.map { suspend { it.invoke(this) } } } },
name = name,
skipByDefault = skipByDefault,
)
2 changes: 2 additions & 0 deletions kt/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
plugins {
base
alias(libs.plugins.kotlin.jvm) apply false
alias(libs.plugins.kotlin.multiplatform) apply false
alias(libs.plugins.kotlin.plugin.allopen) apply false
alias(libs.plugins.ksp) apply false
alias(libs.plugins.detekt)
alias(libs.plugins.kotlinx.benchmark) apply false
}
Expand Down
5 changes: 5 additions & 0 deletions kt/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ kotlin = "2.1.0"
kotlinx-benchmark = "0.4.13"
kotlinx-coroutines = "1.10.1"
kotlinpoet = "2.0.0"
ksp = "2.1.0-1.0.29"
native-image = "0.10.4"
okio = "3.9.1"

[plugins]
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
kotlin-plugin-allopen = { id = "org.jetbrains.kotlin.plugin.allopen", version.ref = "kotlin" }
kotlinx-benchmark = { id = "org.jetbrains.kotlinx.benchmark", version.ref = "kotlinx-benchmark" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
native-image = { id = "org.graalvm.buildtools.native", version.ref = "native-image" }

[libraries]
Expand All @@ -21,9 +24,11 @@ junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.re
junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit-jupiter" }
kotlin-wrappers-node = { module = "org.jetbrains.kotlin-wrappers:kotlin-node", version = "22.5.5-pre.854" }
kotlinpoet = { module = "com.squareup:kotlinpoet", version.ref = "kotlinpoet" }
kotlinpoet-ksp = { module = "com.squareup:kotlinpoet-ksp", version.ref = "kotlinpoet" }
kotlinx-benchmark = { module = "org.jetbrains.kotlinx:kotlinx-benchmark-runtime", version.ref = "kotlinx-benchmark" }
kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }
ksp = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "ksp" }
okio = { module = "com.squareup.okio:okio", version.ref = "okio" }

[bundles]
Expand Down
9 changes: 9 additions & 0 deletions kt/processor/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
plugins {
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.detekt)
}

dependencies {
implementation(libs.ksp)
implementation(libs.kotlinpoet.ksp)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package com.github.ephemient.aoc2024.processor

import com.google.devtools.ksp.isAbstract
import com.google.devtools.ksp.isPublic
import com.google.devtools.ksp.processing.CodeGenerator
import com.google.devtools.ksp.processing.Dependencies
import com.google.devtools.ksp.processing.JvmPlatformInfo
import com.google.devtools.ksp.processing.PlatformInfo
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.symbol.ClassKind
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSFunctionDeclaration
import com.squareup.kotlinpoet.AnnotationSpec
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.CodeBlock
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.KModifier
import com.squareup.kotlinpoet.LIST
import com.squareup.kotlinpoet.MemberName
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import com.squareup.kotlinpoet.PropertySpec
import com.squareup.kotlinpoet.TypeName
import com.squareup.kotlinpoet.joinToCode
import com.squareup.kotlinpoet.ksp.toClassName
import com.squareup.kotlinpoet.ksp.writeTo

class DaysProcessor(
private val platforms: List<PlatformInfo>,
private val codeGenerator: CodeGenerator,
) : SymbolProcessor {
private val days = mutableListOf<Day>()

override fun process(resolver: Resolver): List<KSAnnotated> {
resolver.getNewFiles()
.flatMap { it.declarations }
.mapNotNullTo(days) { declaration ->
if (
declaration !is KSClassDeclaration ||
!declaration.isPublic() ||
declaration.isAbstract() ||
declaration.classKind != ClassKind.CLASS
) return@mapNotNullTo null
classNamePattern.matchEntire(declaration.simpleName.asString())?.let { match ->
val (name, day) = match.destructured
val typeName = declaration.toClassName()
Day(
day = day.toInt(),
name = name,
typeName = typeName,
parts = declaration.declarations
.mapNotNull { declaration ->
if (
declaration !is KSFunctionDeclaration ||
!declaration.isPublic()
) return@mapNotNull null
val memberName = declaration.simpleName.asString()
if (memberName == "solve") return@mapNotNull Part(
part = Int.MAX_VALUE,
name = memberName,
memberName = memberName
)
functionNamePattern.matchEntire(memberName)?.let { match ->
val (name, part) = match.destructured
Part(
part = part.toInt(),
name = name,
memberName = memberName,
)
}
}
.toList()
.sortedWith(compareBy(Part::part, Part::name))
)
}
}
return emptyList()
}

override fun finish() {
FileSpec.builder(PACKAGE, "Days")
.addAnnotations(
if (platforms.any { it is JvmPlatformInfo }) listOf(
AnnotationSpec.builder(ClassName("kotlin.jvm", "JvmName"))
.addMember("%S", "JvmDays")
.build()
) else emptyList()
)
.addProperty(
PropertySpec.builder("days", LIST.parameterizedBy(ClassName(PACKAGE, "Day")))
.addModifiers(KModifier.ACTUAL)
.initializer(
"%M(\n%L)",
MemberName("kotlin.collections", "listOf"),
days.sortedWith(compareBy(Day::day, Day::name)).joinToCode(",\n") { day ->
CodeBlock.of(
"%T(%L)",
ClassName(PACKAGE, "Day"),
listOfNotNull(
CodeBlock.of("%N = %L", "day", day.day),
CodeBlock.of("::%T", day.typeName),
*Array(day.parts.size) {
CodeBlock.of("%T::%N", day.typeName, day.parts[it].memberName)
},
CodeBlock.of("%N = %S", "name", day.name),
).joinToCode(),
)
}
)
.build()
)
.build()
.writeTo(codeGenerator, Dependencies.ALL_FILES)
}

private data class Day(
val day: Int,
val name: String,
val typeName: TypeName,
val parts: List<Part>,
)

private data class Part(
val part: Int,
val name: String,
val memberName: String,
)

companion object {
private const val PACKAGE = "com.github.ephemient.aoc2024"
private val classNamePattern = """Day((\d+).*)""".toRegex()
private val functionNamePattern = """part((\d+).*)""".toRegex()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.github.ephemient.aoc2024.processor

import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.google.devtools.ksp.processing.SymbolProcessorProvider

class DaysProcessorProvider : SymbolProcessorProvider {
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor =
DaysProcessor(environment.platforms, environment.codeGenerator)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
com.github.ephemient.aoc2024.processor.DaysProcessorProvider
2 changes: 1 addition & 1 deletion kt/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ gradle.afterProject {
}

rootProject.name = "aoc2024"
include("aoc2024-exe", "aoc2024-lib", "graalvm")
include("aoc2024-exe", "aoc2024-lib", "graalvm", "processor")

0 comments on commit 2e22bf1

Please sign in to comment.