Skip to content

Commit

Permalink
Addressing comments on PR #383
Browse files Browse the repository at this point in the history
  • Loading branch information
ftomassetti committed Sep 19, 2024
1 parent 8d1e0de commit 49b5578
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package com.strumenta.kolasu.transformation
import com.strumenta.kolasu.model.Node
import com.strumenta.kolasu.model.PossiblyNamed
import com.strumenta.kolasu.model.ReferenceByName
import com.strumenta.kolasu.model.isContainment
import com.strumenta.kolasu.model.nodeProperties
import java.lang.reflect.ParameterizedType
import kotlin.random.Random
import kotlin.reflect.KClass
import kotlin.reflect.KParameter
import kotlin.reflect.full.createType
Expand All @@ -18,8 +19,8 @@ import kotlin.reflect.jvm.javaType
* Typically, the only goal of the element would be to hold some annotation that indicates that the element
* is representing an error or a missing transformation or something of that sort.
*/
fun <T : Node> KClass<T>.dummyInstance(): T {
val kClassToInstantiate = this.toInstantiableType()
fun <T : Node> KClass<T>.dummyInstance(levelOfDummyTree: Int = 0): T {
val kClassToInstantiate = this.toInstantiableType(levelOfDummyTree)
val emptyConstructor = kClassToInstantiate.constructors.find { it.parameters.isEmpty() }
if (emptyConstructor != null) {
return emptyConstructor.call()
Expand All @@ -32,7 +33,7 @@ fun <T : Node> KClass<T>.dummyInstance(): T {
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.classifier as KClass<out Node>).dummyInstance(levelOfDummyTree + 1)
param.type == String::class.createType() -> "DUMMY"
param.type.classifier == ReferenceByName::class -> ReferenceByName<PossiblyNamed>("UNKNOWN")
param.type == Int::class.createType() -> 0
Expand All @@ -49,7 +50,7 @@ fun <T : Node> KClass<T>.dummyInstance(): T {
return constructor.callBy(params)
}

private fun <T : Any> KClass<T>.toInstantiableType(): KClass<out T> {
private fun <T : Any> KClass<T>.toInstantiableType(levelOfDummyTree: Int = 0): KClass<out T> {
return when {
this.isSealed -> {
val subclasses = this.sealedSubclasses.filter { it.isDirectlyOrIndirectlyInstantiable() }
Expand All @@ -59,16 +60,21 @@ private fun <T : Any> KClass<T>.toInstantiableType(): KClass<out T> {
val subClassWithEmptyParam = subclasses.find { it.constructors.any { it.parameters.isEmpty() } }
if (subClassWithEmptyParam == null) {
if (subclasses.size == 1) {
subclasses.first().toInstantiableType()
subclasses.first().toInstantiableType(levelOfDummyTree + 1)
} 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()
// So we want to avoid just using the same subclass, repeatedly as it would lead to an
// infinite loop. Therefore we sort subclasses by the order of containments, preferring the ones
// with no or few containments and we take them consider the level of depth in the dummy tree
val subclassesByNumberOfContainments = subclasses.map {
it to it.nodeProperties.count {
it.isContainment()
}
}.toList().sortedBy { it.second }.map { it.first }
subclasses[levelOfDummyTree].toInstantiableType(levelOfDummyTree + 1)
}
} else {
subClassWithEmptyParam.toInstantiableType()
subClassWithEmptyParam.toInstantiableType(levelOfDummyTree + 1)
}
}
this.isAbstract -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,28 @@ package com.strumenta.kolasu.transformation
import com.strumenta.kolasu.model.Node
import com.strumenta.kolasu.model.Origin
import com.strumenta.kolasu.model.Position
import com.strumenta.kolasu.traversing.walkAncestors
import kotlin.reflect.KClass

/**
* This indicates if the Node itself is marked as a placeholder. Note that the Node could not be directly marked
* as such and still be the descendants of such type of Node. In other words it could be in a placeholder tree.
* This operation is not expensive to perform.
*/
val Node.isDirectlyPlaceholderASTTransformation: Boolean
get() = this.origin is PlaceholderASTTransformation

/**
* This indicates if the Node itself is marked as a placeholder or if any of its ancestors are. Note that the Node
* could not be directly marked as such and still be the descendants of such type of Node. In other words it could be
* in a placeholder tree.
* This operation is expensive to perform.
*/
val Node.isDirectlyOrIndirectlyAPlaceholderASTTransformation: Boolean
get() = this.isDirectlyPlaceholderASTTransformation || this.walkAncestors().any {
it.isDirectlyPlaceholderASTTransformation
}

/**
* This is used to indicate that a Node represents some form of placeholders to be used in transformation.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,9 @@ open class ASTTransformer(
crossinline factory: S.(ASTTransformer) -> T?
): NodeFactory<S, T> = registerNodeFactory(S::class) { source, transformer, _ -> source.factory(transformer) }

/**
* We need T to be reified because we may need to install dummy classes of T.
*/
inline fun <S : Any, reified T : Node> registerNodeFactory(
kclass: KClass<S>,
crossinline factory: (S) -> T?
Expand Down Expand Up @@ -607,6 +610,10 @@ open class ASTTransformer(
return nodeFactory
}

/**
* Here the method needs to be inlined and the type parameter reified as in the invoked
* registerNodeFactory we need to access the nodeClass
*/
inline fun <reified T : Node> registerIdentityTransformation(nodeClass: KClass<T>) =
registerNodeFactory(nodeClass) { node -> node }.skipChildren()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.strumenta.kolasu.model.children
import com.strumenta.kolasu.model.kReferenceByNameType
import com.strumenta.kolasu.model.nodeProperties
import com.strumenta.kolasu.semantics.scope.provider.ScopeProvider
import com.strumenta.kolasu.transformation.isDirectlyPlaceholderASTTransformation
import kotlin.reflect.KProperty1
import kotlin.reflect.full.isSubtypeOf

Expand Down Expand Up @@ -52,8 +53,15 @@ open class SymbolResolver(
node: Node,
entireTree: Boolean = false
) {
if (node.isDirectlyPlaceholderASTTransformation) {
return
}
node.references().forEach { reference -> this.resolve(node, reference) }
if (entireTree) node.children.forEach { this.resolve(it, entireTree) }
if (entireTree) {
node.children.filter { !it.isDirectlyPlaceholderASTTransformation }.forEach {
this.resolve(it, entireTree)
}
}
}

/**
Expand Down

0 comments on commit 49b5578

Please sign in to comment.