From 0d1a79f45c0d5581b2eedb5b66d65e1b7fb04cfe Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Fri, 17 Jan 2025 14:25:45 +0300 Subject: [PATCH] Add Raw Stmt/Value/Type (#291) --- buildSrc/src/main/kotlin/Dependencies.kt | 2 +- .../kotlin/org/jacodb/ets/base/EtsEntity.kt | 21 ++ .../main/kotlin/org/jacodb/ets/base/EtsRef.kt | 82 +++---- .../kotlin/org/jacodb/ets/base/EtsStmt.kt | 36 +-- .../kotlin/org/jacodb/ets/base/EtsType.kt | 91 ++------ .../kotlin/org/jacodb/ets/base/EtsValue.kt | 6 - .../main/kotlin/org/jacodb/ets/dto/Convert.kt | 69 ++---- .../main/kotlin/org/jacodb/ets/dto/Model.kt | 9 +- .../kotlin/org/jacodb/ets/dto/Serializers.kt | 88 +++++++- .../kotlin/org/jacodb/ets/dto/Signatures.kt | 54 +---- .../main/kotlin/org/jacodb/ets/dto/Stmts.kt | 36 ++- .../main/kotlin/org/jacodb/ets/dto/Types.kt | 177 +++------------ .../main/kotlin/org/jacodb/ets/dto/Values.kt | 211 ++++-------------- .../org/jacodb/ets/utils/GetOperands.kt | 12 +- .../org/jacodb/ets/test/EtsFromJsonTest.kt | 56 ++++- 15 files changed, 371 insertions(+), 579 deletions(-) diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index 1ac3c0864..a3c684d0f 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -29,7 +29,7 @@ object Versions { const val kotlinx_collections_immutable = "0.3.5" const val kotlinx_coroutines = "1.6.4" const val kotlin_metadata = kotlin - const val kotlinx_serialization = "1.4.1" + const val kotlinx_serialization = "1.8.0" const val licenser = "0.6.1" const val mockk = "1.13.3" const val sarif4k = "0.5.0" diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsEntity.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsEntity.kt index 30fb3d1d9..68f682ee5 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsEntity.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsEntity.kt @@ -28,6 +28,13 @@ interface EtsEntity : CommonExpr { EtsValue.Visitor, EtsExpr.Visitor { + fun visit(value: EtsRawEntity): R { + if (this is Default) { + return defaultVisit(value) + } + error("Cannot handle ${value::class.java.simpleName}: $value") + } + interface Default : Visitor, EtsValue.Visitor.Default, EtsExpr.Visitor.Default { @@ -41,3 +48,17 @@ interface EtsEntity : CommonExpr { fun accept(visitor: Visitor): R } + +data class EtsRawEntity( + val kind: String, + val extra: Map = emptyMap(), + override val type: EtsType, +) : EtsEntity { + override fun toString(): String { + return "$kind $extra: $type" + } + + override fun accept(visitor: EtsEntity.Visitor): R { + return visitor.visit(this) + } +} diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsRef.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsRef.kt index ff84a89d0..c6855b03e 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsRef.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsRef.kt @@ -45,47 +45,47 @@ data class EtsParameterRef( } } -data class EtsCaughtExceptionRef( - override val type: EtsType, -) : EtsValue { - override fun toString(): String { - return "catch($type)" - } - - override fun accept(visitor: EtsValue.Visitor): R { - return visitor.visit(this) - } -} - -data class EtsGlobalRef( - val name: String, - val ref: EtsValue?, // TODO: check whether it could be EtsEntity at best -) : EtsValue { - override val type: EtsType - get() = ref?.type ?: EtsUnknownType - - override fun toString(): String { - return "global $name" - } - - override fun accept(visitor: EtsValue.Visitor): R { - return visitor.visit(this) - } -} - -data class EtsClosureFieldRef( - val base: EtsLocal, - val fieldName: String, - override val type: EtsType, -) : EtsValue { - override fun toString(): String { - return "$base.$fieldName" - } - - override fun accept(visitor: EtsValue.Visitor): R { - return visitor.visit(this) - } -} +// data class EtsCaughtExceptionRef( +// override val type: EtsType, +// ) : EtsValue { +// override fun toString(): String { +// return "catch($type)" +// } +// +// override fun accept(visitor: EtsValue.Visitor): R { +// return visitor.visit(this) +// } +// } +// +// data class EtsGlobalRef( +// val name: String, +// val ref: EtsValue?, // TODO: check whether it could be EtsEntity at best +// ) : EtsValue { +// override val type: EtsType +// get() = ref?.type ?: EtsUnknownType +// +// override fun toString(): String { +// return "global $name" +// } +// +// override fun accept(visitor: EtsValue.Visitor): R { +// return visitor.visit(this) +// } +// } +// +// data class EtsClosureFieldRef( +// val base: EtsLocal, +// val fieldName: String, +// override val type: EtsType, +// ) : EtsValue { +// override fun toString(): String { +// return "$base.$fieldName" +// } +// +// override fun accept(visitor: EtsValue.Visitor): R { +// return visitor.visit(this) +// } +// } data class EtsArrayAccess( val array: EtsValue, diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsStmt.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsStmt.kt index 6b66c197a..fa27946f6 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsStmt.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsStmt.kt @@ -42,7 +42,13 @@ interface EtsStmt : CommonInst { fun visit(stmt: EtsGotoStmt): R fun visit(stmt: EtsIfStmt): R fun visit(stmt: EtsSwitchStmt): R - fun visit(stmt: EtsRawStmt): R + + fun visit(stmt: EtsRawStmt): R { + if (this is Default) { + return defaultVisit(stmt) + } + error("Cannot handle ${stmt::class.java.simpleName}: $stmt") + } interface Default : Visitor { override fun visit(stmt: EtsNopStmt): R = defaultVisit(stmt) @@ -62,6 +68,20 @@ interface EtsStmt : CommonInst { fun accept(visitor: Visitor): R } +data class EtsRawStmt( + override val location: EtsInstLocation, + val kind: String, + val extra: Map = emptyMap(), +) : EtsStmt { + override fun toString(): String { + return "$kind $extra" + } + + override fun accept(visitor: EtsStmt.Visitor): R { + return visitor.visit(this) + } +} + data class EtsNopStmt( override val location: EtsInstLocation, ) : EtsStmt { @@ -169,17 +189,3 @@ data class EtsSwitchStmt( return visitor.visit(this) } } - -data class EtsRawStmt( - override val location: EtsInstLocation, - val type: String, - val text: String, -) : EtsStmt { - override fun toString(): String { - return text - } - - override fun accept(visitor: EtsStmt.Visitor): R { - return visitor.visit(this) - } -} diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsType.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsType.kt index 78b16bd69..b0cabd28d 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsType.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsType.kt @@ -21,7 +21,6 @@ import org.jacodb.api.common.CommonTypeName import org.jacodb.ets.model.EtsClassSignature import org.jacodb.ets.model.EtsLocalSignature import org.jacodb.ets.model.EtsMethodSignature -import org.jacodb.ets.model.EtsNamespaceSignature interface EtsType : CommonType, CommonTypeName { override val typeName: String @@ -45,13 +44,16 @@ interface EtsType : CommonType, CommonTypeName { fun visit(type: EtsClassType): R fun visit(type: EtsFunctionType): R fun visit(type: EtsArrayType): R - fun visit(type: EtsArrayObjectType): R fun visit(type: EtsUnclearRefType): R fun visit(type: EtsGenericType): R fun visit(type: EtsAliasType): R - fun visit(type: EtsAnnotationNamespaceType): R - fun visit(type: EtsAnnotationTypeQueryType): R - fun visit(type: EtsLexicalEnvType): R + + fun visit(type: EtsRawType): R { + if (this is Default) { + return defaultVisit(type) + } + error("Cannot handle ${type::class.java.simpleName}: $type") + } interface Default : Visitor { override fun visit(type: EtsAnyType): R = defaultVisit(type) @@ -69,13 +71,10 @@ interface EtsType : CommonType, CommonTypeName { override fun visit(type: EtsClassType): R = defaultVisit(type) override fun visit(type: EtsFunctionType): R = defaultVisit(type) override fun visit(type: EtsArrayType): R = defaultVisit(type) - override fun visit(type: EtsArrayObjectType): R = defaultVisit(type) override fun visit(type: EtsUnclearRefType): R = defaultVisit(type) override fun visit(type: EtsGenericType): R = defaultVisit(type) override fun visit(type: EtsAliasType): R = defaultVisit(type) - override fun visit(type: EtsAnnotationNamespaceType): R = defaultVisit(type) - override fun visit(type: EtsAnnotationTypeQueryType): R = defaultVisit(type) - override fun visit(type: EtsLexicalEnvType): R = defaultVisit(type) + override fun visit(type: EtsRawType): R = defaultVisit(type) fun defaultVisit(type: EtsType): R } @@ -84,6 +83,22 @@ interface EtsType : CommonType, CommonTypeName { fun accept(visitor: Visitor): R } +data class EtsRawType( + val kind: String, + val extra: Map = emptyMap(), +) : EtsType { + override val typeName: String + get() = kind + + override fun toString(): String { + return "$kind $extra" + } + + override fun accept(visitor: EtsType.Visitor): R { + return visitor.visit(this) + } +} + object EtsAnyType : EtsType { override val typeName: String get() = "any" @@ -278,19 +293,6 @@ data class EtsArrayType( } } -data class EtsArrayObjectType( - val elementType: EtsType, -) : EtsRefType { - override val typeName: String - get() = "Array<${elementType.typeName}>" - - override fun toString(): String = typeName - - override fun accept(visitor: EtsType.Visitor): R { - return visitor.visit(this) - } -} - data class EtsUnclearRefType( val name: String, val typeParameters: List = emptyList(), @@ -343,48 +345,3 @@ data class EtsAliasType( return visitor.visit(this) } } - -data class EtsAnnotationNamespaceType( - val originType: String, - val namespaceSignature: EtsNamespaceSignature, -) : EtsType { - override val typeName: String - get() = originType - - override fun toString(): String { - return originType - } - - override fun accept(visitor: EtsType.Visitor): R { - return visitor.visit(this) - } -} - -data class EtsAnnotationTypeQueryType( - val originType: String, -) : EtsType { - override val typeName: String - get() = originType - - override fun toString(): String { - return originType - } - - override fun accept(visitor: EtsType.Visitor): R { - return visitor.visit(this) - } -} - -data class EtsLexicalEnvType( - val nestedMethod: EtsMethodSignature, - val closures: List, -) : EtsType { - override val typeName: String - get() = closures.joinToString(prefix = "[", postfix = "]") - - override fun toString(): String = typeName - - override fun accept(visitor: EtsType.Visitor): R { - return visitor.visit(this) - } -} diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsValue.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsValue.kt index 40224ca8b..ae4212fdb 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsValue.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsValue.kt @@ -32,9 +32,6 @@ interface EtsValue : EtsEntity, CommonValue { // Ref fun visit(value: EtsThis): R fun visit(value: EtsParameterRef): R - fun visit(value: EtsCaughtExceptionRef): R - fun visit(value: EtsGlobalRef): R - fun visit(value: EtsClosureFieldRef): R fun visit(value: EtsArrayAccess): R fun visit(value: EtsInstanceFieldRef): R fun visit(value: EtsStaticFieldRef): R @@ -50,9 +47,6 @@ interface EtsValue : EtsEntity, CommonValue { override fun visit(value: EtsThis): R = defaultVisit(value) override fun visit(value: EtsParameterRef): R = defaultVisit(value) - override fun visit(value: EtsCaughtExceptionRef): R = defaultVisit(value) - override fun visit(value: EtsGlobalRef): R = defaultVisit(value) - override fun visit(value: EtsClosureFieldRef): R = defaultVisit(value) override fun visit(value: EtsArrayAccess): R = defaultVisit(value) override fun visit(value: EtsInstanceFieldRef): R = defaultVisit(value) override fun visit(value: EtsStaticFieldRef): R = defaultVisit(value) diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Convert.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Convert.kt index 4b1b810a1..f92bbcdb3 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Convert.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Convert.kt @@ -20,8 +20,6 @@ import org.jacodb.ets.base.CONSTRUCTOR_NAME import org.jacodb.ets.base.EtsAddExpr import org.jacodb.ets.base.EtsAliasType import org.jacodb.ets.base.EtsAndExpr -import org.jacodb.ets.base.EtsAnnotationNamespaceType -import org.jacodb.ets.base.EtsAnnotationTypeQueryType import org.jacodb.ets.base.EtsAnyType import org.jacodb.ets.base.EtsArrayAccess import org.jacodb.ets.base.EtsArrayType @@ -36,9 +34,7 @@ import org.jacodb.ets.base.EtsBooleanType import org.jacodb.ets.base.EtsCallExpr import org.jacodb.ets.base.EtsCallStmt import org.jacodb.ets.base.EtsCastExpr -import org.jacodb.ets.base.EtsCaughtExceptionRef import org.jacodb.ets.base.EtsClassType -import org.jacodb.ets.base.EtsClosureFieldRef import org.jacodb.ets.base.EtsCommaExpr import org.jacodb.ets.base.EtsConstant import org.jacodb.ets.base.EtsDeleteExpr @@ -50,7 +46,6 @@ import org.jacodb.ets.base.EtsExpr import org.jacodb.ets.base.EtsFieldRef import org.jacodb.ets.base.EtsFunctionType import org.jacodb.ets.base.EtsGenericType -import org.jacodb.ets.base.EtsGlobalRef import org.jacodb.ets.base.EtsGotoStmt import org.jacodb.ets.base.EtsGtEqExpr import org.jacodb.ets.base.EtsGtExpr @@ -62,7 +57,6 @@ import org.jacodb.ets.base.EtsInstanceFieldRef import org.jacodb.ets.base.EtsInstanceOfExpr import org.jacodb.ets.base.EtsLeftShiftExpr import org.jacodb.ets.base.EtsLengthExpr -import org.jacodb.ets.base.EtsLexicalEnvType import org.jacodb.ets.base.EtsLiteralType import org.jacodb.ets.base.EtsLocal import org.jacodb.ets.base.EtsLtEqExpr @@ -85,7 +79,9 @@ import org.jacodb.ets.base.EtsParameterRef import org.jacodb.ets.base.EtsPreDecExpr import org.jacodb.ets.base.EtsPreIncExpr import org.jacodb.ets.base.EtsPtrCallExpr +import org.jacodb.ets.base.EtsRawEntity import org.jacodb.ets.base.EtsRawStmt +import org.jacodb.ets.base.EtsRawType import org.jacodb.ets.base.EtsRemExpr import org.jacodb.ets.base.EtsReturnStmt import org.jacodb.ets.base.EtsRightShiftExpr @@ -274,28 +270,13 @@ class EtsMethodBuilder( is RawStmtDto -> { EtsRawStmt( location = loc(), - type = type, - text = text, + kind = kind, + extra = extra, ) } - - // else -> error("Unknown Stmt: $stmt") } private fun ValueDto.toEtsEntity(): EtsEntity = when (this) { - is UnknownValueDto -> object : EtsEntity { - override val type: EtsType = EtsUnknownType - - override fun toString(): String = "UnknownValue($value)" - - override fun accept(visitor: EtsEntity.Visitor): R { - if (visitor is EtsEntity.Visitor.Default) { - return visitor.defaultVisit(this) - } - error("Cannot handle $this") - } - } - is LocalDto -> toEtsLocal() is ConstantDto -> toEtsConstant() @@ -339,8 +320,6 @@ class EtsMethodBuilder( type = type.toEtsType(), ) - is PhiExprDto -> error("PhiExpr is not supported") - is UnaryOperationDto -> { val arg = arg.toEtsEntity() // Note: `type` is ignored here! @@ -424,21 +403,6 @@ class EtsMethodBuilder( type = type.toEtsType(), ) - is CaughtExceptionRefDto -> EtsCaughtExceptionRef( - type = type.toEtsType(), - ) - - is GlobalRefDto -> EtsGlobalRef( - name = name, - ref = ref?.toEtsEntity() as EtsValue, // TODO: check whether the cast is safe - ) - - is ClosureFieldRefDto -> EtsClosureFieldRef( - base = base.toEtsLocal(), - fieldName = fieldName, - type = type.toEtsType(), - ) - is ArrayRefDto -> EtsArrayAccess( array = array.toEtsEntity() as EtsValue, // TODO: check whether the cast is safe index = index.toEtsEntity() as EtsValue, // TODO: check whether the cast is safe @@ -447,7 +411,11 @@ class EtsMethodBuilder( is FieldRefDto -> toEtsFieldRef() - // else -> error("Unknown Value: $value") + is RawValueDto -> EtsRawEntity( + kind = kind, + extra = extra, + type = type.toEtsType(), + ) } private fun FieldRefDto.toEtsFieldRef(): EtsFieldRef { @@ -591,15 +559,6 @@ fun TypeDto.toEtsType(): EtsType = when (this) { signature = signature.toEtsLocalSignature(), ) - is AnnotationNamespaceTypeDto -> EtsAnnotationNamespaceType( - originType = originType, - namespaceSignature = namespaceSignature.toEtsNamespaceSignature(), - ) - - is AnnotationTypeQueryTypeDto -> EtsAnnotationTypeQueryType( - originType = originType, - ) - AnyTypeDto -> EtsAnyType is ArrayTypeDto -> EtsArrayType( @@ -622,11 +581,6 @@ fun TypeDto.toEtsType(): EtsType = when (this) { constraint = constraint?.toEtsType(), ) - is LexicalEnvTypeDto -> EtsLexicalEnvType( - nestedMethod = nestedMethod.toEtsMethodSignature(), - closures = closures.map { it.toEtsLocal() }, - ) - is LiteralTypeDto -> EtsLiteralType( literalTypeName = literal.toString(), ) @@ -657,6 +611,11 @@ fun TypeDto.toEtsType(): EtsType = when (this) { UnknownTypeDto -> EtsUnknownType VoidTypeDto -> EtsVoidType + + is RawTypeDto -> EtsRawType( + kind = kind, + extra = extra, + ) } fun ClassTypeDto.toEtsClassType(): EtsClassType { diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Model.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Model.kt index 3cb36992a..45cd7be96 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Model.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Model.kt @@ -19,7 +19,6 @@ package org.jacodb.ets.dto import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromStream import java.io.InputStream @@ -33,13 +32,17 @@ data class EtsFileDto( val exportInfos: List, ) { companion object { + private val json = Json { + serializersModule = dtoModule + } + fun loadFromJson(jsonString: String): EtsFileDto { - return Json.decodeFromString(jsonString) + return json.decodeFromString(jsonString) } @OptIn(ExperimentalSerializationApi::class) fun loadFromJson(stream: InputStream): EtsFileDto { - return Json.decodeFromStream(stream) + return json.decodeFromStream(stream) } } } diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Serializers.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Serializers.kt index 8b29759b1..a081a30e4 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Serializers.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Serializers.kt @@ -14,11 +14,8 @@ * limitations under the License. */ -@file:OptIn(ExperimentalSerializationApi::class) - package org.jacodb.ets.dto -import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.KSerializer import kotlinx.serialization.SerializationException import kotlinx.serialization.descriptors.PrimitiveKind @@ -28,12 +25,36 @@ import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.json.JsonDecoder import kotlinx.serialization.json.JsonEncoder +import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.booleanOrNull +import kotlinx.serialization.json.decodeFromJsonElement import kotlinx.serialization.json.double +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive +import kotlinx.serialization.modules.SerializersModule + +internal val stmtModule = SerializersModule { + polymorphicDefaultDeserializer(StmtDto::class) { RawStmtSerializer } +} + +internal val valueModule = SerializersModule { + polymorphicDefaultDeserializer(ValueDto::class) { RawValueSerializer } +} + +internal val typeModule = SerializersModule { + polymorphicDefaultDeserializer(TypeDto::class) { RawTypeSerializer } +} + +internal val dtoModule = SerializersModule { + include(stmtModule) + include(valueModule) + include(typeModule) +} object PrimitiveLiteralSerializer : KSerializer { - override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("PrimitiveLiteral", PrimitiveKind.STRING) + override val descriptor: SerialDescriptor = + PrimitiveSerialDescriptor("PrimitiveLiteral", PrimitiveKind.STRING) override fun serialize(encoder: Encoder, value: PrimitiveLiteralDto) { require(encoder is JsonEncoder) @@ -61,3 +82,62 @@ object PrimitiveLiteralSerializer : KSerializer { } } } + +object RawStmtSerializer : KSerializer { + private val serializer = RawStmtDto.generatedSerializer() + + override val descriptor: SerialDescriptor = serializer.descriptor + + override fun deserialize(decoder: Decoder): RawStmtDto { + require(decoder is JsonDecoder) + val element = decoder.decodeJsonElement().jsonObject + val kind = element.getValue("_").jsonPrimitive.content + val details = element.toMutableMap() + details.remove("_") + return RawStmtDto(kind, JsonObject(details)) + } + + override fun serialize(encoder: Encoder, value: RawStmtDto) { + encoder.encodeSerializableValue(serializer, value) + } +} + +object RawValueSerializer : KSerializer { + private val serializer = RawValueDto.generatedSerializer() + + override val descriptor: SerialDescriptor = serializer.descriptor + + override fun deserialize(decoder: Decoder): RawValueDto { + require(decoder is JsonDecoder) + val element = decoder.decodeJsonElement().jsonObject + val kind = element.getValue("_").jsonPrimitive.content + val type = decoder.json.decodeFromJsonElement(element.getValue("type")) + val details = element.toMutableMap() + details.remove("_") + details.remove("type") + return RawValueDto(kind, JsonObject(details), type) + } + + override fun serialize(encoder: Encoder, value: RawValueDto) { + encoder.encodeSerializableValue(serializer, value) + } +} + +object RawTypeSerializer : KSerializer { + private val serializer = RawTypeDto.generatedSerializer() + + override val descriptor: SerialDescriptor = serializer.descriptor + + override fun deserialize(decoder: Decoder): RawTypeDto { + require(decoder is JsonDecoder) + val element = decoder.decodeJsonElement().jsonObject + val kind = element.getValue("_").jsonPrimitive.content + val details = element.toMutableMap() + details.remove("_") + return RawTypeDto(kind, JsonObject(details)) + } + + override fun serialize(encoder: Encoder, value: RawTypeDto) { + encoder.encodeSerializableValue(serializer, value) + } +} diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Signatures.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Signatures.kt index beb1b5375..54cc32202 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Signatures.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Signatures.kt @@ -16,89 +16,53 @@ package org.jacodb.ets.dto +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable data class FileSignatureDto( val projectName: String, val fileName: String, -) { - override fun toString(): String { - return "@$projectName/$fileName" - } -} +) @Serializable data class NamespaceSignatureDto( val name: String, val declaringFile: FileSignatureDto, val declaringNamespace: NamespaceSignatureDto? = null, -) { - override fun toString(): String { - return if (declaringNamespace != null) { - "$declaringNamespace::$name" - } else { - "$declaringFile::$name" - } - } -} - +) @Serializable data class ClassSignatureDto( val name: String, val declaringFile: FileSignatureDto, val declaringNamespace: NamespaceSignatureDto? = null, -) { - override fun toString(): String { - return if (declaringNamespace != null) { - "$declaringNamespace::$name" - } else { - "$declaringFile::$name" - } - } -} +) @Serializable data class FieldSignatureDto( val declaringClass: ClassSignatureDto, val name: String, val type: TypeDto, -) { - override fun toString(): String { - return "${declaringClass.name}::$name: $type" - } -} +) @Serializable +@SerialName("MethodSignature") data class MethodSignatureDto( val declaringClass: ClassSignatureDto, val name: String, val parameters: List, val returnType: TypeDto, -) { - override fun toString(): String { - val params = parameters.joinToString() - return "${declaringClass.name}::$name($params): $returnType" - } -} +) @Serializable data class MethodParameterDto( val name: String, val type: TypeDto, val isOptional: Boolean = false, -) { - override fun toString(): String { - return "$name: $type" - } -} +) @Serializable data class LocalSignatureDto( val name: String, val method: MethodSignatureDto, -) { - override fun toString(): String { - return "${method}#${name}" - } -} +) diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Stmts.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Stmts.kt index ccf2bf9b0..56f0da981 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Stmts.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Stmts.kt @@ -17,15 +17,26 @@ package org.jacodb.ets.dto import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.KeepGeneratedSerializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator +import kotlinx.serialization.json.JsonObject @Serializable @OptIn(ExperimentalSerializationApi::class) @JsonClassDiscriminator("_") sealed interface StmtDto +@Serializable(with = RawStmtSerializer::class) +@SerialName("RawStmt") +@OptIn(ExperimentalSerializationApi::class) +@KeepGeneratedSerializer +data class RawStmtDto( + val kind: String, // constructor name + val extra: JsonObject, +) : StmtDto + @Serializable @SerialName("NopStmt") data object NopStmtDto : StmtDto @@ -35,21 +46,13 @@ data object NopStmtDto : StmtDto data class AssignStmtDto( val left: ValueDto, val right: ValueDto, -) : StmtDto { - override fun toString(): String { - return "$left = $right" - } -} +) : StmtDto @Serializable @SerialName("CallStmt") data class CallStmtDto( val expr: CallExprDto, -) : StmtDto { - override fun toString(): String { - return expr.toString() - } -} +) : StmtDto @Serializable sealed interface TerminatingStmtDto : StmtDto @@ -62,11 +65,7 @@ data object ReturnVoidStmtDto : TerminatingStmtDto @SerialName("ReturnStmt") data class ReturnStmtDto( val arg: ValueDto, -) : TerminatingStmtDto { - override fun toString(): String { - return "return $arg" - } -} +) : TerminatingStmtDto @Serializable @SerialName("ThrowStmt") @@ -93,10 +92,3 @@ data class SwitchStmtDto( val arg: ValueDto, val cases: List, ) : BranchingStmtDto - -@Serializable -@SerialName("RawStmt") -data class RawStmtDto( - val type: String, // constructor name - val text: String, // toString -) : StmtDto diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Types.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Types.kt index 17d58f9ee..e7ad33a76 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Types.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Types.kt @@ -17,66 +17,53 @@ package org.jacodb.ets.dto import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.KeepGeneratedSerializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator +import kotlinx.serialization.json.JsonObject @Serializable @OptIn(ExperimentalSerializationApi::class) @JsonClassDiscriminator("_") sealed interface TypeDto +@Serializable(with = RawTypeSerializer::class) +@SerialName("RawType") +@OptIn(ExperimentalSerializationApi::class) +@KeepGeneratedSerializer +data class RawTypeDto( + val kind: String, // constructor name + val extra: JsonObject, +) : TypeDto + @Serializable @SerialName("AnyType") -object AnyTypeDto : TypeDto { - override fun toString(): String { - return "any" - } -} +data object AnyTypeDto : TypeDto @Serializable @SerialName("UnknownType") -object UnknownTypeDto : TypeDto { - override fun toString(): String { - return "unknown" - } -} +data object UnknownTypeDto : TypeDto @Serializable @SerialName("VoidType") -object VoidTypeDto : TypeDto { - override fun toString(): String { - return "void" - } -} +data object VoidTypeDto : TypeDto @Serializable @SerialName("NeverType") -object NeverTypeDto : TypeDto { - override fun toString(): String { - return "never" - } -} +data object NeverTypeDto : TypeDto @Serializable @SerialName("UnionType") data class UnionTypeDto( val types: List, -) : TypeDto { - override fun toString(): String { - return types.joinToString(" | ") - } -} +) : TypeDto @Serializable @SerialName("TupleType") data class TupleTypeDto( val types: List, -) : TypeDto { - override fun toString(): String { - return "[${types.joinToString()}]" - } -} +) : TypeDto @Serializable sealed interface PrimitiveTypeDto : TypeDto { @@ -85,57 +72,37 @@ sealed interface PrimitiveTypeDto : TypeDto { @Serializable @SerialName("BooleanType") -object BooleanTypeDto : PrimitiveTypeDto { +data object BooleanTypeDto : PrimitiveTypeDto { override val name: String get() = "boolean" - - override fun toString(): String { - return name - } } @Serializable @SerialName("NumberType") -object NumberTypeDto : PrimitiveTypeDto { +data object NumberTypeDto : PrimitiveTypeDto { override val name: String get() = "number" - - override fun toString(): String { - return name - } } @Serializable @SerialName("StringType") -object StringTypeDto : PrimitiveTypeDto { +data object StringTypeDto : PrimitiveTypeDto { override val name: String get() = "string" - - override fun toString(): String { - return name - } } @Serializable @SerialName("NullType") -object NullTypeDto : PrimitiveTypeDto { +data object NullTypeDto : PrimitiveTypeDto { override val name: String get() = "null" - - override fun toString(): String { - return name - } } @Serializable @SerialName("UndefinedType") -object UndefinedTypeDto : PrimitiveTypeDto { +data object UndefinedTypeDto : PrimitiveTypeDto { override val name: String get() = "undefined" - - override fun toString(): String { - return name - } } @Serializable @@ -145,25 +112,15 @@ data class LiteralTypeDto( ) : PrimitiveTypeDto { override val name: String get() = literal.toString() - - override fun toString(): String { - return name - } } @Serializable(with = PrimitiveLiteralSerializer::class) sealed class PrimitiveLiteralDto { - data class StringLiteral(val value: String) : PrimitiveLiteralDto() { - override fun toString(): String = value - } + data class StringLiteral(val value: String) : PrimitiveLiteralDto() - data class NumberLiteral(val value: Double) : PrimitiveLiteralDto() { - override fun toString(): String = value.toString() - } + data class NumberLiteral(val value: Double) : PrimitiveLiteralDto() - data class BooleanLiteral(val value: Boolean) : PrimitiveLiteralDto() { - override fun toString(): String = value.toString() - } + data class BooleanLiteral(val value: Boolean) : PrimitiveLiteralDto() } @Serializable @@ -171,60 +128,28 @@ sealed class PrimitiveLiteralDto { data class ClassTypeDto( val signature: ClassSignatureDto, val typeParameters: List = emptyList(), -) : TypeDto { - override fun toString(): String { - return if (typeParameters.isNotEmpty()) { - val generics = typeParameters.joinToString() - "$signature<$generics>" - } else { - signature.toString() - } - } -} +) : TypeDto @Serializable @SerialName("FunctionType") data class FunctionTypeDto( val signature: MethodSignatureDto, val typeParameters: List = emptyList(), -) : TypeDto { - override fun toString(): String { - val params = signature.parameters.joinToString() - return if (typeParameters.isNotEmpty()) { - val generics = typeParameters.joinToString() - "${signature.name}<$generics>($params): ${signature.returnType}" - } else { - "${signature.name}($params): ${signature.returnType}" - } - } -} +) : TypeDto @Serializable @SerialName("ArrayType") data class ArrayTypeDto( val elementType: TypeDto, val dimensions: Int, -) : TypeDto { - override fun toString(): String { - return "$elementType" + "[]".repeat(dimensions) - } -} +) : TypeDto @Serializable @SerialName("UnclearReferenceType") data class UnclearReferenceTypeDto( val name: String, val typeParameters: List = emptyList(), -) : TypeDto { - override fun toString(): String { - return if (typeParameters.isNotEmpty()) { - val generics = typeParameters.joinToString() - "$name<$generics>" - } else { - name - } - } -} +) : TypeDto @Serializable @SerialName("GenericType") @@ -232,11 +157,7 @@ data class GenericTypeDto( val name: String, val defaultType: TypeDto? = null, val constraint: TypeDto? = null, -) : TypeDto { - override fun toString(): String { - return name + (constraint?.let { " extends $it" } ?: "") + (defaultType?.let { " = $it" } ?: "") - } -} +) : TypeDto @Serializable @SerialName("AliasType") @@ -244,40 +165,4 @@ data class AliasTypeDto( val name: String, val originalType: TypeDto, val signature: LocalSignatureDto, -) : TypeDto { - override fun toString(): String { - return "$name = $originalType" - } -} - -@Serializable -@SerialName("AnnotationNamespaceType") -data class AnnotationNamespaceTypeDto( - val originType: String, - val namespaceSignature: NamespaceSignatureDto, -) : TypeDto { - override fun toString(): String { - return originType - } -} - -@Serializable -@SerialName("AnnotationTypeQueryType") -data class AnnotationTypeQueryTypeDto( - val originType: String, -) : TypeDto { - override fun toString(): String { - return originType - } -} - -@Serializable -@SerialName("LexicalEnvType") -data class LexicalEnvTypeDto( - val nestedMethod: MethodSignatureDto, - val closures: List, -) : TypeDto { - override fun toString(): String { - return closures.joinToString(prefix = "[", postfix = "]") - } -} +) : TypeDto diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Values.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Values.kt index b9c8928cf..8072c99c5 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Values.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Values.kt @@ -17,9 +17,11 @@ package org.jacodb.ets.dto import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.KeepGeneratedSerializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator +import kotlinx.serialization.json.JsonObject @Serializable @OptIn(ExperimentalSerializationApi::class) @@ -28,18 +30,15 @@ sealed interface ValueDto { val type: TypeDto } -@Serializable -@SerialName("UNKNOWN_VALUE") -data class UnknownValueDto( - val value: String, -) : ValueDto { - override val type: TypeDto - get() = UnknownTypeDto - - override fun toString(): String { - return "UNKNOWN($value)" - } -} +@Serializable(with = RawValueSerializer::class) +@SerialName("RawValue") +@OptIn(ExperimentalSerializationApi::class) +@KeepGeneratedSerializer +data class RawValueDto( + val kind: String, // constructor name + val extra: JsonObject, + override val type: TypeDto, +) : ValueDto @Serializable sealed interface ImmediateDto : ValueDto @@ -49,22 +48,14 @@ sealed interface ImmediateDto : ValueDto data class LocalDto( val name: String, override val type: TypeDto, -) : ImmediateDto { - override fun toString(): String { - return name - } -} +) : ImmediateDto @Serializable @SerialName("Constant") data class ConstantDto( val value: String, override val type: TypeDto, -) : ImmediateDto { - override fun toString(): String { - return "'$value': $type" - } -} +) : ImmediateDto // TODO: uncomment and adapt the following code for different constants // Currently, ArkIR stores all constants as strings (see ConstantDto above), @@ -140,11 +131,7 @@ data class NewExprDto( val classType: TypeDto, // ClassType ) : ExprDto { override val type: TypeDto - get() = classType as ClassTypeDto // safe cast - - override fun toString(): String { - return "new $type()" - } + get() = classType } @Serializable @@ -155,10 +142,6 @@ data class NewArrayExprDto( ) : ExprDto { override val type: TypeDto get() = ArrayTypeDto(elementType, 1) - - override fun toString(): String { - return "new Array<$elementType>($size)" - } } @Serializable @@ -168,10 +151,6 @@ data class DeleteExprDto( ) : ExprDto { override val type: TypeDto get() = BooleanTypeDto - - override fun toString(): String { - return "delete $arg" - } } @Serializable @@ -181,10 +160,6 @@ data class AwaitExprDto( ) : ExprDto { override val type: TypeDto get() = arg.type - - override fun toString(): String { - return "await $arg" - } } @Serializable @@ -194,10 +169,6 @@ data class YieldExprDto( ) : ExprDto { override val type: TypeDto get() = arg.type - - override fun toString(): String { - return "yield $arg" - } } @Serializable @@ -207,10 +178,6 @@ data class TypeOfExprDto( ) : ExprDto { override val type: TypeDto get() = StringTypeDto - - override fun toString(): String { - return "typeof $arg" - } } @Serializable @@ -221,10 +188,6 @@ data class InstanceOfExprDto( ) : ExprDto { override val type: TypeDto get() = BooleanTypeDto - - override fun toString(): String { - return "$arg instanceof $checkType" - } } @Serializable @@ -234,10 +197,6 @@ data class LengthExprDto( ) : ExprDto { override val type: TypeDto get() = NumberTypeDto - - override fun toString(): String { - return "$arg.length" - } } @Serializable @@ -245,23 +204,7 @@ data class LengthExprDto( data class CastExprDto( val arg: ValueDto, override val type: TypeDto, -) : ExprDto { - override fun toString(): String { - return "$arg as $type" - } -} - -@Serializable -@SerialName("PhiExpr") -data class PhiExprDto( - val args: List, - val blocks: List, - override val type: TypeDto, -) : ExprDto { - override fun toString(): String { - return "phi(${args.joinToString()})" - } -} +) : ExprDto @Serializable sealed interface UnaryExprDto : ExprDto { @@ -276,11 +219,7 @@ sealed interface UnaryExprDto : ExprDto { data class UnaryOperationDto( val op: String, override val arg: ValueDto, -) : UnaryExprDto { - override fun toString(): String { - return "$op $arg" - } -} +) : UnaryExprDto @Serializable sealed interface BinaryExprDto : ExprDto { @@ -295,11 +234,7 @@ data class BinaryOperationDto( override val left: ValueDto, override val right: ValueDto, override val type: TypeDto = UnknownTypeDto, -) : BinaryExprDto { - override fun toString(): String { - return "$left $op $right" - } -} +) : BinaryExprDto @Serializable sealed interface ConditionExprDto : BinaryExprDto @@ -311,11 +246,7 @@ data class RelationOperationDto( override val left: ValueDto, override val right: ValueDto, override val type: TypeDto = UnknownTypeDto, -) : ConditionExprDto { - override fun toString(): String { - return "$left $op $right" - } -} +) : ConditionExprDto @Serializable sealed interface CallExprDto : ExprDto { @@ -332,22 +263,14 @@ data class InstanceCallExprDto( val instance: ValueDto, // Local override val method: MethodSignatureDto, override val args: List, -) : CallExprDto { - override fun toString(): String { - return "$instance.${method.name}(${args.joinToString()})" - } -} +) : CallExprDto @Serializable @SerialName("StaticCallExpr") data class StaticCallExprDto( override val method: MethodSignatureDto, override val args: List, -) : CallExprDto { - override fun toString(): String { - return "${method.name}(${args.joinToString()})" - } -} +) : CallExprDto @Serializable @SerialName("PtrCallExpr") @@ -355,11 +278,7 @@ data class PtrCallExprDto( val ptr: ValueDto, // Local override val method: MethodSignatureDto, override val args: List, -) : CallExprDto { - override fun toString(): String { - return "$ptr@${method.declaringClass.name}::${method.name}(${args.joinToString()})" - } -} +) : CallExprDto @Serializable sealed interface RefDto : ValueDto @@ -368,58 +287,38 @@ sealed interface RefDto : ValueDto @SerialName("ThisRef") data class ThisRefDto( override val type: TypeDto, // ClassType -) : RefDto { - override fun toString(): String { - return "this" - } -} +) : RefDto @Serializable @SerialName("ParameterRef") data class ParameterRefDto( val index: Int, override val type: TypeDto, -) : RefDto { - override fun toString(): String { - return "arg$index" - } -} - -@Serializable -@SerialName("CaughtExceptionRef") -data class CaughtExceptionRefDto( - override val type: TypeDto, -) : RefDto { - override fun toString(): String { - return "catch($type)" - } -} +) : RefDto -@Serializable -@SerialName("GlobalRef") -data class GlobalRefDto( - val name: String, - val ref: ValueDto?, -) : RefDto { - override val type: TypeDto - get() = ref?.type ?: UnknownTypeDto - - override fun toString(): String { - return "global $name" - } -} - -@Serializable -@SerialName("ClosureFieldRef") -data class ClosureFieldRefDto( - val base: LocalDto, - val fieldName: String, - override val type: TypeDto, -) : RefDto { - override fun toString(): String { - return "$base.$fieldName" - } -} +// @Serializable +// @SerialName("CaughtExceptionRef") +// data class CaughtExceptionRefDto( +// override val type: TypeDto, +// ) : RefDto +// +// @Serializable +// @SerialName("GlobalRef") +// data class GlobalRefDto( +// val name: String, +// val ref: ValueDto?, +// ) : RefDto { +// override val type: TypeDto +// get() = ref?.type ?: UnknownTypeDto +// } +// +// @Serializable +// @SerialName("ClosureFieldRef") +// data class ClosureFieldRefDto( +// val base: LocalDto, +// val fieldName: String, +// override val type: TypeDto, +// ) : RefDto @Serializable @SerialName("ArrayRef") @@ -427,11 +326,7 @@ data class ArrayRefDto( val array: ValueDto, val index: ValueDto, override val type: TypeDto, -) : RefDto { - override fun toString(): String { - return "$array[$index]" - } -} +) : RefDto @Serializable sealed interface FieldRefDto : RefDto { @@ -446,18 +341,10 @@ sealed interface FieldRefDto : RefDto { data class InstanceFieldRefDto( val instance: ValueDto, // Local override val field: FieldSignatureDto, -) : FieldRefDto { - override fun toString(): String { - return "$instance.${field.name}" - } -} +) : FieldRefDto @Serializable @SerialName("StaticFieldRef") data class StaticFieldRefDto( override val field: FieldSignatureDto, -) : FieldRefDto { - override fun toString(): String { - return "${field.declaringClass.name}.${field.name}" - } -} +) : FieldRefDto diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/GetOperands.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/GetOperands.kt index 6dbaee0d2..971d9debb 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/GetOperands.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/GetOperands.kt @@ -28,15 +28,12 @@ import org.jacodb.ets.base.EtsBitXorExpr import org.jacodb.ets.base.EtsBooleanConstant import org.jacodb.ets.base.EtsCallStmt import org.jacodb.ets.base.EtsCastExpr -import org.jacodb.ets.base.EtsCaughtExceptionRef -import org.jacodb.ets.base.EtsClosureFieldRef import org.jacodb.ets.base.EtsCommaExpr import org.jacodb.ets.base.EtsDeleteExpr import org.jacodb.ets.base.EtsDivExpr import org.jacodb.ets.base.EtsEntity import org.jacodb.ets.base.EtsEqExpr import org.jacodb.ets.base.EtsExpExpr -import org.jacodb.ets.base.EtsGlobalRef import org.jacodb.ets.base.EtsGotoStmt import org.jacodb.ets.base.EtsGtEqExpr import org.jacodb.ets.base.EtsGtExpr @@ -67,6 +64,7 @@ import org.jacodb.ets.base.EtsPostIncExpr import org.jacodb.ets.base.EtsPreDecExpr import org.jacodb.ets.base.EtsPreIncExpr import org.jacodb.ets.base.EtsPtrCallExpr +import org.jacodb.ets.base.EtsRawEntity import org.jacodb.ets.base.EtsRawStmt import org.jacodb.ets.base.EtsRemExpr import org.jacodb.ets.base.EtsReturnStmt @@ -303,12 +301,6 @@ private object EntityGetOperands : EtsEntity.Visitor> { override fun visit(expr: EtsTernaryExpr): Sequence = sequenceOf(expr.condition, expr.thenExpr, expr.elseExpr) - override fun visit(value: EtsCaughtExceptionRef): Sequence = + override fun visit(value: EtsRawEntity): Sequence = emptySequence() - - override fun visit(value: EtsGlobalRef): Sequence = - if (value.ref != null) sequenceOf(value.ref) else emptySequence() - - override fun visit(value: EtsClosureFieldRef): Sequence = - sequenceOf(value.base) } diff --git a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsFromJsonTest.kt b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsFromJsonTest.kt index 61f149313..5449835ac 100644 --- a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsFromJsonTest.kt +++ b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsFromJsonTest.kt @@ -16,9 +16,8 @@ package org.jacodb.ets.test -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +import kotlinx.serialization.json.jsonPrimitive import mu.KotlinLogging import org.jacodb.ets.base.DEFAULT_ARK_CLASS_NAME import org.jacodb.ets.base.DEFAULT_ARK_METHOD_NAME @@ -38,9 +37,14 @@ import org.jacodb.ets.dto.LocalDto import org.jacodb.ets.dto.MethodDto import org.jacodb.ets.dto.NumberTypeDto import org.jacodb.ets.dto.PrimitiveLiteralDto +import org.jacodb.ets.dto.RawStmtDto +import org.jacodb.ets.dto.RawTypeDto +import org.jacodb.ets.dto.RawValueDto import org.jacodb.ets.dto.ReturnVoidStmtDto import org.jacodb.ets.dto.StmtDto import org.jacodb.ets.dto.TypeDto +import org.jacodb.ets.dto.ValueDto +import org.jacodb.ets.dto.dtoModule import org.jacodb.ets.dto.toEtsLocal import org.jacodb.ets.dto.toEtsMethod import org.jacodb.ets.model.EtsClassSignature @@ -76,6 +80,7 @@ class EtsFromJsonTest { private val json = Json { // classDiscriminator = "_" prettyPrint = true + serializersModule = dtoModule } @JvmStatic @@ -420,4 +425,51 @@ class EtsFromJsonTest { assertIs(typeDto) assertEquals(PrimitiveLiteralDto.StringLiteral("hello"), typeDto.literal) } + + @Test + fun testLoadRawTypeFromJson() { + val jsonString = """ + { + "_": "DummyType", + "value": 42 + } + """.trimIndent() + val typeDto = json.decodeFromString(jsonString) + logger.info { "typeDto = $typeDto" } + assertIs(typeDto) + assertEquals("DummyType", typeDto.kind) + assertEquals(42, typeDto.extra.getValue("value").jsonPrimitive.content.toInt()) + } + + @Test + fun testLoadRawValueFromJson() { + val jsonString = """ + { + "_": "DummyValue", + "value": 42, + "type": { "_": "NumberType" } + } + """.trimIndent() + val valueDto = json.decodeFromString(jsonString) + logger.info { "valueDto = $valueDto" } + assertIs(valueDto) + assertEquals("DummyValue", valueDto.kind) + assertEquals(NumberTypeDto, valueDto.type) + assertEquals(42, valueDto.extra.getValue("value").jsonPrimitive.content.toInt()) + } + + @Test + fun testLoadRawStmtFromJson() { + val jsonString = """ + { + "_": "DummyStmt", + "value": 42 + } + """.trimIndent() + val stmtDto = json.decodeFromString(jsonString) + logger.info { "stmtDto = $stmtDto" } + assertIs(stmtDto) + assertEquals("DummyStmt", stmtDto.kind) + assertEquals(42, stmtDto.extra.getValue("value").jsonPrimitive.content.toInt()) + } }