Skip to content

Commit

Permalink
Generalize printing of placeholders
Browse files Browse the repository at this point in the history
  • Loading branch information
ftomassetti committed Sep 13, 2024
1 parent e10d925 commit 4b8c7c5
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import com.strumenta.kolasu.model.Node
import com.strumenta.kolasu.model.Position
import com.strumenta.kolasu.model.START_POINT
import com.strumenta.kolasu.model.TextFileDestination
import com.strumenta.kolasu.transformation.FailingASTTransformation
import com.strumenta.kolasu.transformation.MissingASTTransformation
import com.strumenta.kolasu.transformation.PlaceholderASTTransformation
import kotlin.reflect.KClass
import kotlin.reflect.full.superclasses

Expand Down Expand Up @@ -99,7 +101,7 @@ class PrinterOutput(
if (overrider != null) {
return overrider
}
val properPrinter = if (ast.origin is MissingASTTransformation && placeholderNodePrinter != null) {
val properPrinter = if (ast.origin is PlaceholderASTTransformation && placeholderNodePrinter != null) {
placeholderNodePrinter
} else {
nodePrinters[kclass]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.strumenta.kolasu.model.*
import com.strumenta.kolasu.validation.Issue
import com.strumenta.kolasu.validation.IssueSeverity
import java.lang.reflect.ParameterizedType
import kotlin.random.Random
import org.antlr.v4.runtime.tree.ParseTree
import kotlin.reflect.KClass
import kotlin.reflect.KMutableProperty1
Expand Down Expand Up @@ -240,19 +241,15 @@ data class ChildNodeFactory<Source, Target, Child : Any>(
*/
private val NO_CHILD_NODE = ChildNodeFactory<Any, Any, Any>("", { x -> x }, { _, _ -> }, Node::class)

class MissingASTTransformation(val origin: Origin?) : Origin {
sealed class PlaceholderASTTransformation(val origin: Origin?) : Origin {
override val position: Position?
get() = origin?.position
override val sourceText: String?
get() = origin?.sourceText
}

class FailingASTTransformation(val origin: Origin?) : Origin {
override val position: Position?
get() = origin?.position
override val sourceText: String?
get() = origin?.sourceText
}
class MissingASTTransformation(origin: Origin?) : PlaceholderASTTransformation(origin)
class FailingASTTransformation(origin: Origin?) : PlaceholderASTTransformation(origin)

/**
* Implementation of a tree-to-tree transformation. For each source node type, we can register a factory that knows how
Expand Down Expand Up @@ -469,14 +466,22 @@ open class ASTTransformer(
inline fun <S : Any, reified T : Node> registerNodeFactory(kclass: KClass<S>, crossinline factory: (S) -> T?): NodeFactory<S, T> =
registerNodeFactory(kclass) { input, _, _ -> try {
factory(input)
} catch (t: Throwable) {
} catch (t: NotImplementedError) {
if (faultTollerant) {
val node = T::class.dummyInstance()
node.origin = FailingASTTransformation(asOrigin(input))
node
} else {
throw RuntimeException("Failed to transform $input into $kclass", t)
}
}catch (e: Exception) {
if (faultTollerant) {
val node = T::class.dummyInstance()
node.origin = FailingASTTransformation(asOrigin(input))
node
} else {
throw RuntimeException("Failed to transform $input into $kclass", e)
}
}
}

Expand Down Expand Up @@ -634,8 +639,24 @@ private fun <T:Any> KClass<T>.isDirectlyOrIndirectlyInstantiable(): Boolean {
private fun <T:Any> KClass<T>.toInstantiableType() : KClass<out T> {
return when {
this.isSealed -> {
val subclass = this.sealedSubclasses.find { it.isDirectlyOrIndirectlyInstantiable() }
subclass?.toInstantiableType() ?: throw IllegalStateException("$this has no instantiable sealed subclasses")
val subclasses = this.sealedSubclasses.filter { it.isDirectlyOrIndirectlyInstantiable() }
if (subclasses.isEmpty()) {
throw IllegalStateException("$this has no instantiable sealed subclasses")
}
val subClassWithEmptyParam = subclasses.find { it.constructors.any { it.parameters.isEmpty() } }
if (subClassWithEmptyParam == null) {
if (subclasses.size == 1) {
subclasses.first().toInstantiableType()
} else {
// Some constructs are recursive (think of the ArrayType)
// We either find complex logic to find the ones that aren't or just pick one randomly. Eventually we will build
// a tree
val r = Random.Default
subclasses[r.nextInt(subclasses.size)].toInstantiableType()
}
} else {
subClassWithEmptyParam.toInstantiableType()
}
}
this.isAbstract -> {
throw IllegalStateException("We cannot instantiate an abstract class (but we can handle sealed classes)")
Expand All @@ -662,6 +683,9 @@ fun <T:Node> KClass<T>.dummyInstance() : T {
val value = when {
param.type.isMarkedNullable -> null
mt is ParameterizedType && mt.rawType == List::class.java -> mutableListOf<Any>()
(param.type.classifier as KClass<*>).isSubclassOf(Node::class) -> (param.type.classifier as KClass<out Node>).dummyInstance()
param.type == String::class.createType() -> "DUMMY"
param.type.classifier == ReferenceByName::class -> ReferenceByName<PossiblyNamed>("UNKNOWN")
else -> TODO()
}
params[param] = value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ package com.strumenta.kolasu.codegen

import com.strumenta.kolasu.model.Node
import com.strumenta.kolasu.transformation.MissingASTTransformation
import com.strumenta.kolasu.transformation.PlaceholderASTTransformation

class KotlinPrinter : ASTCodeGenerator<KCompilationUnit>() {

override val placeholderNodePrinter: NodePrinter
get() = NodePrinter { output: PrinterOutput, ast: Node ->
val origin = (ast.origin as MissingASTTransformation).origin
val origin = (ast.origin as PlaceholderASTTransformation).origin
val nodeType = if (origin is Node) {
origin.nodeType
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import kotlin.reflect.KMutableProperty
import kotlin.reflect.KParameter
import kotlin.reflect.full.primaryConstructor
import io.lionweb.lioncore.java.language.Feature as LWFeature
import com.strumenta.kolasu.transformation.PlaceholderASTTransformation

interface PrimitiveValueSerialization<E> {
fun serialize(value: E): String
Expand Down Expand Up @@ -218,7 +219,7 @@ class LionWebModelConverter(
if (origin is KNode) {
val targetID = myIDManager.nodeId(origin)
setOriginalNode(lwNode, targetID)
} else if (origin is MissingASTTransformation) {
} else if (origin is PlaceholderASTTransformation) {
if (lwNode is AbstractClassifierInstance<*>) {
val instance = DynamicAnnotationInstance(
StarLasuLWLanguage.PlaceholderNode.id,
Expand Down

0 comments on commit 4b8c7c5

Please sign in to comment.