diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsConstant.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsConstant.kt index 508a93b7e..f81daf77a 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsConstant.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsConstant.kt @@ -89,41 +89,3 @@ object EtsUndefinedConstant : EtsConstant { return visitor.visit(this) } } - -data class EtsArrayLiteral( - val elements: List, - override val type: EtsType, -) : EtsConstant { - - init { - if (type is EtsArrayType) { - require(type.dimensions == 1) { - "Array type of array literal must have exactly one dimension" - } - } - } - - override fun toString(): String { - return elements.joinToString(prefix = "[", postfix = "]") - } - - override fun accept(visitor: EtsValue.Visitor): R { - return visitor.visit(this) - } -} - -// TODO: see TypeScript reference for different types of elements inside object literals, such as property assignment, shorthand property assignment, method definition, spread assignment, and getter/setter accessors. -data class EtsObjectLiteral( - val properties: List>, - override val type: EtsType, -) : EtsConstant { - override fun toString(): String { - return properties.joinToString(prefix = "{", postfix = "}") { (name, value) -> - "$name: $value" - } - } - - override fun accept(visitor: EtsValue.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 72a98493a..ff84a89d0 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,6 +45,48 @@ 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 EtsArrayAccess( val array: EtsValue, val index: 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 1efd08e63..6b66c197a 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,6 +42,7 @@ interface EtsStmt : CommonInst { fun visit(stmt: EtsGotoStmt): R fun visit(stmt: EtsIfStmt): R fun visit(stmt: EtsSwitchStmt): R + fun visit(stmt: EtsRawStmt): R interface Default : Visitor { override fun visit(stmt: EtsNopStmt): R = defaultVisit(stmt) @@ -52,6 +53,7 @@ interface EtsStmt : CommonInst { override fun visit(stmt: EtsGotoStmt): R = defaultVisit(stmt) override fun visit(stmt: EtsIfStmt): R = defaultVisit(stmt) override fun visit(stmt: EtsSwitchStmt): R = defaultVisit(stmt) + override fun visit(stmt: EtsRawStmt): R = defaultVisit(stmt) fun defaultVisit(stmt: EtsStmt): R } @@ -167,3 +169,17 @@ 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 22c380522..78b16bd69 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 @@ -51,6 +51,7 @@ interface EtsType : CommonType, CommonTypeName { fun visit(type: EtsAliasType): R fun visit(type: EtsAnnotationNamespaceType): R fun visit(type: EtsAnnotationTypeQueryType): R + fun visit(type: EtsLexicalEnvType): R interface Default : Visitor { override fun visit(type: EtsAnyType): R = defaultVisit(type) @@ -74,6 +75,7 @@ interface EtsType : CommonType, CommonTypeName { 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) fun defaultVisit(type: EtsType): R } @@ -372,3 +374,17 @@ data class EtsAnnotationTypeQueryType( 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 6ef988243..40224ca8b 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 @@ -28,12 +28,13 @@ interface EtsValue : EtsEntity, CommonValue { fun visit(value: EtsNumberConstant): R fun visit(value: EtsNullConstant): R fun visit(value: EtsUndefinedConstant): R - fun visit(value: EtsArrayLiteral): R - fun visit(value: EtsObjectLiteral): R // 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 @@ -46,11 +47,12 @@ interface EtsValue : EtsEntity, CommonValue { override fun visit(value: EtsNumberConstant): R = defaultVisit(value) override fun visit(value: EtsNullConstant): R = defaultVisit(value) override fun visit(value: EtsUndefinedConstant): R = defaultVisit(value) - override fun visit(value: EtsArrayLiteral): R = defaultVisit(value) - override fun visit(value: EtsObjectLiteral): R = defaultVisit(value) 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/Graph.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Cfg.kt similarity index 100% rename from jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Graph.kt rename to jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Cfg.kt 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 81605cd7b..6d2e8b197 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 @@ -24,7 +24,6 @@ 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.EtsArrayLiteral import org.jacodb.ets.base.EtsArrayType import org.jacodb.ets.base.EtsAssignStmt import org.jacodb.ets.base.EtsAwaitExpr @@ -37,7 +36,9 @@ 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 @@ -49,6 +50,7 @@ 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 @@ -60,6 +62,7 @@ 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 @@ -77,7 +80,6 @@ import org.jacodb.ets.base.EtsNullType import org.jacodb.ets.base.EtsNullishCoalescingExpr import org.jacodb.ets.base.EtsNumberConstant import org.jacodb.ets.base.EtsNumberType -import org.jacodb.ets.base.EtsObjectLiteral import org.jacodb.ets.base.EtsOrExpr import org.jacodb.ets.base.EtsParameterRef import org.jacodb.ets.base.EtsPreDecExpr @@ -105,6 +107,7 @@ import org.jacodb.ets.base.EtsUnclearRefType import org.jacodb.ets.base.EtsUndefinedConstant import org.jacodb.ets.base.EtsUndefinedType import org.jacodb.ets.base.EtsUnionType +import org.jacodb.ets.base.EtsRawStmt import org.jacodb.ets.base.EtsUnknownType import org.jacodb.ets.base.EtsUnsignedRightShiftExpr import org.jacodb.ets.base.EtsValue @@ -116,7 +119,6 @@ import org.jacodb.ets.model.EtsClass import org.jacodb.ets.model.EtsClassImpl import org.jacodb.ets.model.EtsClassSignature import org.jacodb.ets.model.EtsDecorator -import org.jacodb.ets.model.EtsField import org.jacodb.ets.model.EtsFieldImpl import org.jacodb.ets.model.EtsFieldSignature import org.jacodb.ets.model.EtsFieldSubSignature @@ -130,6 +132,7 @@ import org.jacodb.ets.model.EtsMethodSignature import org.jacodb.ets.model.EtsModifiers import org.jacodb.ets.model.EtsNamespace import org.jacodb.ets.model.EtsNamespaceSignature +import org.jacodb.ets.model.EtsField class EtsMethodBuilder( signature: EtsMethodSignature, @@ -156,7 +159,7 @@ class EtsMethodBuilder( fun build(cfgDto: CfgDto): EtsMethod { require(!built) { "Method has already been built" } - val cfg = convertToEtsCfg(cfgDto) + val cfg = cfgDto.toEtsCfg() etsMethod._cfg = cfg built = true return etsMethod @@ -186,306 +189,285 @@ class EtsMethodBuilder( } } - fun convertToEtsStmt(stmt: StmtDto): EtsStmt { - return when (stmt) { - is UnknownStmtDto -> object : EtsStmt { - override val location: EtsInstLocation = loc() - - override fun toString(): String = "UnknownStmt(${stmt.stmt})" - - // TODO: equals/hashCode ??? - - override fun accept(visitor: EtsStmt.Visitor): R { - error("UnknownStmt is not supported") - } - } + private fun StmtDto.toEtsStmt(): EtsStmt = when (this) { + is NopStmtDto -> { + EtsNopStmt(location = loc()) + } - is NopStmtDto -> { - EtsNopStmt(location = loc()) + is AssignStmtDto -> { + val lhv = left.toEtsEntity() as EtsValue // safe cast + check(lhv is EtsLocal || lhv is EtsFieldRef || lhv is EtsArrayAccess) { + "LHV of AssignStmt should be EtsLocal, EtsFieldRef, or EtsArrayAccess, but got $lhv" } - - is AssignStmtDto -> { - val lhv = convertToEtsEntity(stmt.left) as EtsValue // safe cast - check(lhv is EtsLocal || lhv is EtsFieldRef || lhv is EtsArrayAccess) { - "LHV of AssignStmt should be EtsLocal, EtsFieldRef, or EtsArrayAccess, but got $lhv" - } - val rhv = convertToEtsEntity(stmt.right).let { rhv -> - if (lhv is EtsLocal) { - if (rhv is EtsCastExpr && rhv.arg is EtsExpr) { - EtsCastExpr(ensureLocal(rhv.arg), rhv.type) - } else { - rhv - } - } else if (rhv is EtsCastExpr || rhv is EtsNewExpr) { - rhv + val rhv = right.toEtsEntity().let { rhv -> + if (lhv is EtsLocal) { + if (rhv is EtsCastExpr && rhv.arg is EtsExpr) { + EtsCastExpr(ensureLocal(rhv.arg), rhv.type) } else { - ensureOneAddress(rhv) + rhv } + } else if (rhv is EtsCastExpr || rhv is EtsNewExpr) { + rhv + } else { + ensureOneAddress(rhv) } - EtsAssignStmt( - location = loc(), - lhv = lhv, - rhv = rhv, - ) } + EtsAssignStmt( + location = loc(), + lhv = lhv, + rhv = rhv, + ) + } - is CallStmtDto -> { - val expr = convertToEtsEntity(stmt.expr) as EtsCallExpr - EtsCallStmt( - location = loc(), - expr = expr, - ) - } + is CallStmtDto -> { + val expr = expr.toEtsEntity() as EtsCallExpr // safe cast + EtsCallStmt( + location = loc(), + expr = expr, + ) + } - is ReturnStmtDto -> { - val returnValue = ensureOneAddress(convertToEtsEntity(stmt.arg)) - EtsReturnStmt( - location = loc(), - returnValue = returnValue, - ) - } + is ReturnStmtDto -> { + val returnValue = ensureOneAddress(arg.toEtsEntity()) + EtsReturnStmt( + location = loc(), + returnValue = returnValue, + ) + } - is ReturnVoidStmtDto -> { - EtsReturnStmt( - location = loc(), - returnValue = null, - ) - } + is ReturnVoidStmtDto -> { + EtsReturnStmt( + location = loc(), + returnValue = null, + ) + } - is ThrowStmtDto -> { - val arg = convertToEtsEntity(stmt.arg) - EtsThrowStmt( - location = loc(), - arg = arg, - ) - } + is ThrowStmtDto -> { + val arg = arg.toEtsEntity() + EtsThrowStmt( + location = loc(), + arg = arg, + ) + } - is GotoStmtDto -> { - EtsGotoStmt(location = loc()) - } + is GotoStmtDto -> { + EtsGotoStmt(location = loc()) + } - is IfStmtDto -> { - val condition = convertToEtsEntity(stmt.condition) - EtsIfStmt( - location = loc(), - condition = condition, - ) - } + is IfStmtDto -> { + val condition = condition.toEtsEntity() + EtsIfStmt( + location = loc(), + condition = condition, + ) + } - is SwitchStmtDto -> { - val arg = convertToEtsEntity(stmt.arg) - val cases = stmt.cases.map { convertToEtsEntity(it) } - EtsSwitchStmt( - location = loc(), - arg = arg, - cases = cases, - ) - } + is SwitchStmtDto -> { + val arg = arg.toEtsEntity() + val cases = cases.map { it.toEtsEntity() } + EtsSwitchStmt( + location = loc(), + arg = arg, + cases = cases, + ) + } - // else -> error("Unknown Stmt: $stmt") + is RawStmtDto -> { + EtsRawStmt( + location = loc(), + type = type, + text = text, + ) } + + // else -> error("Unknown Stmt: $stmt") } - fun convertToEtsEntity(value: ValueDto): EtsEntity { - return when (value) { - is UnknownValueDto -> object : EtsEntity { - override val type: EtsType = EtsUnknownType + private fun ValueDto.toEtsEntity(): EtsEntity = when (this) { + is UnknownValueDto -> object : EtsEntity { + override val type: EtsType = EtsUnknownType - override fun toString(): String = "UnknownValue(${value.value})" + 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") + override fun accept(visitor: EtsEntity.Visitor): R { + if (visitor is EtsEntity.Visitor.Default) { + return visitor.defaultVisit(this) } + error("Cannot handle $this") } + } - is LocalDto -> convertToEtsLocal(value) - - is ConstantDto -> convertToEtsConstant(value) - - is NewExprDto -> EtsNewExpr( - type = convertToEtsType(value.classType) // TODO: safe cast to ClassType - ) - - is NewArrayExprDto -> EtsNewArrayExpr( - elementType = convertToEtsType(value.elementType), - size = convertToEtsEntity(value.size), - ) + is LocalDto -> toEtsLocal() - is DeleteExprDto -> EtsDeleteExpr( - arg = convertToEtsEntity(value.arg) - ) + is ConstantDto -> toEtsConstant() - is AwaitExprDto -> EtsAwaitExpr( - arg = convertToEtsEntity(value.arg) - ) + is NewExprDto -> EtsNewExpr( + type = classType.toEtsType() // TODO: safe cast to ClassType + ) - is YieldExprDto -> EtsYieldExpr( - arg = convertToEtsEntity(value.arg) - ) + is NewArrayExprDto -> EtsNewArrayExpr( + elementType = elementType.toEtsType(), + size = size.toEtsEntity(), + ) - is TypeOfExprDto -> EtsTypeOfExpr( - arg = convertToEtsEntity(value.arg) - ) + is DeleteExprDto -> EtsDeleteExpr( + arg = arg.toEtsEntity(), + ) - is InstanceOfExprDto -> EtsInstanceOfExpr( - arg = convertToEtsEntity(value.arg), - checkType = convertToEtsType(value.checkType), - ) + is AwaitExprDto -> EtsAwaitExpr( + arg = arg.toEtsEntity(), + ) - is LengthExprDto -> EtsLengthExpr( - arg = convertToEtsEntity(value.arg) - ) + is YieldExprDto -> EtsYieldExpr( + arg = arg.toEtsEntity(), + ) - is CastExprDto -> EtsCastExpr( - arg = convertToEtsEntity(value.arg), - type = convertToEtsType(value.type), - ) + is TypeOfExprDto -> EtsTypeOfExpr( + arg = arg.toEtsEntity(), + ) - is PhiExprDto -> error("PhiExpr is not supported") + is InstanceOfExprDto -> EtsInstanceOfExpr( + arg = arg.toEtsEntity(), + checkType = checkType.toEtsType(), + ) - is ArrayLiteralDto -> EtsArrayLiteral( - elements = value.elements.map { convertToEtsEntity(it) }, - type = convertToEtsType(value.type), // TODO: as EtsArrayType, - ) + is LengthExprDto -> EtsLengthExpr( + arg = arg.toEtsEntity(), + ) - is ObjectLiteralDto -> EtsObjectLiteral( - properties = emptyList(), // TODO - type = convertToEtsType(value.type), - ) + is CastExprDto -> EtsCastExpr( + arg = arg.toEtsEntity(), + type = type.toEtsType(), + ) - is UnaryOperationDto -> { - val arg = convertToEtsEntity(value.arg) - // Note: `value.type` is ignored here! - when (value.op) { - Ops.NOT -> EtsNotExpr(arg) - Ops.BIT_NOT -> EtsBitNotExpr(arg.type, arg) - Ops.MINUS -> EtsNegExpr(arg.type, arg) - Ops.PLUS -> EtsUnaryPlusExpr(arg) - Ops.INC -> EtsPreIncExpr(arg.type, arg) - Ops.DEC -> EtsPreDecExpr(arg.type, arg) - else -> error("Unknown unop: '${value.op}'") - } + is PhiExprDto -> error("PhiExpr is not supported") + + is UnaryOperationDto -> { + val arg = arg.toEtsEntity() + // Note: `type` is ignored here! + when (op) { + Ops.NOT -> EtsNotExpr(arg) + Ops.BIT_NOT -> EtsBitNotExpr(arg.type, arg) + Ops.MINUS -> EtsNegExpr(arg.type, arg) + Ops.PLUS -> EtsUnaryPlusExpr(arg) + Ops.INC -> EtsPreIncExpr(arg.type, arg) + Ops.DEC -> EtsPreDecExpr(arg.type, arg) + else -> error("Unknown unop: '$op'") } + } - is BinaryOperationDto -> { - val left = convertToEtsEntity(value.left) - val right = convertToEtsEntity(value.right) - val type = convertToEtsType(value.type) - when (value.op) { - Ops.ADD -> EtsAddExpr(type, left, right) - Ops.SUB -> EtsSubExpr(type, left, right) - Ops.MUL -> EtsMulExpr(type, left, right) - Ops.DIV -> EtsDivExpr(type, left, right) - Ops.MOD -> EtsRemExpr(type, left, right) - Ops.EXP -> EtsExpExpr(type, left, right) - Ops.BIT_AND -> EtsBitAndExpr(type, left, right) - Ops.BIT_OR -> EtsBitOrExpr(type, left, right) - Ops.BIT_XOR -> EtsBitXorExpr(type, left, right) - Ops.LSH -> EtsLeftShiftExpr(type, left, right) - Ops.RSH -> EtsRightShiftExpr(type, left, right) - Ops.URSH -> EtsUnsignedRightShiftExpr(type, left, right) - Ops.AND -> EtsAndExpr(type, left, right) - Ops.OR -> EtsOrExpr(type, left, right) - Ops.NULLISH -> EtsNullishCoalescingExpr(type, left, right) - Ops.COMMA -> EtsCommaExpr(left, right) // Note: `type` is ignored here! - - // TODO: fix (remove) this when `instanceof` is properly supported in ArkAnalyzer. - // Ideally, it would become a separate `ArkInstanceOfExpr`, and we are going to - // introduce a corresponding DTO for it. - // Currently, `x instanceof T` is represented as `BinopExpr(Local("x"), Local("T"))`, - // so we just *unsafely* extract the type name from the "pseudo-local" here: - // "instanceof" -> EtsInstanceOfExpr(left, (right as EtsLocal).name) - - // TODO: Currently, ArkIR treats "in" operation just as BinopExpr. - // Ideally, it would be represented as a separate `ArkInExpr`, - // or at least as `ArkConditionExpr`, since it inherently has a boolean type. - // Ops.IN -> EtsInExpr(left, right) // Note: `type` is ignored here! - - else -> error("Unknown binop: ${value.op}") - } + is BinaryOperationDto -> { + val left = left.toEtsEntity() + val right = right.toEtsEntity() + val type = type.toEtsType() + when (op) { + Ops.ADD -> EtsAddExpr(type, left, right) + Ops.SUB -> EtsSubExpr(type, left, right) + Ops.MUL -> EtsMulExpr(type, left, right) + Ops.DIV -> EtsDivExpr(type, left, right) + Ops.MOD -> EtsRemExpr(type, left, right) + Ops.EXP -> EtsExpExpr(type, left, right) + Ops.BIT_AND -> EtsBitAndExpr(type, left, right) + Ops.BIT_OR -> EtsBitOrExpr(type, left, right) + Ops.BIT_XOR -> EtsBitXorExpr(type, left, right) + Ops.LSH -> EtsLeftShiftExpr(type, left, right) + Ops.RSH -> EtsRightShiftExpr(type, left, right) + Ops.URSH -> EtsUnsignedRightShiftExpr(type, left, right) + Ops.AND -> EtsAndExpr(type, left, right) + Ops.OR -> EtsOrExpr(type, left, right) + Ops.NULLISH -> EtsNullishCoalescingExpr(type, left, right) + Ops.COMMA -> EtsCommaExpr(left, right) // Note: `type` is ignored here! + + else -> error("Unknown binop: $op") } + } - is RelationOperationDto -> { - val left = convertToEtsEntity(value.left) - val right = convertToEtsEntity(value.right) - // Note: `value.type` is ignored here! - when (value.op) { - Ops.EQ_EQ -> EtsEqExpr(left, right) - Ops.NOT_EQ -> EtsNotEqExpr(left, right) - Ops.EQ_EQ_EQ -> EtsStrictEqExpr(left, right) - Ops.NOT_EQ_EQ -> EtsStrictNotEqExpr(left, right) - Ops.LT -> EtsLtExpr(left, right) - Ops.LT_EQ -> EtsLtEqExpr(left, right) - Ops.GT -> EtsGtExpr(left, right) - Ops.GT_EQ -> EtsGtEqExpr(left, right) - Ops.IN -> EtsInExpr(left, right) - else -> error("Unknown relop: ${value.op}") - } + is RelationOperationDto -> { + val left = left.toEtsEntity() + val right = right.toEtsEntity() + // Note: `type` is ignored here! + when (op) { + Ops.EQ_EQ -> EtsEqExpr(left, right) + Ops.NOT_EQ -> EtsNotEqExpr(left, right) + Ops.EQ_EQ_EQ -> EtsStrictEqExpr(left, right) + Ops.NOT_EQ_EQ -> EtsStrictNotEqExpr(left, right) + Ops.LT -> EtsLtExpr(left, right) + Ops.LT_EQ -> EtsLtEqExpr(left, right) + Ops.GT -> EtsGtExpr(left, right) + Ops.GT_EQ -> EtsGtEqExpr(left, right) + Ops.IN -> EtsInExpr(left, right) + else -> error("Unknown relop: $op") } + } - is InstanceCallExprDto -> EtsInstanceCallExpr( - instance = convertToEtsEntity(value.instance as LocalDto) as EtsLocal, // safe cast - method = convertToEtsMethodSignature(value.method), - args = value.args.map { - ensureLocal(convertToEtsEntity(it)) - }, - ) + is InstanceCallExprDto -> EtsInstanceCallExpr( + instance = (instance as LocalDto).toEtsLocal(), // safe cast + method = method.toEtsMethodSignature(), + args = args.map { ensureLocal(it.toEtsEntity()) }, + ) - is StaticCallExprDto -> EtsStaticCallExpr( - method = convertToEtsMethodSignature(value.method), - args = value.args.map { - ensureLocal(convertToEtsEntity(it)) - }, - ) + is StaticCallExprDto -> EtsStaticCallExpr( + method = method.toEtsMethodSignature(), + args = args.map { ensureLocal(it.toEtsEntity()) }, + ) - is PtrCallExprDto -> EtsPtrCallExpr( - ptr = convertToEtsEntity(value.ptr as LocalDto) as EtsLocal, // safe cast - method = convertToEtsMethodSignature(value.method), - args = value.args.map { - ensureLocal(convertToEtsEntity(it)) - }, - ) + is PtrCallExprDto -> EtsPtrCallExpr( + ptr = (ptr as LocalDto).toEtsLocal(), // safe cast + method = method.toEtsMethodSignature(), + args = args.map { ensureLocal(it.toEtsEntity()) }, + ) - is ThisRefDto -> EtsThis( - type = convertToEtsType(value.type as ClassTypeDto) as EtsClassType // safe cast - ) + is ThisRefDto -> EtsThis( + type = (type as ClassTypeDto).toEtsClassType(), // safe cast + ) - is ParameterRefDto -> EtsParameterRef( - index = value.index, - type = convertToEtsType(value.type), - ) + is ParameterRefDto -> EtsParameterRef( + index = index, + type = type.toEtsType(), + ) - is ArrayRefDto -> EtsArrayAccess( - array = convertToEtsEntity(value.array) as EtsValue, // TODO: check whether the cast is safe - index = convertToEtsEntity(value.index) as EtsValue, // TODO: check whether the cast is safe - type = convertToEtsType(value.type), - ) + is CaughtExceptionRefDto -> EtsCaughtExceptionRef( + type = type.toEtsType(), + ) - is FieldRefDto -> convertToEtsFieldRef(value) + is GlobalRefDto -> EtsGlobalRef( + name = name, + ref = ref?.toEtsEntity() as EtsValue, // TODO: check whether the cast is safe + ) - // else -> error("Unknown Value: $value") - } + 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 + type = type.toEtsType(), + ) + + is FieldRefDto -> toEtsFieldRef() + + // else -> error("Unknown Value: $value") } - fun convertToEtsFieldRef(fieldRef: FieldRefDto): EtsFieldRef { - val field = convertToEtsFieldSignature(fieldRef.field) - return when (fieldRef) { + private fun FieldRefDto.toEtsFieldRef(): EtsFieldRef { + val field = field.toEtsFieldSignature() + return when (this) { is InstanceFieldRefDto -> EtsInstanceFieldRef( - instance = convertToEtsEntity(fieldRef.instance as LocalDto) as EtsLocal, // safe cast + instance = (instance as LocalDto).toEtsLocal(), // safe cast field = field, ) is StaticFieldRefDto -> EtsStaticFieldRef( - field = field + field = field, ) } } - fun convertToEtsCfg(cfg: CfgDto): EtsCfg { - require(cfg.blocks.isNotEmpty()) { + private fun CfgDto.toEtsCfg(): EtsCfg { + require(blocks.isNotEmpty()) { "Method body should contain at least return stmt" } @@ -493,7 +475,7 @@ class EtsMethodBuilder( val queue: ArrayDeque = ArrayDeque() queue.add(0) - val blocks = cfg.blocks.associateBy { it.id } + val blocks = blocks.associateBy { it.id } val blockStart: MutableMap = hashMapOf() val blockEnd: MutableMap = hashMapOf() @@ -502,7 +484,7 @@ class EtsMethodBuilder( blockStart[block.id] = currentStmts.size if (block.stmts.isNotEmpty()) { for (stmt in block.stmts) { - currentStmts += convertToEtsStmt(stmt) + currentStmts += stmt.toEtsStmt() } } else { currentStmts += EtsNopStmt(loc()) @@ -518,7 +500,7 @@ class EtsMethodBuilder( } val successorMap: MutableMap> = hashMapOf() - for (block in cfg.blocks) { + for (block in this.blocks) { val startId = blockStart[block.id]!! val endId = blockEnd[block.id]!! for (i in startId until endId) { @@ -536,7 +518,7 @@ class EtsMethodBuilder( } } -fun convertToEtsClass(classDto: ClassDto): EtsClass { +fun ClassDto.toEtsClass(): EtsClass { fun defaultConstructorDto(classSignatureDto: ClassSignatureDto): MethodDto { val zeroBlock = BasicBlockDto( id = 0, @@ -563,33 +545,33 @@ fun convertToEtsClass(classDto: ClassDto): EtsClass { ) } - val signature = convertToEtsClassSignature(classDto.signature) - val superClassSignature = classDto.superClassName?.takeIf { it != "" }?.let { name -> + val signature = signature.toEtsClassSignature() + val superClassSignature = superClassName?.takeIf { it != "" }?.let { name -> EtsClassSignature( name = name, file = EtsFileSignature.DEFAULT, ) } - val implementedInterfaces = classDto.implementedInterfaceNames.map { name -> + val implementedInterfaces = implementedInterfaceNames.map { name -> EtsClassSignature( name = name, file = EtsFileSignature.DEFAULT, ) } - val fields = classDto.fields.map { convertToEtsField(it) } + val fields = fields.map { it.toEtsField() } - val (methodDtos, ctorDtos) = classDto.methods.partition { it.signature.name != CONSTRUCTOR_NAME } + val (methodDtos, ctorDtos) = methods.partition { it.signature.name != CONSTRUCTOR_NAME } check(ctorDtos.size <= 1) { "Class should not have multiple constructors" } - val ctorDto = ctorDtos.firstOrNull() ?: defaultConstructorDto(classDto.signature) + val ctorDto = ctorDtos.firstOrNull() ?: defaultConstructorDto(this.signature) - val methods = methodDtos.map { convertToEtsMethod(it) } - val ctor = convertToEtsMethod(ctorDto) + val methods = methodDtos.map { it.toEtsMethod() } + val ctor = ctorDto.toEtsMethod() - val typeParameters = classDto.typeParameters?.map { convertToEtsType(it) } ?: emptyList() + val typeParameters = typeParameters?.map { it.toEtsType() } ?: emptyList() - val modifiers = EtsModifiers(classDto.modifiers) - val decorators = classDto.decorators.map { convertToEtsDecorator(it) } + val modifiers = EtsModifiers(modifiers) + val decorators = decorators.map { it.toEtsDecorator() } return EtsClassImpl( signature = signature, @@ -604,109 +586,95 @@ fun convertToEtsClass(classDto: ClassDto): EtsClass { ) } -fun convertToEtsType(type: TypeDto): EtsType { - return when (type) { - is AbsolutelyUnknownTypeDto -> object : EtsType { - override val typeName: String - get() = type.type ?: "UNKNOWN" - - override fun toString(): String { - return type.type ?: "UNKNOWN" - } - - override fun accept(visitor: EtsType.Visitor): R { - error("Not supported: ${type.type}") - } - } - - is AliasTypeDto -> EtsAliasType( - name = type.name, - originalType = convertToEtsType(type.originalType), - signature = convertToEtsLocalSignature(type.signature), - ) +fun TypeDto.toEtsType(): EtsType = when (this) { + is AliasTypeDto -> EtsAliasType( + name = name, + originalType = originalType.toEtsType(), + signature = signature.toEtsLocalSignature(), + ) - is AnnotationNamespaceTypeDto -> EtsAnnotationNamespaceType( - originType = type.originType, - namespaceSignature = convertToEtsNamespaceSignature(type.namespaceSignature), - ) + is AnnotationNamespaceTypeDto -> EtsAnnotationNamespaceType( + originType = originType, + namespaceSignature = namespaceSignature.toEtsNamespaceSignature(), + ) + is AnnotationTypeQueryTypeDto -> EtsAnnotationTypeQueryType( + originType = originType, + ) - is AnnotationTypeQueryTypeDto -> EtsAnnotationTypeQueryType( - originType = type.originType, - ) + AnyTypeDto -> EtsAnyType - AnyTypeDto -> EtsAnyType + is ArrayTypeDto -> EtsArrayType( + elementType = elementType.toEtsType(), + dimensions = dimensions, + ) - is ArrayTypeDto -> EtsArrayType( - elementType = convertToEtsType(type.elementType), - dimensions = type.dimensions, - ) + BooleanTypeDto -> EtsBooleanType - BooleanTypeDto -> EtsBooleanType + is ClassTypeDto -> toEtsClassType() - is ClassTypeDto -> EtsClassType( - signature = convertToEtsClassSignature(type.signature), - typeParameters = type.typeParameters.map { convertToEtsType(it) }, - ) + is FunctionTypeDto -> EtsFunctionType( + method = signature.toEtsMethodSignature(), + typeParameters = typeParameters.map { it.toEtsType() }, + ) - is FunctionTypeDto -> EtsFunctionType( - method = convertToEtsMethodSignature(type.signature), - typeParameters = type.typeParameters.map { convertToEtsType(it) }, - ) + is GenericTypeDto -> EtsGenericType( + name = name, + defaultType = defaultType?.toEtsType(), + constraint = constraint?.toEtsType(), + ) + + is LexicalEnvTypeDto -> EtsLexicalEnvType( + nestedMethod = nestedMethod.toEtsMethodSignature(), + closures = closures.map { it.toEtsLocal() }, + ) - is GenericTypeDto -> EtsGenericType( - name = type.name, - defaultType = type.defaultType?.let { convertToEtsType(it) }, - constraint = type.constraint?.let { convertToEtsType(it) }, - ) + is LiteralTypeDto -> EtsLiteralType( + literalTypeName = literal.toString(), + ) - is LiteralTypeDto -> EtsLiteralType( - literalTypeName = type.literal.toString(), - ) + NeverTypeDto -> EtsNeverType - NeverTypeDto -> EtsNeverType + NullTypeDto -> EtsNullType - NullTypeDto -> EtsNullType + NumberTypeDto -> EtsNumberType - NumberTypeDto -> EtsNumberType + StringTypeDto -> EtsStringType - StringTypeDto -> EtsStringType + is TupleTypeDto -> EtsTupleType( + types = types.map { it.toEtsType() }, + ) - is TupleTypeDto -> EtsTupleType( - types = type.types.map { convertToEtsType(it) } - ) + is UnclearReferenceTypeDto -> EtsUnclearRefType( + name = name, + typeParameters = typeParameters.map { it.toEtsType() }, + ) - is UnclearReferenceTypeDto -> EtsUnclearRefType( - name = type.name, - typeParameters = type.typeParameters.map { convertToEtsType(it) }, - ) + UndefinedTypeDto -> EtsUndefinedType - UndefinedTypeDto -> EtsUndefinedType + is UnionTypeDto -> EtsUnionType( + types = types.map { it.toEtsType() }, + ) - is UnionTypeDto -> EtsUnionType( - types = type.types.map { convertToEtsType(it) } - ) + UnknownTypeDto -> EtsUnknownType - UnknownTypeDto -> EtsUnknownType + VoidTypeDto -> EtsVoidType +} - VoidTypeDto -> EtsVoidType - } +fun ClassTypeDto.toEtsClassType(): EtsClassType { + return EtsClassType( + signature = signature.toEtsClassSignature(), + typeParameters = typeParameters.map { it.toEtsType() }, + ) } -fun convertToEtsConstant(value: ConstantDto): EtsConstant { - val type = convertToEtsType(value.type) - return when (type) { - EtsStringType -> EtsStringConstant( - value = value.value - ) +fun ConstantDto.toEtsConstant(): EtsConstant { + return when (type.toEtsType()) { + EtsStringType -> EtsStringConstant(value = this.value) - EtsBooleanType -> EtsBooleanConstant( - value = value.value.toBoolean() - ) + EtsBooleanType -> EtsBooleanConstant(value = value.toBoolean()) - EtsNumberType -> EtsNumberConstant( - value = value.value.toDouble() - ) + EtsNumberType -> EtsNumberConstant(value = value.toDouble()) EtsNullType -> EtsNullConstant @@ -715,7 +683,7 @@ fun convertToEtsConstant(value: ConstantDto): EtsConstant { else -> object : EtsConstant { override val type: EtsType = EtsUnknownType - override fun toString(): String = "Unknown(${value.value})" + override fun toString(): String = "Unknown($value)" override fun accept(visitor: EtsValue.Visitor): R { if (visitor is EtsValue.Visitor.Default) { @@ -727,70 +695,70 @@ fun convertToEtsConstant(value: ConstantDto): EtsConstant { } } -fun convertToEtsFileSignature(file: FileSignatureDto): EtsFileSignature { +fun FileSignatureDto.toEtsFileSignature(): EtsFileSignature { return EtsFileSignature( - projectName = file.projectName, - fileName = file.fileName, + projectName = projectName, + fileName = fileName, ) } -fun convertToEtsNamespaceSignature(namespace: NamespaceSignatureDto): EtsNamespaceSignature { +fun NamespaceSignatureDto.toEtsNamespaceSignature(): EtsNamespaceSignature { return EtsNamespaceSignature( - name = namespace.name, - file = namespace.declaringFile.let { convertToEtsFileSignature(it) }, - namespace = namespace.declaringNamespace?.let { convertToEtsNamespaceSignature(it) }, + name = name, + file = declaringFile.toEtsFileSignature(), + namespace = declaringNamespace?.toEtsNamespaceSignature(), ) } -fun convertToEtsClassSignature(clazz: ClassSignatureDto): EtsClassSignature { +fun ClassSignatureDto.toEtsClassSignature(): EtsClassSignature { return EtsClassSignature( - name = clazz.name, - file = clazz.declaringFile.let { convertToEtsFileSignature(it) }, - namespace = clazz.declaringNamespace?.let { convertToEtsNamespaceSignature(it) }, + name = name, + file = declaringFile.toEtsFileSignature(), + namespace = declaringNamespace?.toEtsNamespaceSignature(), ) } -fun convertToEtsFieldSignature(field: FieldSignatureDto): EtsFieldSignature { +fun FieldSignatureDto.toEtsFieldSignature(): EtsFieldSignature { return EtsFieldSignature( - enclosingClass = convertToEtsClassSignature(field.declaringClass), + enclosingClass = declaringClass.toEtsClassSignature(), sub = EtsFieldSubSignature( - name = field.name, - type = convertToEtsType(field.type), - ) + name = name, + type = type.toEtsType(), + ), ) } -fun convertToEtsMethodSignature(method: MethodSignatureDto): EtsMethodSignature { +fun MethodSignatureDto.toEtsMethodSignature(): EtsMethodSignature { return EtsMethodSignature( - enclosingClass = convertToEtsClassSignature(method.declaringClass), - name = method.name, - parameters = method.parameters.mapIndexed { index, param -> + enclosingClass = declaringClass.toEtsClassSignature(), + name = name, + parameters = parameters.mapIndexed { index, param -> EtsMethodParameter( index = index, name = param.name, - type = convertToEtsType(param.type), - isOptional = param.isOptional + type = param.type.toEtsType(), + isOptional = param.isOptional, ) }, - returnType = convertToEtsType(method.returnType), + returnType = returnType.toEtsType(), ) } -fun convertToEtsLocalSignature(local: LocalSignatureDto): EtsLocalSignature { +fun LocalSignatureDto.toEtsLocalSignature(): EtsLocalSignature { return EtsLocalSignature( - name = local.name, - method = convertToEtsMethodSignature(local.method), + name = name, + method = method.toEtsMethodSignature(), ) } -fun convertToEtsMethod(method: MethodDto): EtsMethod { - val signature = convertToEtsMethodSignature(method.signature) - val typeParameters = method.typeParameters?.map { convertToEtsType(it) } ?: emptyList() - val modifiers = EtsModifiers(method.modifiers) - val decorators = method.decorators.map { convertToEtsDecorator(it) } - if (method.body != null) { - val locals = method.body.locals.map { - convertToEtsLocal(it) +fun MethodDto.toEtsMethod(): EtsMethod { + val signature = signature.toEtsMethodSignature() + val typeParameters = typeParameters?.map { it.toEtsType() } ?: emptyList() + val modifiers = EtsModifiers(modifiers) + val decorators = decorators.map { it.toEtsDecorator() } + if (body != null) { + val locals = body.locals.map { + it.toEtsLocal() } val builder = EtsMethodBuilder( signature = signature, @@ -799,7 +767,7 @@ fun convertToEtsMethod(method: MethodDto): EtsMethod { modifiers = modifiers, decorators = decorators, ) - return builder.build(method.body.cfg) + return builder.build(body.cfg) } else { return EtsMethodImpl( signature = signature, @@ -811,25 +779,25 @@ fun convertToEtsMethod(method: MethodDto): EtsMethod { } } -fun convertToEtsField(field: FieldDto): EtsField { +fun FieldDto.toEtsField(): EtsField { return EtsFieldImpl( signature = EtsFieldSignature( - enclosingClass = convertToEtsClassSignature(field.signature.declaringClass), + enclosingClass = signature.declaringClass.toEtsClassSignature(), sub = EtsFieldSubSignature( - name = field.signature.name, - type = convertToEtsType(field.signature.type), - ) + name = signature.name, + type = signature.type.toEtsType(), + ), ), - modifiers = EtsModifiers(field.modifiers), - isOptional = field.isOptional, - isDefinitelyAssigned = field.isDefinitelyAssigned, + modifiers = EtsModifiers(modifiers), + isOptional = isOptional, + isDefinitelyAssigned = isDefinitelyAssigned, ) } -fun convertToEtsNamespace(namespace: NamespaceDto): EtsNamespace { - val signature = convertToEtsNamespaceSignature(namespace.signature) - val classes = namespace.classes.map { convertToEtsClass(it) } - val namespaces = namespace.namespaces.map { convertToEtsNamespace(it) } +fun NamespaceDto.toEtsNamespace(): EtsNamespace { + val signature = signature.toEtsNamespaceSignature() + val classes = classes.map { it.toEtsClass() } + val namespaces = namespaces.map { it.toEtsNamespace() } return EtsNamespace( signature = signature, classes = classes, @@ -837,10 +805,10 @@ fun convertToEtsNamespace(namespace: NamespaceDto): EtsNamespace { ) } -fun convertToEtsFile(file: EtsFileDto): EtsFile { - val signature = convertToEtsFileSignature(file.signature) - val classes = file.classes.map { convertToEtsClass(it) } - val namespaces = file.namespaces.map { convertToEtsNamespace(it) } +fun EtsFileDto.toEtsFile(): EtsFile { + val signature = signature.toEtsFileSignature() + val classes = classes.map { it.toEtsClass() } + val namespaces = namespaces.map { it.toEtsNamespace() } return EtsFile( signature = signature, classes = classes, @@ -848,17 +816,17 @@ fun convertToEtsFile(file: EtsFileDto): EtsFile { ) } -fun convertToEtsDecorator(decorator: DecoratorDto): EtsDecorator { +fun DecoratorDto.toEtsDecorator(): EtsDecorator { return EtsDecorator( - name = decorator.kind, + name = kind, // TODO: content // TODO: param ) } -fun convertToEtsLocal(local: LocalDto): EtsLocal { +fun LocalDto.toEtsLocal(): EtsLocal { return EtsLocal( - name = local.name, - type = convertToEtsType(local.type), + name = name, + type = type.toEtsType(), ) } 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 38763bd27..8b29759b1 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 @@ -39,7 +39,7 @@ object PrimitiveLiteralSerializer : KSerializer { require(encoder is JsonEncoder) when (value) { is PrimitiveLiteralDto.StringLiteral -> encoder.encodeString(value.value) - is PrimitiveLiteralDto.NumberLiteral -> encoder.encodeDouble(value.value.toDouble()) + is PrimitiveLiteralDto.NumberLiteral -> encoder.encodeDouble(value.value) is PrimitiveLiteralDto.BooleanLiteral -> encoder.encodeBoolean(value.value) } } 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 0b4cdc77c..ccf2bf9b0 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 @@ -26,21 +26,9 @@ import kotlinx.serialization.json.JsonClassDiscriminator @JsonClassDiscriminator("_") sealed interface StmtDto -@Serializable -@SerialName("UNKNOWN_STMT") -data class UnknownStmtDto( - val stmt: String, -) : StmtDto { - override fun toString(): String { - return "UNKNOWN($stmt)" - } -} - @Serializable @SerialName("NopStmt") -object NopStmtDto : StmtDto { - override fun toString(): String = javaClass.simpleName -} +data object NopStmtDto : StmtDto @Serializable @SerialName("AssignStmt") @@ -68,9 +56,7 @@ sealed interface TerminatingStmtDto : StmtDto @Serializable @SerialName("ReturnVoidStmt") -object ReturnVoidStmtDto : TerminatingStmtDto { - override fun toString(): String = javaClass.simpleName -} +data object ReturnVoidStmtDto : TerminatingStmtDto @Serializable @SerialName("ReturnStmt") @@ -93,9 +79,7 @@ sealed interface BranchingStmtDto : StmtDto @Serializable @SerialName("GotoStmt") -object GotoStmtDto : BranchingStmtDto { - override fun toString(): String = javaClass.simpleName -} +data object GotoStmtDto : BranchingStmtDto @Serializable @SerialName("IfStmt") @@ -109,3 +93,10 @@ 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 ed395210b..17d58f9ee 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 @@ -272,11 +272,12 @@ data class AnnotationTypeQueryTypeDto( } @Serializable -@SerialName("UNKNOWN_TYPE") -data class AbsolutelyUnknownTypeDto( - val type: String? = null, +@SerialName("LexicalEnvType") +data class LexicalEnvTypeDto( + val nestedMethod: MethodSignatureDto, + val closures: List, ) : TypeDto { override fun toString(): String { - return type ?: "UNKNOWN" + return closures.joinToString(prefix = "[", postfix = "]") } } 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 0d8962b6b..b9c8928cf 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 @@ -263,24 +263,6 @@ data class PhiExprDto( } } -@Serializable -@SerialName("ArrayLiteralExpr") -data class ArrayLiteralDto( - val elements: List, - override val type: TypeDto, -) : ExprDto { - override fun toString(): String { - return "[" + elements.joinToString() + "]" - } -} - -@Serializable -@SerialName("ObjectLiteralExpr") -data class ObjectLiteralDto( - val anonymousClass: ClassSignatureDto, - override val type: TypeDto, -) : ExprDto - @Serializable sealed interface UnaryExprDto : ExprDto { val arg: ValueDto @@ -403,6 +385,42 @@ data class ParameterRefDto( } } +@Serializable +@SerialName("CaughtExceptionRef") +data class CaughtExceptionRefDto( + override val type: TypeDto, +) : RefDto { + override fun toString(): String { + return "catch($type)" + } +} + +@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("ArrayRef") data class ArrayRefDto( diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/model/EtsFile.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/model/EtsFile.kt index d9c363c2d..606277d2f 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/model/EtsFile.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/model/EtsFile.kt @@ -31,6 +31,6 @@ class EtsFile( } override fun toString(): String { - return name + return signature.toString() } } 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 324cc8db5..6dbaee0d2 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 @@ -19,7 +19,6 @@ package org.jacodb.ets.utils import org.jacodb.ets.base.EtsAddExpr import org.jacodb.ets.base.EtsAndExpr import org.jacodb.ets.base.EtsArrayAccess -import org.jacodb.ets.base.EtsArrayLiteral import org.jacodb.ets.base.EtsAssignStmt import org.jacodb.ets.base.EtsAwaitExpr import org.jacodb.ets.base.EtsBitAndExpr @@ -29,12 +28,15 @@ 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 @@ -58,7 +60,6 @@ import org.jacodb.ets.base.EtsNotExpr import org.jacodb.ets.base.EtsNullConstant import org.jacodb.ets.base.EtsNullishCoalescingExpr import org.jacodb.ets.base.EtsNumberConstant -import org.jacodb.ets.base.EtsObjectLiteral import org.jacodb.ets.base.EtsOrExpr import org.jacodb.ets.base.EtsParameterRef import org.jacodb.ets.base.EtsPostDecExpr @@ -66,6 +67,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.EtsRawStmt import org.jacodb.ets.base.EtsRemExpr import org.jacodb.ets.base.EtsReturnStmt import org.jacodb.ets.base.EtsRightShiftExpr @@ -120,6 +122,9 @@ private object StmtGetOperands : EtsStmt.Visitor> { override fun visit(stmt: EtsSwitchStmt): Sequence = sequenceOf(stmt.arg) + stmt.cases.asSequence() + + override fun visit(stmt: EtsRawStmt): Sequence = + emptySequence() } private object EntityGetOperands : EtsEntity.Visitor> { @@ -142,13 +147,6 @@ private object EntityGetOperands : EtsEntity.Visitor> { override fun visit(value: EtsUndefinedConstant): Sequence = emptySequence() - override fun visit(value: EtsArrayLiteral): Sequence = - value.elements.asSequence() - - // TODO: check - override fun visit(value: EtsObjectLiteral): Sequence = - value.properties.asSequence().map { (_, v) -> v } - override fun visit(value: EtsThis): Sequence = emptySequence() @@ -304,4 +302,13 @@ private object EntityGetOperands : EtsEntity.Visitor> { override fun visit(expr: EtsTernaryExpr): Sequence = sequenceOf(expr.condition, expr.thenExpr, expr.elseExpr) + + override fun visit(value: EtsCaughtExceptionRef): 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/main/kotlin/org/jacodb/ets/utils/LoadEtsFile.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/LoadEtsFile.kt index 2aeccc9d1..3e570ce53 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/LoadEtsFile.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/LoadEtsFile.kt @@ -17,12 +17,13 @@ package org.jacodb.ets.utils import org.jacodb.ets.dto.EtsFileDto -import org.jacodb.ets.dto.convertToEtsFile +import org.jacodb.ets.dto.toEtsFile import org.jacodb.ets.model.EtsFile import org.jacodb.ets.model.EtsScene import java.io.FileNotFoundException import java.nio.file.Path import kotlin.io.path.Path +import kotlin.io.path.PathWalkOption import kotlin.io.path.absolute import kotlin.io.path.createTempDirectory import kotlin.io.path.exists @@ -95,17 +96,17 @@ fun generateSdkIR(sdkPath: Path): Path = generateEtsIR( ) fun loadEtsFileAutoConvert( - projectPath: Path, + path: Path, useArkAnalyzerTypeInference: Int? = 1, ): EtsFile { val irFilePath = generateEtsIR( - projectPath, + path, isProject = false, useArkAnalyzerTypeInference = useArkAnalyzerTypeInference, ) irFilePath.inputStream().use { stream -> val etsFileDto = EtsFileDto.loadFromJson(stream) - return convertToEtsFile(etsFileDto) + return etsFileDto.toEtsFile() } } @@ -142,13 +143,13 @@ fun loadEtsProjectFromMultipleIR(input: List, sdkPaths: List): EtsSc return EtsScene(projectFiles, sdkFiles) } -private val walker = { irFolder: Path -> - irFolder.walk() +private val walker = { dir: Path -> + dir.walk(PathWalkOption.BREADTH_FIRST) .filter { it.extension == "json" } .map { it.inputStream().use { stream -> val etsFileDto = EtsFileDto.loadFromJson(stream) - convertToEtsFile(etsFileDto) + etsFileDto.toEtsFile() } } .toList() 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 49c1d8c9e..61f149313 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 @@ -30,7 +30,6 @@ import org.jacodb.ets.base.EtsUnknownType import org.jacodb.ets.dto.AnyTypeDto import org.jacodb.ets.dto.ClassSignatureDto import org.jacodb.ets.dto.DecoratorDto -import org.jacodb.ets.dto.EtsMethodBuilder import org.jacodb.ets.dto.FieldDto import org.jacodb.ets.dto.FieldSignatureDto import org.jacodb.ets.dto.FileSignatureDto @@ -42,24 +41,30 @@ import org.jacodb.ets.dto.PrimitiveLiteralDto import org.jacodb.ets.dto.ReturnVoidStmtDto import org.jacodb.ets.dto.StmtDto import org.jacodb.ets.dto.TypeDto -import org.jacodb.ets.dto.convertToEtsFile -import org.jacodb.ets.dto.convertToEtsMethod +import org.jacodb.ets.dto.toEtsLocal +import org.jacodb.ets.dto.toEtsMethod import org.jacodb.ets.model.EtsClassSignature +import org.jacodb.ets.model.EtsFile import org.jacodb.ets.model.EtsFileSignature import org.jacodb.ets.model.EtsMethodSignature +import org.jacodb.ets.model.EtsScene import org.jacodb.ets.test.utils.getResourcePath import org.jacodb.ets.test.utils.getResourcePathOrNull -import org.jacodb.ets.test.utils.loadEtsFileDtoFromResource +import org.jacodb.ets.test.utils.loadEtsFileFromResource import org.jacodb.ets.test.utils.loadEtsProjectFromResources import org.jacodb.ets.test.utils.testFactory import org.jacodb.ets.utils.loadEtsFileAutoConvert -import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Assumptions import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestFactory -import org.junit.jupiter.api.condition.EnabledIf +import kotlin.io.path.PathWalkOption import kotlin.io.path.div import kotlin.io.path.exists -import kotlin.io.path.toPath +import kotlin.io.path.isDirectory +import kotlin.io.path.listDirectoryEntries +import kotlin.io.path.name +import kotlin.io.path.relativeTo +import kotlin.io.path.walk import kotlin.test.assertEquals import kotlin.test.assertIs @@ -73,76 +78,153 @@ class EtsFromJsonTest { prettyPrint = true } - private val defaultSignature = EtsMethodSignature( - enclosingClass = EtsClassSignature( - name = DEFAULT_ARK_CLASS_NAME, - file = EtsFileSignature.DEFAULT, - ), - name = DEFAULT_ARK_METHOD_NAME, - parameters = emptyList(), - returnType = EtsAnyType, - ) + @JvmStatic + private fun projectAvailable(res: String): Boolean { + val path = getResourcePathOrNull(res) + return path != null && path.exists() + } + + private fun printProject(project: EtsScene) { + logger.info { + "Loaded project with ${project.projectClasses.size} classes and ${ + project.projectClasses.sumOf { it.methods.size } + } methods" + } + for (cls in project.projectClasses) { + logger.info { + buildString { + appendLine("Class ${cls.name} has ${cls.methods.size} methods") + for (method in cls.methods) { + appendLine("- $method") + } + } + } + } + } - private const val PROJECT_PATH = "/projects/ArkTSDistributedCalc" + private fun printFile(file: EtsFile, showStmts: Boolean = false) { + logger.info { "Loaded file $file with ${file.allClasses.size} classes" } + for (cls in file.allClasses) { + logger.info { + buildString { + appendLine("Class ${cls.name} has ${cls.methods.size} methods") + for (method in cls.methods) { + appendLine("- $method") + if (showStmts) { + for (stmt in method.cfg.stmts) { + appendLine(" - $stmt") + } + } + } + } + } + } + } } @Test fun testLoadEtsFileFromJson() { val path = "/samples/etsir/ast/save/basic.ts.json" - val etsDto = loadEtsFileDtoFromResource(path) - println("etsDto = $etsDto") - val ets = convertToEtsFile(etsDto) - println("ets = $ets") - - println("Classes: ${ets.classes.size}") - for (cls in ets.classes) { - println("= $cls with ${cls.methods.size} methods:") - for (method in cls.methods) { - println(" - $method") - } - } + val file = loadEtsFileFromResource(path) + printFile(file, showStmts = true) } @Test fun testLoadEtsFileAutoConvert() { val path = "/samples/source/example.ts" val res = getResourcePath(path) - val etsFile = loadEtsFileAutoConvert(res) - println("etsFile = $etsFile") + val file = loadEtsFileAutoConvert(res) + printFile(file, showStmts = true) } - private fun projectAvailable(): Boolean { - val path = this::class.java.getResource(PROJECT_PATH)?.toURI()?.toPath() - return path != null && path.exists() + @TestFactory + fun testLoadAllAvailableEtsFilesFromJson() = testFactory { + val prefix = "/samples" + val base = getResourcePathOrNull("$prefix/source") ?: run { + logger.warn { "No samples directory found in resources" } + return@testFactory + } + val availableFiles = base.walk(PathWalkOption.BREADTH_FIRST) + .map { it.relativeTo(base) } + .toList() + logger.info { + buildString { + appendLine("Found ${availableFiles.size} sample files") + for (path in availableFiles) { + appendLine(" - $path") + } + } + } + if (availableFiles.isEmpty()) { + logger.warn { "No sample files found" } + return@testFactory + } + container("load ${availableFiles.size} files") { + for (path in availableFiles) { + test("load $path") { + val file = loadEtsFileFromResource("$prefix/etsir/ast/$path.json") + printFile(file) + } + } + } + } + + @TestFactory + fun testLoadAllAvailableEtsFilesAutoConvert() = testFactory { + val prefix = "/samples/source" + val base = getResourcePathOrNull(prefix) ?: run { + logger.warn { "No samples directory found in resources" } + return@testFactory + } + val availableFiles = base.walk(PathWalkOption.BREADTH_FIRST) + .map { it.relativeTo(base) } + .toList() + logger.info { + buildString { + appendLine("Found ${availableFiles.size} sample files") + for (path in availableFiles) { + appendLine(" - $path") + } + } + } + if (availableFiles.isEmpty()) { + logger.warn { "No sample files found" } + return@testFactory + } + container("auto-load ${availableFiles.size} files") { + for (path in availableFiles) { + test("load $path") { + val p = getResourcePath("$prefix/$path") + val file = loadEtsFileAutoConvert(p) + printFile(file) + } + } + } } - @EnabledIf("projectAvailable") @Test fun testLoadEtsProject() { - val modules = listOf( - "entry", - ) - val prefix = "$PROJECT_PATH/etsir" + val res = "/projects/Demo_Calc" + Assumptions.assumeTrue(projectAvailable(res)) { "Project not available: $res" } + val modules = listOf("entry") + val prefix = "$res/etsir" val project = loadEtsProjectFromResources(modules, prefix) - println("Classes: ${project.projectClasses.size}") - for (cls in project.projectClasses) { - println("= ${cls.signature} with ${cls.methods.size} methods:") - for (method in cls.methods) { - println(" - ${method.signature}") - } - } + printProject(project) } @TestFactory fun testLoadAllAvailableEtsProjects() = testFactory { - val p = getResourcePathOrNull("/projects") ?: run { + val base = getResourcePathOrNull("/projects") ?: run { logger.warn { "No projects directory found in resources" } return@testFactory } - val availableProjectNames = p.toFile().listFiles { f -> f.isDirectory }!!.map { it.name } + val availableProjectNames = base.listDirectoryEntries() + .filter { it.isDirectory() } + .map { it.name } + .sorted() logger.info { buildString { - appendLine("Found projects: ${availableProjectNames.size}") + appendLine("Found ${availableProjectNames.size} projects") for (name in availableProjectNames) { appendLine(" - $name") } @@ -153,7 +235,7 @@ class EtsFromJsonTest { return@testFactory } container("load ${availableProjectNames.size} projects") { - for (projectName in availableProjectNames.sorted()) { + for (projectName in availableProjectNames) { test("load $projectName") { dynamicLoadEtsProject(projectName) } @@ -169,24 +251,17 @@ class EtsFromJsonTest { logger.warn { "No etsir directory found for project $projectName" } return } - val modules = etsirPath.toFile().listFiles { f -> f.isDirectory }!!.map { it.name } + val modules = etsirPath.listDirectoryEntries() + .filter { it.isDirectory() } + .map { it.name } + .sorted() logger.info { "Found ${modules.size} modules: $modules" } if (modules.isEmpty()) { logger.warn { "No modules found for project $projectName" } return } val project = loadEtsProjectFromResources(modules, "/projects/$projectName/etsir") - logger.info { - buildString { - appendLine("Loaded project with ${project.projectClasses.size} classes and ${project.projectClasses.sumOf { it.methods.size }} methods") - for (cls in project.projectClasses) { - appendLine("= ${cls.signature} with ${cls.methods.size} methods:") - for (method in cls.methods) { - appendLine(" - ${method.signature}") - } - } - } - } + printProject(project) } @Test @@ -200,12 +275,11 @@ class EtsFromJsonTest { } """.trimIndent() val valueDto = Json.decodeFromString(jsonString) - println("valueDto = $valueDto") - Assertions.assertEquals(LocalDto("x", AnyTypeDto), valueDto) - val ctx = EtsMethodBuilder(defaultSignature) - val value = ctx.convertToEtsEntity(valueDto) - println("value = $value") - Assertions.assertEquals(EtsLocal("x", EtsAnyType), value) + logger.info { "valueDto = $valueDto" } + assertEquals(LocalDto("x", AnyTypeDto), valueDto) + val value = valueDto.toEtsLocal() + logger.info { "value = $value" } + assertEquals(EtsLocal("x", EtsAnyType), value) } @Test @@ -227,14 +301,14 @@ class EtsFromJsonTest { isOptional = true, isDefinitelyAssigned = false, ) - println("field = $field") + logger.info { "field = $field" } val jsonString = json.encodeToString(field) - println("json: $jsonString") + logger.info { "json: $jsonString" } - val fieldDto = json.decodeFromString(jsonString) - println("fieldDto = $fieldDto") - Assertions.assertEquals(field, fieldDto) + val fieldDto = Json.decodeFromString(jsonString) + logger.info { "fieldDto = $fieldDto" } + assertEquals(field, fieldDto) } @Test @@ -245,8 +319,8 @@ class EtsFromJsonTest { } """.trimIndent() val stmtDto = Json.decodeFromString(jsonString) - println("stmtDto = $stmtDto") - Assertions.assertEquals(ReturnVoidStmtDto, stmtDto) + logger.info { "stmtDto = $stmtDto" } + assertEquals(ReturnVoidStmtDto, stmtDto) } @Test @@ -290,10 +364,10 @@ class EtsFromJsonTest { } """.trimIndent() val methodDto = Json.decodeFromString(jsonString) - println("methodDto = $methodDto") - val method = convertToEtsMethod(methodDto) - println("method = $method") - Assertions.assertEquals( + logger.info { "methodDto = $methodDto" } + val method = methodDto.toEtsMethod() + logger.info { "method = $method" } + assertEquals( EtsMethodSignature( enclosingClass = EtsClassSignature( name = DEFAULT_ARK_CLASS_NAME, @@ -308,9 +382,9 @@ class EtsFromJsonTest { ), method.signature ) - Assertions.assertEquals(0, method.locals.size) - Assertions.assertEquals(1, method.cfg.stmts.size) - Assertions.assertEquals( + assertEquals(0, method.locals.size) + assertEquals(1, method.cfg.stmts.size) + assertEquals( listOf( EtsReturnStmt(EtsInstLocation(method, 0), null), ), @@ -326,10 +400,10 @@ class EtsFromJsonTest { } """.trimIndent() val decoratorDto = Json.decodeFromString(jsonString) - println("decoratorDto = $decoratorDto") - Assertions.assertEquals(DecoratorDto("cat"), decoratorDto) + logger.info { "decoratorDto = $decoratorDto" } + assertEquals(DecoratorDto("cat"), decoratorDto) val jsonString2 = json.encodeToString(decoratorDto) - println("json: $jsonString2") + logger.info { "json: $jsonString2" } } @Test @@ -342,7 +416,7 @@ class EtsFromJsonTest { } """.trimIndent() val typeDto = Json.decodeFromString(jsonString) - println("typeDto = $typeDto") + logger.info { "typeDto = $typeDto" } assertIs(typeDto) assertEquals(PrimitiveLiteralDto.StringLiteral("hello"), typeDto.literal) } diff --git a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/Entrypoints.kt b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/Entrypoints.kt index f648b1eeb..899e031ec 100644 --- a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/Entrypoints.kt +++ b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/utils/Entrypoints.kt @@ -17,7 +17,7 @@ package org.jacodb.ets.test.utils import org.jacodb.ets.dto.EtsFileDto -import org.jacodb.ets.dto.convertToEtsFile +import org.jacodb.ets.dto.toEtsFile import org.jacodb.ets.model.EtsFile import org.jacodb.ets.utils.dumpDot import org.jacodb.ets.utils.render @@ -104,7 +104,7 @@ object DumpEtsFilesToDot { render(DOT_DIR, dotPath.relativeTo(DOT_DIR)) } - val etsFile = convertToEtsFile(etsFileDto) + val etsFile = etsFileDto.toEtsFile() run { val dotPath = DOT_DIR / path.resolveSibling(path.nameWithoutExtension + ".dot") etsFile.dumpDot(dotPath) diff --git a/jacodb-ets/src/testFixtures/kotlin/org/jacodb/ets/test/utils/LoadEts.kt b/jacodb-ets/src/testFixtures/kotlin/org/jacodb/ets/test/utils/LoadEts.kt index 18771380c..10b4cb2b7 100644 --- a/jacodb-ets/src/testFixtures/kotlin/org/jacodb/ets/test/utils/LoadEts.kt +++ b/jacodb-ets/src/testFixtures/kotlin/org/jacodb/ets/test/utils/LoadEts.kt @@ -18,11 +18,10 @@ package org.jacodb.ets.test.utils import mu.KotlinLogging import org.jacodb.ets.dto.EtsFileDto -import org.jacodb.ets.dto.convertToEtsFile +import org.jacodb.ets.dto.toEtsFile import org.jacodb.ets.model.EtsFile import org.jacodb.ets.model.EtsScene import java.nio.file.Path -import kotlin.io.path.ExperimentalPathApi import kotlin.io.path.extension import kotlin.io.path.inputStream import kotlin.io.path.relativeTo @@ -56,7 +55,7 @@ fun loadEtsFileDtoFromResource(jsonPath: String): EtsFileDto { */ fun loadEtsFileFromResource(jsonPath: String): EtsFile { val etsFileDto = loadEtsFileDtoFromResource(jsonPath) - return convertToEtsFile(etsFileDto) + return etsFileDto.toEtsFile() } /** @@ -84,7 +83,7 @@ fun loadEtsProjectFromResources( modules: List, prefix: String, ): EtsScene { - logger.info { "Loading Ets project with modules $modules from '$prefix/'" } + logger.info { "Loading project with ${modules.size} modules $modules from '$prefix/'" } val dirPaths = modules.map { "$prefix/$it" } val files = loadMultipleEtsFilesFromMultipleResourceDirectories(dirPaths).toList() logger.info { "Loaded ${files.size} files" } @@ -118,7 +117,7 @@ fun loadEtsFileDto(path: Path): EtsFileDto { */ fun loadEtsFile(path: Path): EtsFile { val etsFileDto = loadEtsFileDto(path) - return convertToEtsFile(etsFileDto) + return etsFileDto.toEtsFile() } /**