Skip to content

Commit

Permalink
Merge pull request #20 from ty1824/references
Browse files Browse the repository at this point in the history
New reference handling for node builders
  • Loading branch information
ty1824 authored Mar 27, 2023
2 parents d91b914 + 7aa0147 commit 6bb2bc7
Show file tree
Hide file tree
Showing 13 changed files with 361 additions and 274 deletions.
24 changes: 19 additions & 5 deletions dialector-kt-processor/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import java.nio.file.Paths

plugins {
kotlin("jvm")
id("org.jetbrains.kotlinx.kover")
id("com.google.devtools.ksp")
// TODO: Re-enable when unit tests are added, tests right now depend on running the processor at test compile time.
//id("org.jetbrains.kotlinx.kover")
id("maven-publish")
signing
}
Expand All @@ -15,8 +19,17 @@ repositories {
dependencies {
implementation(project(":dialector-kt"))
implementation("com.squareup:kotlinpoet:1.12.0")
implementation("com.squareup:kotlinpoet-ksp:1.12.0")
implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
implementation(kotlin("reflect"))

testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation(project(":dialector-kt"))
kspTest(project(":dialector-kt-processor"))
}

ksp {
arg("dev.dialector.targetPackage", "dev.dialector.processor.ast")
}

kotlin {
Expand All @@ -34,10 +47,11 @@ tasks.withType<Test> {
useJUnitPlatform()
}

kover {
xmlReport {
onCheck.set(true)
}
tasks.withType<org.jmailen.gradle.kotlinter.tasks.ConfigurableKtLintTask> {
exclude { it.file.toPath().contains(Paths.get("build")) }
// The following does not work on all OS - path separator is OS-dependent
// exclude { it.file.path.contains("/build/generated/") }
// exclude { it.file.path.contains("\\build\\generated\\") }
}

publishing {
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,7 @@ import com.google.devtools.ksp.getAllSuperTypes
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSAnnotation
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSDeclaration
import com.google.devtools.ksp.symbol.KSType
import com.google.devtools.ksp.symbol.KSTypeParameter
import com.google.devtools.ksp.symbol.Variance
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.KModifier
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import com.squareup.kotlinpoet.TypeName
import com.squareup.kotlinpoet.TypeVariableName
import kotlin.reflect.KClass

sealed class Result<out S, out F>
Expand All @@ -37,44 +29,3 @@ fun KSClassDeclaration.isSubclassOf(superclass: KClass<out Any>): Boolean {
}

fun KSType.isAssignableTo(type: KSType): Boolean = type.isAssignableFrom(this)

internal fun KSDeclaration.getLocalQualifiedName(): List<String> =
if (this.parentDeclaration != null) {
this.parentDeclaration!!.getLocalQualifiedName() + this.simpleName.asString()
} else {
listOf(this.simpleName.asString())
}

internal fun KSClassDeclaration.asClassName(): ClassName =
ClassName(this.packageName.asString(), this.getLocalQualifiedName())

internal fun KSType.asTypeName(): TypeName {
return if (this.declaration is KSClassDeclaration) {
val declarationName = (this.declaration as KSClassDeclaration).asClassName()
val candidate = if (this.arguments.isNotEmpty()) {
declarationName.parameterizedBy(*this.arguments.map { it.type!!.resolve().asTypeName() }.toTypedArray())
} else {
declarationName
}

if (this.isMarkedNullable) candidate.copy(nullable = true) else candidate
} else if (this.declaration is KSTypeParameter) {
val declarationName: TypeVariableName = (this.declaration as KSTypeParameter).asTypeVariableName()
if (this.isMarkedNullable) declarationName.copy(nullable = true) else declarationName
} else {
throw RuntimeException("Failed to create TypeName for $this")
}
}

internal fun KSTypeParameter.asTypeVariableName(): TypeVariableName {
return TypeVariableName.invoke(
name = name.asString(),
bounds = this.bounds.map { it.resolve().asTypeName() }.toList().toTypedArray(),
variance = when (variance) {
Variance.INVARIANT, Variance.STAR -> null
Variance.CONTRAVARIANT -> KModifier.IN
Variance.COVARIANT -> KModifier.OUT
else -> null
}
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package dev.dialector.processor

import dev.dialector.processor.ast.childNode
import dev.dialector.processor.ast.simpleNode
import kotlin.test.Test
import kotlin.test.assertEquals

/**
* These tests are designed to validate the generated code, both its API and its functionality.
*/
class DialectorSymbolProcessorTest {

@Test
fun processorApi() {
val singleChildValue = childNode()
val optionalChildValue = childNode()
val pluralFirstChildValue = childNode()
val pluralSecondChildValue = childNode()
val pluralThirdChildValue = childNode()
val node = simpleNode {
property = "hello"
optionalProperty = "provided"
singleChild = singleChildValue
optionalChild = optionalChildValue
pluralChildren += pluralFirstChildValue
pluralChildren += listOf(pluralSecondChildValue, pluralThirdChildValue)
reference = "target.id"
optionalReference = "target.otherId"
}

// Verify raw values
assertEquals("hello", node.property)
assertEquals("provided", node.optionalProperty)
assertEquals(singleChildValue, node.singleChild)
assertEquals(optionalChildValue, node.optionalChild)
assertEquals(listOf(pluralFirstChildValue, pluralSecondChildValue, pluralThirdChildValue), node.pluralChildren)
assertEquals("target.id", node.reference.targetIdentifier)
assertEquals("target.otherId", node.optionalReference?.targetIdentifier)

// Verify parent assignment
assertEquals(node, singleChildValue.parent)

// Verify reference property assignment
assertEquals(node, node.reference.sourceNode)
assertEquals(SimpleNode::reference, node.reference.relation)
assertEquals(SimpleNode::optionalReference, node.optionalReference?.relation)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package dev.dialector.processor

import dev.dialector.syntax.Child
import dev.dialector.syntax.Node
import dev.dialector.syntax.NodeDefinition
import dev.dialector.syntax.NodeReference
import dev.dialector.syntax.Property
import dev.dialector.syntax.Reference

@NodeDefinition
interface SimpleNode : Node {
@Property
val property: String

@Property
val optionalProperty: String?

@Child
val singleChild: ChildNode

@Child
val optionalChild: ChildNode

@Child
val pluralChildren: List<ChildNode>

@Reference
val reference: NodeReference<ReferenceTargetNode>

@Reference
val optionalReference: NodeReference<ReferenceTargetNode>?
}

@NodeDefinition
interface ChildNode : Node

@NodeDefinition
interface ReferenceTargetNode : Node {
@Property
val name: String
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class SingleRootScopeGraph private constructor(
it(this, node, scope)
}
} else {
node.references.forEach { scope.reference(Default, it.value, it.value.targetIdentifier) }
node.references.values.filterNotNull().forEach { scope.reference(Default, it, it.targetIdentifier) }
node.children.forEach { child -> child.value.forEach { traverse(it, scope) } }
}
})
Expand Down Expand Up @@ -291,7 +291,7 @@ class LinearScopeGraph private constructor(
it(this, node, scope)
}
} else {
node.references.forEach { scope.reference(Default, it.value, it.value.targetIdentifier) }
node.references.values.filterNotNull().forEach { scope.reference(Default, it, it.targetIdentifier) }
node.children.forEach { child -> child.value.forEach { traverse(it, scope) } }
}
})
Expand Down
119 changes: 0 additions & 119 deletions dialector-kt/src/main/kotlin/dev/dialector/server/DialectorServer.kt

This file was deleted.

26 changes: 0 additions & 26 deletions dialector-kt/src/main/kotlin/dev/dialector/server/EventBus.kt

This file was deleted.

Loading

0 comments on commit 6bb2bc7

Please sign in to comment.