com.tambapps.marcel.semantic.transform.StringifyAstTransformation.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of marcel-semantic-transformer Show documentation
Show all versions of marcel-semantic-transformer Show documentation
Marcel Semantic Transformation module
The newest version!
package com.tambapps.marcel.semantic.transform
import com.tambapps.marcel.parser.cst.CstNode
import com.tambapps.marcel.semantic.ast.Annotable
import com.tambapps.marcel.semantic.ast.AnnotationNode
import com.tambapps.marcel.semantic.ast.AstNode
import com.tambapps.marcel.semantic.ast.ClassNode
import com.tambapps.marcel.semantic.ast.MethodNode
import com.tambapps.marcel.semantic.ast.expression.ExpressionNode
import com.tambapps.marcel.semantic.extensions.javaAnnotationType
import com.tambapps.marcel.semantic.extensions.javaType
import com.tambapps.marcel.semantic.type.JavaType
import com.tambapps.marcel.semantic.type.SourceJavaType
import marcel.lang.data
import marcel.lang.stringify
import java.util.Arrays
/**
* AST transformation to generate toString method. Implicitly referenced in stringify annotation
*/
class StringifyAstTransformation : GenerateMethodAstTransformation() {
override fun generateSignatures(node: CstNode, javaType: SourceJavaType, annotation: AnnotationNode) = listOf(
signature(name = "toString", returnType = JavaType.String)
)
override fun generateMethodNodes(node: AstNode, classNode: ClassNode, annotation: AnnotationNode): List {
val stringParts = mutableListOf(
string(classNode.type.simpleName + "(")
)
if (classNode.superType != JavaType.Object) {
stringParts.add(string("super="))
stringParts.add(toString(fCall(name = "toString", owner = superRef(), arguments = emptyList())))
}
for (field in classNode.fields) {
if (isAnnotableExcluded(field) || field.isStatic) continue
stringParts.add(string(field.name + "="))
stringParts.add(toString(ref(field)))
stringParts.add(string(", "))
}
if (annotation.getAttribute("includeGetters")?.value == true) {
for (method in classNode.methods) {
if (isAnnotableExcluded(method) || !method.isGetter
|| method.isStatic
) continue
stringParts.add(string(method.propertyName + "="))
stringParts.add(
toString(
fCall(
owner = thisRef(),
name = method.name,
arguments = emptyList()
)
)
)
stringParts.add(string(", "))
}
}
stringParts.removeLast() // remove trailing ", "
stringParts.add(string(")"))
val methodNode = methodNode(
ownerClass = classNode.type,
name = "toString",
returnType = JavaType.String,
annotations = listOf(annotationNode(Override::class.javaAnnotationType))
) {
returnStmt(string(stringParts))
}
return listOf(methodNode)
}
private fun toString(expr: ExpressionNode): ExpressionNode {
return when {
expr.type.isArray -> if (expr.type.asArrayType.elementsType.primitive) fCall(
name = "toString",
ownerType = Arrays::class.javaType,
arguments = listOf(expr)
)
else fCall(name = "deepToString", ownerType = Arrays::class.javaType, arguments = listOf(expr))
expr.type == JavaType.String -> expr
else -> fCall(ownerType = JavaType.String, name = "valueOf", arguments = listOf(expr))
}
}
private fun isAnnotableExcluded(annotable: Annotable): Boolean {
return annotable.getAnnotation(stringify.Exclude::class.javaType) != null
// useful because this can be run from a data annotation
|| annotable.getAnnotation(data.Exclude::class.javaType) != null
}
}