From 04c4e92ce6902f669e575a84efb7d3454bb7cc4d Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Fri, 2 Aug 2024 19:20:17 +0300 Subject: [PATCH] Refactor Ets values, operations, visitors (#249) --- .../kotlin/org/jacodb/ets/base/EtsConstant.kt | 44 +- .../kotlin/org/jacodb/ets/base/EtsEntity.kt | 13 +- .../kotlin/org/jacodb/ets/base/EtsExpr.kt | 643 ++++++++++++++++-- .../org/jacodb/ets/base/EtsImmediate.kt | 24 +- .../kotlin/org/jacodb/ets/base/EtsLocal.kt | 2 +- .../main/kotlin/org/jacodb/ets/base/EtsRef.kt | 36 +- .../kotlin/org/jacodb/ets/base/EtsStmt.kt | 2 +- .../kotlin/org/jacodb/ets/base/EtsValue.kt | 48 +- .../main/kotlin/org/jacodb/ets/base/Ops.kt | 293 +------- .../main/kotlin/org/jacodb/ets/dto/Convert.kt | 166 +++-- .../org/jacodb/ets/utils/GetOperands.kt | 176 ++++- 11 files changed, 937 insertions(+), 510 deletions(-) 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 1b7534230..508a93b7e 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 @@ -16,35 +16,7 @@ package org.jacodb.ets.base -interface EtsConstant : EtsImmediate { - interface Visitor { - fun visit(value: EtsStringConstant): R - fun visit(value: EtsBooleanConstant): R - 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 - - interface Default : Visitor { - override fun visit(value: EtsStringConstant): R = defaultVisit(value) - override fun visit(value: EtsBooleanConstant): R = defaultVisit(value) - 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) - - fun defaultVisit(value: EtsConstant): R - } - } - - override fun accept(visitor: EtsImmediate.Visitor): R { - return accept(visitor as Visitor) - } - - fun accept(visitor: Visitor): R -} +interface EtsConstant : EtsImmediate data class EtsStringConstant( val value: String, @@ -56,7 +28,7 @@ data class EtsStringConstant( return "\"$value\"" } - override fun accept(visitor: EtsConstant.Visitor): R { + override fun accept(visitor: EtsValue.Visitor): R { return visitor.visit(this) } } @@ -71,7 +43,7 @@ data class EtsBooleanConstant( return if (value) "true" else "false" } - override fun accept(visitor: EtsConstant.Visitor): R { + override fun accept(visitor: EtsValue.Visitor): R { return visitor.visit(this) } @@ -91,7 +63,7 @@ data class EtsNumberConstant( return value.toString() } - override fun accept(visitor: EtsConstant.Visitor): R { + override fun accept(visitor: EtsValue.Visitor): R { return visitor.visit(this) } } @@ -102,7 +74,7 @@ object EtsNullConstant : EtsConstant { override fun toString(): String = "null" - override fun accept(visitor: EtsConstant.Visitor): R { + override fun accept(visitor: EtsValue.Visitor): R { return visitor.visit(this) } } @@ -113,7 +85,7 @@ object EtsUndefinedConstant : EtsConstant { override fun toString(): String = "undefined" - override fun accept(visitor: EtsConstant.Visitor): R { + override fun accept(visitor: EtsValue.Visitor): R { return visitor.visit(this) } } @@ -135,7 +107,7 @@ data class EtsArrayLiteral( return elements.joinToString(prefix = "[", postfix = "]") } - override fun accept(visitor: EtsConstant.Visitor): R { + override fun accept(visitor: EtsValue.Visitor): R { return visitor.visit(this) } } @@ -151,7 +123,7 @@ data class EtsObjectLiteral( } } - override fun accept(visitor: EtsConstant.Visitor): R { + override fun accept(visitor: EtsValue.Visitor): R { return visitor.visit(this) } } 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 f0dc498ba..30fb3d1d9 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 @@ -25,18 +25,15 @@ interface EtsEntity : CommonExpr { get() = type.typeName interface Visitor : - EtsImmediate.Visitor, - EtsExpr.Visitor, - EtsRef.Visitor { + EtsValue.Visitor, + EtsExpr.Visitor { interface Default : Visitor, - EtsImmediate.Visitor.Default, - EtsExpr.Visitor.Default, - EtsRef.Visitor.Default { + EtsValue.Visitor.Default, + EtsExpr.Visitor.Default { - override fun defaultVisit(value: EtsImmediate): R = defaultVisit(value as EtsEntity) + override fun defaultVisit(value: EtsValue): R = defaultVisit(value as EtsEntity) override fun defaultVisit(expr: EtsExpr): R = defaultVisit(expr as EtsEntity) - override fun defaultVisit(ref: EtsRef): R = defaultVisit(ref as EtsEntity) fun defaultVisit(value: EtsEntity): R } diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsExpr.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsExpr.kt index 83b33d2ed..309a667ee 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsExpr.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsExpr.kt @@ -23,31 +23,116 @@ interface EtsExpr : EtsEntity { interface Visitor { fun visit(expr: EtsNewExpr): R fun visit(expr: EtsNewArrayExpr): R - fun visit(expr: EtsDeleteExpr): R - fun visit(expr: EtsTypeOfExpr): R - fun visit(expr: EtsInstanceOfExpr): R fun visit(expr: EtsLengthExpr): R fun visit(expr: EtsCastExpr): R - fun visit(expr: EtsUnaryOperation): R - fun visit(expr: EtsBinaryOperation): R - fun visit(expr: EtsRelationOperation): R + fun visit(expr: EtsInstanceOfExpr): R + + // Unary + fun visit(expr: EtsDeleteExpr): R + fun visit(expr: EtsTypeOfExpr): R + fun visit(expr: EtsVoidExpr): R + fun visit(expr: EtsNotExpr): R + fun visit(expr: EtsBitNotExpr): R + fun visit(expr: EtsNegExpr): R + fun visit(expr: EtsUnaryPlusExpr): R + fun visit(expr: EtsPreIncExpr): R + fun visit(expr: EtsPreDecExpr): R + fun visit(expr: EtsPostIncExpr): R + fun visit(expr: EtsPostDecExpr): R + + // Relation + fun visit(expr: EtsEqExpr): R + fun visit(expr: EtsNotEqExpr): R + fun visit(expr: EtsStrictEqExpr): R + fun visit(expr: EtsStrictNotEqExpr): R + fun visit(expr: EtsLtExpr): R + fun visit(expr: EtsLtEqExpr): R + fun visit(expr: EtsGtExpr): R + fun visit(expr: EtsGtEqExpr): R + fun visit(expr: EtsInExpr): R + + // Arithmetic + fun visit(expr: EtsAddExpr): R + fun visit(expr: EtsSubExpr): R + fun visit(expr: EtsMulExpr): R + fun visit(expr: EtsDivExpr): R + fun visit(expr: EtsRemExpr): R + fun visit(expr: EtsExpExpr): R + + // Bitwise + fun visit(expr: EtsBitAndExpr): R + fun visit(expr: EtsBitOrExpr): R + fun visit(expr: EtsBitXorExpr): R + fun visit(expr: EtsLeftShiftExpr): R + fun visit(expr: EtsRightShiftExpr): R + fun visit(expr: EtsUnsignedRightShiftExpr): R + + // Logical + fun visit(expr: EtsAndExpr): R + fun visit(expr: EtsOrExpr): R + fun visit(expr: EtsNullishCoalescingExpr): R + + // Call fun visit(expr: EtsInstanceCallExpr): R fun visit(expr: EtsStaticCallExpr): R + // Other + fun visit(expr: EtsCommaExpr): R + fun visit(expr: EtsTernaryExpr): R + interface Default : Visitor { override fun visit(expr: EtsNewExpr): R = defaultVisit(expr) override fun visit(expr: EtsNewArrayExpr): R = defaultVisit(expr) - override fun visit(expr: EtsDeleteExpr): R = defaultVisit(expr) - override fun visit(expr: EtsTypeOfExpr): R = defaultVisit(expr) - override fun visit(expr: EtsInstanceOfExpr): R = defaultVisit(expr) override fun visit(expr: EtsLengthExpr): R = defaultVisit(expr) override fun visit(expr: EtsCastExpr): R = defaultVisit(expr) - override fun visit(expr: EtsUnaryOperation): R = defaultVisit(expr) - override fun visit(expr: EtsBinaryOperation): R = defaultVisit(expr) - override fun visit(expr: EtsRelationOperation): R = defaultVisit(expr) + override fun visit(expr: EtsInstanceOfExpr): R = defaultVisit(expr) + + override fun visit(expr: EtsDeleteExpr): R = defaultVisit(expr) + override fun visit(expr: EtsTypeOfExpr): R = defaultVisit(expr) + override fun visit(expr: EtsVoidExpr): R = defaultVisit(expr) + override fun visit(expr: EtsNotExpr): R = defaultVisit(expr) + override fun visit(expr: EtsBitNotExpr): R = defaultVisit(expr) + override fun visit(expr: EtsNegExpr): R = defaultVisit(expr) + override fun visit(expr: EtsUnaryPlusExpr): R = defaultVisit(expr) + override fun visit(expr: EtsPreIncExpr): R = defaultVisit(expr) + override fun visit(expr: EtsPreDecExpr): R = defaultVisit(expr) + override fun visit(expr: EtsPostIncExpr): R = defaultVisit(expr) + override fun visit(expr: EtsPostDecExpr): R = defaultVisit(expr) + + override fun visit(expr: EtsEqExpr): R = defaultVisit(expr) + override fun visit(expr: EtsNotEqExpr): R = defaultVisit(expr) + override fun visit(expr: EtsStrictEqExpr): R = defaultVisit(expr) + override fun visit(expr: EtsStrictNotEqExpr): R = defaultVisit(expr) + override fun visit(expr: EtsLtExpr): R = defaultVisit(expr) + override fun visit(expr: EtsLtEqExpr): R = defaultVisit(expr) + override fun visit(expr: EtsGtExpr): R = defaultVisit(expr) + override fun visit(expr: EtsGtEqExpr): R = defaultVisit(expr) + override fun visit(expr: EtsInExpr): R = defaultVisit(expr) + + override fun visit(expr: EtsAddExpr): R = defaultVisit(expr) + override fun visit(expr: EtsSubExpr): R = defaultVisit(expr) + override fun visit(expr: EtsMulExpr): R = defaultVisit(expr) + override fun visit(expr: EtsDivExpr): R = defaultVisit(expr) + override fun visit(expr: EtsRemExpr): R = defaultVisit(expr) + override fun visit(expr: EtsExpExpr): R = defaultVisit(expr) + + override fun visit(expr: EtsBitAndExpr): R = defaultVisit(expr) + override fun visit(expr: EtsBitOrExpr): R = defaultVisit(expr) + override fun visit(expr: EtsBitXorExpr): R = defaultVisit(expr) + override fun visit(expr: EtsLeftShiftExpr): R = defaultVisit(expr) + override fun visit(expr: EtsRightShiftExpr): R = defaultVisit(expr) + override fun visit(expr: EtsUnsignedRightShiftExpr): R = defaultVisit(expr) + + override fun visit(expr: EtsAndExpr): R = defaultVisit(expr) + override fun visit(expr: EtsOrExpr): R = defaultVisit(expr) + override fun visit(expr: EtsNullishCoalescingExpr): R = defaultVisit(expr) + override fun visit(expr: EtsInstanceCallExpr): R = defaultVisit(expr) override fun visit(expr: EtsStaticCallExpr): R = defaultVisit(expr) + override fun visit(expr: EtsCommaExpr): R = defaultVisit(expr) + override fun visit(expr: EtsTernaryExpr): R = defaultVisit(expr) + fun defaultVisit(expr: EtsExpr): R } } @@ -71,14 +156,15 @@ data class EtsNewExpr( } } -data class EtsDeleteExpr( - val arg: EtsEntity, +data class EtsNewArrayExpr( + val elementType: EtsType, + val size: EtsEntity, ) : EtsExpr { override val type: EtsType - get() = EtsBooleanType + get() = EtsArrayType(elementType, 1) override fun toString(): String { - return "delete $arg" + return "new Array<${elementType.typeName}>($size)" } override fun accept(visitor: EtsExpr.Visitor): R { @@ -86,15 +172,14 @@ data class EtsDeleteExpr( } } -data class EtsNewArrayExpr( - val elementType: EtsType, - val size: EtsEntity, +data class EtsLengthExpr( + val arg: EtsEntity, ) : EtsExpr { override val type: EtsType - get() = EtsArrayType(elementType, 1) + get() = EtsNumberType override fun toString(): String { - return "new Array<${elementType.typeName}>($size)" + return "${arg}.length" } override fun accept(visitor: EtsExpr.Visitor): R { @@ -102,14 +187,12 @@ data class EtsNewArrayExpr( } } -data class EtsTypeOfExpr( +data class EtsCastExpr( val arg: EtsEntity, + override val type: EtsType, ) : EtsExpr { - override val type: EtsType - get() = EtsStringType - override fun toString(): String { - return "typeof $arg" + return "$arg as $type" } override fun accept(visitor: EtsExpr.Visitor): R { @@ -133,14 +216,18 @@ data class EtsInstanceOfExpr( } } -data class EtsLengthExpr( - val arg: EtsEntity, -) : EtsExpr { +interface EtsUnaryExpr : EtsExpr { + val arg: EtsEntity +} + +data class EtsDeleteExpr( + override val arg: EtsEntity, +) : EtsUnaryExpr { override val type: EtsType - get() = EtsNumberType + get() = EtsBooleanType override fun toString(): String { - return "${arg}.length" + return "delete $arg" } override fun accept(visitor: EtsExpr.Visitor): R { @@ -148,12 +235,57 @@ data class EtsLengthExpr( } } -data class EtsCastExpr( - val arg: EtsEntity, +data class EtsTypeOfExpr( + override val arg: EtsEntity, +) : EtsUnaryExpr { + override val type: EtsType + get() = EtsStringType + + override fun toString(): String { + return "typeof $arg" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsVoidExpr( + override val arg: EtsEntity, +) : EtsUnaryExpr { + override val type: EtsType + get() = EtsUndefinedType + + override fun toString(): String { + return "void $arg" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsNotExpr( + override val arg: EtsEntity, +) : EtsUnaryExpr { + override val type: EtsType + get() = EtsBooleanType + + override fun toString(): String { + return "!$arg" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsBitNotExpr( override val type: EtsType, -) : EtsExpr { + override val arg: EtsEntity, +) : EtsUnaryExpr { override fun toString(): String { - return "$arg as $type" + return "~$arg" } override fun accept(visitor: EtsExpr.Visitor): R { @@ -161,19 +293,79 @@ data class EtsCastExpr( } } -interface EtsUnaryExpr : EtsExpr { - val arg: EtsEntity +data class EtsNegExpr( + override val type: EtsType, + override val arg: EtsEntity, +) : EtsUnaryExpr { + override fun toString(): String { + return "-$arg" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} +data class EtsUnaryPlusExpr( + override val arg: EtsEntity, +) : EtsUnaryExpr { override val type: EtsType - get() = arg.type + get() = EtsNumberType + + override fun toString(): String { + return "+$arg" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } } -data class EtsUnaryOperation( - val op: UnaryOp, +data class EtsPreIncExpr( + override val type: EtsType, + override val arg: EtsEntity, +) : EtsUnaryExpr { + override fun toString(): String { + return "++$arg" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsPreDecExpr( + override val type: EtsType, + override val arg: EtsEntity, +) : EtsUnaryExpr { + override fun toString(): String { + return "--$arg" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsPostIncExpr( + override val type: EtsType, + override val arg: EtsEntity, +) : EtsUnaryExpr { + override fun toString(): String { + return "$arg++" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsPostDecExpr( + override val type: EtsType, override val arg: EtsEntity, ) : EtsUnaryExpr { override fun toString(): String { - return "$op$arg" + return "$arg--" } override fun accept(visitor: EtsExpr.Visitor): R { @@ -186,27 +378,95 @@ interface EtsBinaryExpr : EtsExpr { val right: EtsEntity } -// TODO: AddExpr and many others -// data class AddExpr( -// override val left: Value, -// override val right: Value, -// ) : BinaryExpr { -// override fun toString(): String { -// return "$left + $right" -// } -// } +interface EtsRelationExpr : EtsBinaryExpr { + override val type: EtsType + get() = EtsBooleanType +} -data class EtsBinaryOperation( - val op: BinaryOp, +data class EtsEqExpr( override val left: EtsEntity, override val right: EtsEntity, -) : EtsBinaryExpr { - // TODO: either use a type inference mechanism or add a type field - override val type: EtsType - get() = EtsUnknownType +) : EtsRelationExpr { + override fun toString(): String { + return "$left == $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsNotEqExpr( + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsRelationExpr { + override fun toString(): String { + return "$left != $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsStrictEqExpr( + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsRelationExpr { + override fun toString(): String { + return "$left === $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsStrictNotEqExpr( + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsRelationExpr { + override fun toString(): String { + return "$left !== $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsLtExpr( + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsRelationExpr { + override fun toString(): String { + return "$left < $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} +data class EtsLtEqExpr( + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsRelationExpr { + override fun toString(): String { + return "$left <= $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsGtExpr( + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsRelationExpr { override fun toString(): String { - return "$left $op $right" + return "$left > $right" } override fun accept(visitor: EtsExpr.Visitor): R { @@ -214,18 +474,246 @@ data class EtsBinaryOperation( } } -interface EtsConditionExpr : EtsBinaryExpr { +data class EtsGtEqExpr( + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsRelationExpr { + override fun toString(): String { + return "$left >= $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsInExpr( + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsRelationExpr { override val type: EtsType get() = EtsBooleanType + + override fun toString(): String { + return "$left in $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +interface EtsArithmeticExpr : EtsBinaryExpr + +data class EtsAddExpr( + override val type: EtsType, + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsArithmeticExpr { + override fun toString(): String { + return "$left + $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsSubExpr( + override val type: EtsType, + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsArithmeticExpr { + override fun toString(): String { + return "$left - $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsMulExpr( + override val type: EtsType, + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsArithmeticExpr { + override fun toString(): String { + return "$left * $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } } -data class EtsRelationOperation( - val relop: String, +data class EtsDivExpr( + override val type: EtsType, // EtsNumberType override val left: EtsEntity, override val right: EtsEntity, -) : EtsConditionExpr { +) : EtsArithmeticExpr { override fun toString(): String { - return "$left $relop $right" + return "$left / $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsRemExpr( + override val type: EtsType, + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsArithmeticExpr { + override fun toString(): String { + return "$left % $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsExpExpr( + override val type: EtsType, + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsArithmeticExpr { + override fun toString(): String { + return "$left ** $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +interface EtsBitwiseExpr : EtsBinaryExpr + +data class EtsBitAndExpr( + override val type: EtsType, + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsBitwiseExpr { + override fun toString(): String { + return "$left & $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsBitOrExpr( + override val type: EtsType, + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsBitwiseExpr { + override fun toString(): String { + return "$left | $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsBitXorExpr( + override val type: EtsType, + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsBitwiseExpr { + override fun toString(): String { + return "$left ^ $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsLeftShiftExpr( + override val type: EtsType, + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsBitwiseExpr { + override fun toString(): String { + return "$left << $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +// Sign-propagating right shift +data class EtsRightShiftExpr( + override val type: EtsType, + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsBitwiseExpr { + override fun toString(): String { + return "$left >> $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +// Zero-fill right shift +data class EtsUnsignedRightShiftExpr( + override val type: EtsType, + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsBitwiseExpr { + override fun toString(): String { + return "$left >>> $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +interface EtsLogicalExpr : EtsBinaryExpr + +data class EtsAndExpr( + override val type: EtsType, + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsLogicalExpr { + override fun toString(): String { + return "$left && $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsOrExpr( + override val type: EtsType, + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsLogicalExpr { + override fun toString(): String { + return "$left || $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsNullishCoalescingExpr( + override val type: EtsType, + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsLogicalExpr { + override fun toString(): String { + return "$left ?? $right" } override fun accept(visitor: EtsExpr.Visitor): R { @@ -267,3 +755,34 @@ data class EtsStaticCallExpr( return visitor.visit(this) } } + +data class EtsCommaExpr( + override val left: EtsEntity, + override val right: EtsEntity, +) : EtsBinaryExpr { + override val type: EtsType + get() = right.type + + override fun toString(): String { + return "$left, $right" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} + +data class EtsTernaryExpr( + override val type: EtsType, + val condition: EtsEntity, + val thenExpr: EtsEntity, + val elseExpr: EtsEntity, +) : EtsExpr { + override fun toString(): String { + return "$condition ? $thenExpr : $elseExpr" + } + + override fun accept(visitor: EtsExpr.Visitor): R { + return visitor.visit(this) + } +} diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsImmediate.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsImmediate.kt index 3e208575b..ce70c7b90 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsImmediate.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsImmediate.kt @@ -16,26 +16,4 @@ package org.jacodb.ets.base -import org.jacodb.api.common.cfg.CommonValue - -interface EtsImmediate : EtsValue, CommonValue { - interface Visitor : EtsConstant.Visitor { - fun visit(value: EtsLocal): R - - interface Default : Visitor, - EtsConstant.Visitor.Default { - - override fun visit(value: EtsLocal): R = defaultVisit(value) - - override fun defaultVisit(value: EtsConstant): R = defaultVisit(value as EtsImmediate) - - fun defaultVisit(value: EtsImmediate): R - } - } - - override fun accept(visitor: EtsEntity.Visitor): R { - return this.accept(visitor as Visitor) - } - - fun accept(visitor: Visitor): R -} +interface EtsImmediate : EtsValue diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsLocal.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsLocal.kt index 4dac4e22e..120263d2d 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsLocal.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/EtsLocal.kt @@ -24,7 +24,7 @@ data class EtsLocal( return name } - override fun accept(visitor: EtsImmediate.Visitor): R { + 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 adb8cc448..bba2641be 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 @@ -20,38 +20,14 @@ import org.jacodb.api.common.cfg.CommonArgument import org.jacodb.api.common.cfg.CommonThis import org.jacodb.ets.model.EtsFieldSignature -interface EtsRef : EtsValue { - interface Visitor { - fun visit(ref: EtsThis): R - fun visit(ref: EtsParameterRef): R - fun visit(ref: EtsArrayAccess): R - fun visit(ref: EtsInstanceFieldRef): R - fun visit(ref: EtsStaticFieldRef): R - - interface Default : Visitor { - override fun visit(ref: EtsThis): R = defaultVisit(ref) - override fun visit(ref: EtsParameterRef): R = defaultVisit(ref) - override fun visit(ref: EtsArrayAccess): R = defaultVisit(ref) - override fun visit(ref: EtsInstanceFieldRef): R = defaultVisit(ref) - override fun visit(ref: EtsStaticFieldRef): R = defaultVisit(ref) - - fun defaultVisit(ref: EtsRef): R - } - } - - override fun accept(visitor: EtsEntity.Visitor): R { - return accept(visitor as Visitor) - } - - fun accept(visitor: Visitor): R -} +interface EtsRef : EtsValue data class EtsThis( override val type: EtsClassType, ) : EtsRef, CommonThis { override fun toString(): String = "this" - override fun accept(visitor: EtsRef.Visitor): R { + override fun accept(visitor: EtsValue.Visitor): R { return visitor.visit(this) } } @@ -64,7 +40,7 @@ data class EtsParameterRef( return "arg$index" } - override fun accept(visitor: EtsRef.Visitor): R { + override fun accept(visitor: EtsValue.Visitor): R { return visitor.visit(this) } } @@ -78,7 +54,7 @@ data class EtsArrayAccess( return "$array[$index]" } - override fun accept(visitor: EtsRef.Visitor): R { + override fun accept(visitor: EtsValue.Visitor): R { return visitor.visit(this) } } @@ -98,7 +74,7 @@ data class EtsInstanceFieldRef( return "$instance.${field.name}" } - override fun accept(visitor: EtsRef.Visitor): R { + override fun accept(visitor: EtsValue.Visitor): R { return visitor.visit(this) } } @@ -110,7 +86,7 @@ data class EtsStaticFieldRef( return "${field.enclosingClass.name}.${field.name}" } - override fun accept(visitor: EtsRef.Visitor): R { + override fun accept(visitor: EtsValue.Visitor): R { return visitor.visit(this) } } 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 2bd017bc0..1efd08e63 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 @@ -143,7 +143,7 @@ class EtsGotoStmt( data class EtsIfStmt( override val location: EtsInstLocation, - val condition: EtsConditionExpr, + val condition: EtsEntity, ) : EtsBranchingStmt { override fun toString(): String { return "if ($condition)" 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 11da01e07..6ef988243 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 @@ -18,4 +18,50 @@ package org.jacodb.ets.base import org.jacodb.api.common.cfg.CommonValue -interface EtsValue : EtsEntity, CommonValue +interface EtsValue : EtsEntity, CommonValue { + interface Visitor { + fun visit(value: EtsLocal): R + + // Constant + fun visit(value: EtsStringConstant): R + fun visit(value: EtsBooleanConstant): R + 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: EtsArrayAccess): R + fun visit(value: EtsInstanceFieldRef): R + fun visit(value: EtsStaticFieldRef): R + + interface Default : Visitor { + override fun visit(value: EtsLocal): R = defaultVisit(value) + + override fun visit(value: EtsStringConstant): R = defaultVisit(value) + override fun visit(value: EtsBooleanConstant): R = defaultVisit(value) + 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: EtsArrayAccess): R = defaultVisit(value) + override fun visit(value: EtsInstanceFieldRef): R = defaultVisit(value) + override fun visit(value: EtsStaticFieldRef): R = defaultVisit(value) + + fun defaultVisit(value: EtsValue): R + } + } + + override fun accept(visitor: EtsEntity.Visitor): R { + return accept(visitor as Visitor) + } + + fun accept(visitor: Visitor): R +} diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/Ops.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/Ops.kt index ece9e5097..3661e0469 100644 --- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/Ops.kt +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/base/Ops.kt @@ -16,260 +16,41 @@ package org.jacodb.ets.base -enum class UnaryOp { - /** - * '-' - */ - Minus, - - /** - * '+' - */ - Plus, - - /** - * '!' - */ - Bang, - - /** - * '~' - */ - Tilde, - - /** - * 'typeof' - */ - Typeof, - - /** - * 'void' - */ - Void, - - /** - * 'delete' - */ - Delete, -} - -enum class UpdateOp { - /** - * '++' - */ - Inc, - - /** - * '--' - */ - Dec, -} - -enum class BinaryOp { - /** - * `==` - */ - EqEq, - - /** - * `!=` - */ - NotEq, - - /** - * `===` - */ - EqEqEq, - - /** - * `!==` - */ - NotEqEq, - - /** - * `<` - */ - Lt, - - /** - * `<=` - */ - LtEq, - - /** - * `>` - */ - Gt, - - /** - * `>=` - */ - GtEq, - - /** - * `<<` - */ - LShift, - - /** - * `>>` - */ - RShift, - - /** - * `>>>` - */ - ZeroFillRShift, - - /** - * `+` - */ - Add, - - /** - * `-` - */ - Sub, - - /** - * `*` - */ - Mul, - - /** - * '/' - */ - Div, - - /** - * `%` - */ - Mod, - - /** - * `|` - */ - BitOr, - - /** - * `^` - */ - BitXor, - - /** - * `&` - */ - BitAnd, - - /** - * `||` - */ - LogicalOr, - - /** - * `&&` - */ - LogicalAnd, - - /** - * `in` - */ - In, - - /** - * `instanceof` - */ - InstanceOf, - - /** - * `**` - */ - Exp, - - /** - * `??` - */ - NullishCoalescing, -} - -enum class AssignOp { - /** - * '=' - */ - Assign, - - /** - * '+=' - */ - AddAssign, - - /** - * '-=' - */ - SubAssign, - - /** - * '*=' - */ - MulAssign, - - /** - * '/=' - */ - DivAssign, - - /** - * '%=' - */ - ModAssign, - - /** - * '<<=' - */ - LShiftAssign, - - /** - * '>>=' - */ - RShiftAssign, - - /** - * '>>>=' - */ - ZeroFillRShiftAssign, - - /** - * '|=' - */ - BitOrAssign, - - /** - * '^=' - */ - BitXorAssign, - - /** - * '&=' - */ - BitAndAssign, - - /** - * '**=' - */ - ExpAssign, - - /** - * '&&=' - */ - AndAssign, - - /** - * '||=' - */ - OrAssign, - - /** - * '??=' - */ - NullishAssign, +object Ops { + const val EQ_EQ = "==" + const val NOT_EQ = "!=" + const val EQ_EQ_EQ = "===" + const val NOT_EQ_EQ = "!==" + const val GT = ">" + const val GT_EQ = ">=" + const val LT = "<" + const val LT_EQ = "<=" + const val IN = "in" + const val PLUS = "+" // unary + const val MINUS = "-" // unary + const val ADD = "+" // binary + const val SUB = "-" // binary + const val MUL = "*" + const val DIV = "/" + const val MOD = "%" + const val EXP = "**" + const val INC = "++" + const val DEC = "--" + const val LSH = "<<" + const val RSH = ">>" + const val URSH = ">>>" + const val BIT_AND = "&" + const val BIT_OR = "|" + const val BIT_XOR = "^" + const val BIT_NOT = "~" + const val NOT = "!" + const val AND = "&&" + const val OR = "||" + const val NULLISH = "??" + const val COMMA = "," + // const val DELETE = "delete" + // const val TYPEOF = "typeof" + // const val VOID = "void" + // const val AS = "as" + // const val INSTANCEOF = "instanceof" } 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 70d19f68b..502a08aea 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 @@ -16,13 +16,17 @@ package org.jacodb.ets.dto -import org.jacodb.ets.base.BinaryOp +import org.jacodb.ets.base.EtsAddExpr +import org.jacodb.ets.base.EtsAndExpr 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.EtsBinaryOperation +import org.jacodb.ets.base.EtsBitAndExpr +import org.jacodb.ets.base.EtsBitNotExpr +import org.jacodb.ets.base.EtsBitOrExpr +import org.jacodb.ets.base.EtsBitXorExpr import org.jacodb.ets.base.EtsBooleanConstant import org.jacodb.ets.base.EtsBooleanType import org.jacodb.ets.base.EtsCallExpr @@ -30,52 +34,74 @@ import org.jacodb.ets.base.EtsCallStmt import org.jacodb.ets.base.EtsCallableType import org.jacodb.ets.base.EtsCastExpr import org.jacodb.ets.base.EtsClassType -import org.jacodb.ets.base.EtsConditionExpr +import org.jacodb.ets.base.EtsCommaExpr import org.jacodb.ets.base.EtsConstant 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.EtsFieldRef import org.jacodb.ets.base.EtsGotoStmt +import org.jacodb.ets.base.EtsGtEqExpr +import org.jacodb.ets.base.EtsGtExpr import org.jacodb.ets.base.EtsIfStmt +import org.jacodb.ets.base.EtsInExpr import org.jacodb.ets.base.EtsInstLocation import org.jacodb.ets.base.EtsInstanceCallExpr 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.EtsLiteralType import org.jacodb.ets.base.EtsLocal +import org.jacodb.ets.base.EtsLtEqExpr +import org.jacodb.ets.base.EtsLtExpr +import org.jacodb.ets.base.EtsMulExpr +import org.jacodb.ets.base.EtsNegExpr import org.jacodb.ets.base.EtsNeverType import org.jacodb.ets.base.EtsNewArrayExpr import org.jacodb.ets.base.EtsNewExpr import org.jacodb.ets.base.EtsNopStmt +import org.jacodb.ets.base.EtsNotEqExpr +import org.jacodb.ets.base.EtsNotExpr import org.jacodb.ets.base.EtsNullConstant 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.EtsRelationOperation +import org.jacodb.ets.base.EtsPreDecExpr +import org.jacodb.ets.base.EtsPreIncExpr +import org.jacodb.ets.base.EtsRemExpr import org.jacodb.ets.base.EtsReturnStmt +import org.jacodb.ets.base.EtsRightShiftExpr import org.jacodb.ets.base.EtsStaticCallExpr import org.jacodb.ets.base.EtsStaticFieldRef import org.jacodb.ets.base.EtsStmt +import org.jacodb.ets.base.EtsStrictEqExpr +import org.jacodb.ets.base.EtsStrictNotEqExpr import org.jacodb.ets.base.EtsStringConstant import org.jacodb.ets.base.EtsStringType +import org.jacodb.ets.base.EtsSubExpr import org.jacodb.ets.base.EtsSwitchStmt import org.jacodb.ets.base.EtsThis import org.jacodb.ets.base.EtsThrowStmt import org.jacodb.ets.base.EtsTupleType import org.jacodb.ets.base.EtsType import org.jacodb.ets.base.EtsTypeOfExpr -import org.jacodb.ets.base.EtsUnaryOperation +import org.jacodb.ets.base.EtsUnaryPlusExpr 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.EtsUnknownType +import org.jacodb.ets.base.EtsUnsignedRightShiftExpr import org.jacodb.ets.base.EtsValue import org.jacodb.ets.base.EtsVoidType -import org.jacodb.ets.base.UnaryOp +import org.jacodb.ets.base.Ops import org.jacodb.ets.graph.EtsCfg import org.jacodb.ets.model.EtsClass import org.jacodb.ets.model.EtsClassImpl @@ -176,7 +202,7 @@ class EtsMethodBuilder( is IfStmtDto -> EtsIfStmt( location = loc(), - condition = convertToEtsEntity(stmt.condition) as EtsConditionExpr, + condition = convertToEtsEntity(stmt.condition), ) is SwitchStmtDto -> EtsSwitchStmt( @@ -258,22 +284,70 @@ class EtsMethodBuilder( type = convertToEtsType(value.type), ) - is UnaryOperationDto -> EtsUnaryOperation( - op = convertToEtsUnaryOp(value.op), - arg = convertToEtsEntity(value.arg), - ) + 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 BinaryOperationDto -> EtsBinaryOperation( - op = convertToEtsBinaryOp(value.op), - left = convertToEtsEntity(value.left), - right = convertToEtsEntity(value.right), - ) + 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) + + else -> error("Unknown binop: ${value.op}") + } + } - is RelationOperationDto -> EtsRelationOperation( - relop = value.op, - left = convertToEtsEntity(value.left), - right = convertToEtsEntity(value.right), - ) + 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 InstanceCallExprDto -> EtsInstanceCallExpr( instance = convertToEtsEntity(value.instance), @@ -573,8 +647,8 @@ fun convertToEtsConstant(value: ConstantDto): EtsConstant { override fun toString(): String = "Unknown(${value.value})" - override fun accept(visitor: EtsConstant.Visitor): R { - if (visitor is EtsConstant.Visitor.Default) { + override fun accept(visitor: EtsValue.Visitor): R { + if (visitor is EtsValue.Visitor.Default) { return visitor.defaultVisit(this) } error("Cannot handle $this") @@ -583,52 +657,6 @@ fun convertToEtsConstant(value: ConstantDto): EtsConstant { } } -fun convertToEtsUnaryOp(op: String): UnaryOp { - return when (op) { - "+" -> UnaryOp.Plus - "-" -> UnaryOp.Minus - "!" -> UnaryOp.Bang - "~" -> UnaryOp.Tilde - "typeof" -> UnaryOp.Typeof - "void" -> UnaryOp.Void - "delete" -> UnaryOp.Delete - "MinusToken" -> UnaryOp.Minus - "PlusToken" -> UnaryOp.Plus - else -> error("Unknown UnaryOp: $op") - } -} - -fun convertToEtsBinaryOp(op: String): BinaryOp { - return when (op) { - "+" -> BinaryOp.Add - "-" -> BinaryOp.Sub - "*" -> BinaryOp.Mul - "/" -> BinaryOp.Div - "%" -> BinaryOp.Mod - "==" -> BinaryOp.EqEq - "!=" -> BinaryOp.NotEq - "===" -> BinaryOp.EqEqEq - "!==" -> BinaryOp.NotEqEq - "<" -> BinaryOp.Lt - "<=" -> BinaryOp.LtEq - ">" -> BinaryOp.Gt - ">=" -> BinaryOp.GtEq - "<<" -> BinaryOp.LShift - ">>" -> BinaryOp.RShift - ">>>" -> BinaryOp.ZeroFillRShift - "&" -> BinaryOp.BitAnd - "|" -> BinaryOp.BitOr - "^" -> BinaryOp.BitXor - "&&" -> BinaryOp.LogicalAnd - "||" -> BinaryOp.LogicalOr - "in" -> BinaryOp.In - "instanceof" -> BinaryOp.InstanceOf - "**" -> BinaryOp.Exp - "??" -> BinaryOp.NullishCoalescing - else -> error("Unknown BinaryOp: $op") - } -} - fun convertToEtsClassSignature(clazz: ClassSignatureDto): EtsClassSignature { return EtsClassSignature( name = clazz.name, 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 a3d7d0007..d29520c4c 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 @@ -16,41 +16,73 @@ 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.EtsBinaryOperation +import org.jacodb.ets.base.EtsBitAndExpr +import org.jacodb.ets.base.EtsBitNotExpr +import org.jacodb.ets.base.EtsBitOrExpr +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.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.EtsGotoStmt +import org.jacodb.ets.base.EtsGtEqExpr +import org.jacodb.ets.base.EtsGtExpr import org.jacodb.ets.base.EtsIfStmt +import org.jacodb.ets.base.EtsInExpr import org.jacodb.ets.base.EtsInstanceCallExpr 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.EtsLocal +import org.jacodb.ets.base.EtsLtEqExpr +import org.jacodb.ets.base.EtsLtExpr +import org.jacodb.ets.base.EtsMulExpr +import org.jacodb.ets.base.EtsNegExpr import org.jacodb.ets.base.EtsNewArrayExpr import org.jacodb.ets.base.EtsNewExpr import org.jacodb.ets.base.EtsNopStmt +import org.jacodb.ets.base.EtsNotEqExpr +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.EtsRelationOperation +import org.jacodb.ets.base.EtsPostDecExpr +import org.jacodb.ets.base.EtsPostIncExpr +import org.jacodb.ets.base.EtsPreDecExpr +import org.jacodb.ets.base.EtsPreIncExpr +import org.jacodb.ets.base.EtsRemExpr import org.jacodb.ets.base.EtsReturnStmt +import org.jacodb.ets.base.EtsRightShiftExpr import org.jacodb.ets.base.EtsStaticCallExpr import org.jacodb.ets.base.EtsStaticFieldRef import org.jacodb.ets.base.EtsStmt +import org.jacodb.ets.base.EtsStrictEqExpr +import org.jacodb.ets.base.EtsStrictNotEqExpr import org.jacodb.ets.base.EtsStringConstant +import org.jacodb.ets.base.EtsSubExpr import org.jacodb.ets.base.EtsSwitchStmt +import org.jacodb.ets.base.EtsTernaryExpr import org.jacodb.ets.base.EtsThis import org.jacodb.ets.base.EtsThrowStmt import org.jacodb.ets.base.EtsTypeOfExpr -import org.jacodb.ets.base.EtsUnaryOperation +import org.jacodb.ets.base.EtsUnaryPlusExpr import org.jacodb.ets.base.EtsUndefinedConstant +import org.jacodb.ets.base.EtsUnsignedRightShiftExpr +import org.jacodb.ets.base.EtsVoidExpr fun EtsStmt.getOperands(): Sequence { return accept(StmtGetOperands) @@ -61,6 +93,7 @@ fun EtsEntity.getOperands(): Sequence { } private object StmtGetOperands : EtsStmt.Visitor> { + override fun visit(stmt: EtsNopStmt): Sequence = emptySequence() @@ -87,6 +120,7 @@ private object StmtGetOperands : EtsStmt.Visitor> { } private object EntityGetOperands : EtsEntity.Visitor> { + override fun visit(value: EtsLocal): Sequence = emptySequence() @@ -110,7 +144,22 @@ private object EntityGetOperands : EtsEntity.Visitor> { // TODO: check override fun visit(value: EtsObjectLiteral): Sequence = - value.properties.asSequence().map { it.second } + value.properties.asSequence().map { (_, v) -> v } + + override fun visit(value: EtsThis): Sequence = + emptySequence() + + override fun visit(value: EtsParameterRef): Sequence = + emptySequence() + + override fun visit(value: EtsArrayAccess): Sequence = + sequenceOf(value.array, value.index) + + override fun visit(value: EtsInstanceFieldRef): Sequence = + sequenceOf(value.instance) + + override fun visit(value: EtsStaticFieldRef): Sequence = + emptySequence() override fun visit(expr: EtsNewExpr): Sequence = emptySequence() @@ -118,28 +167,118 @@ private object EntityGetOperands : EtsEntity.Visitor> { override fun visit(expr: EtsNewArrayExpr): Sequence = sequenceOf(expr.size) + override fun visit(expr: EtsLengthExpr): Sequence = + sequenceOf(expr.arg) + + override fun visit(expr: EtsCastExpr): Sequence = + sequenceOf(expr.arg) + + override fun visit(expr: EtsInstanceOfExpr): Sequence = + sequenceOf(expr.arg) + override fun visit(expr: EtsDeleteExpr): Sequence = sequenceOf(expr.arg) override fun visit(expr: EtsTypeOfExpr): Sequence = sequenceOf(expr.arg) - override fun visit(expr: EtsInstanceOfExpr): Sequence = + override fun visit(expr: EtsVoidExpr): Sequence = sequenceOf(expr.arg) - override fun visit(expr: EtsLengthExpr): Sequence = + override fun visit(expr: EtsNotExpr): Sequence = sequenceOf(expr.arg) - override fun visit(expr: EtsCastExpr): Sequence = + override fun visit(expr: EtsBitNotExpr): Sequence = + sequenceOf(expr.arg) + + override fun visit(expr: EtsNegExpr): Sequence = + sequenceOf(expr.arg) + + override fun visit(expr: EtsUnaryPlusExpr): Sequence = + sequenceOf(expr.arg) + + override fun visit(expr: EtsPreIncExpr): Sequence = + sequenceOf(expr.arg) + + override fun visit(expr: EtsPreDecExpr): Sequence = + sequenceOf(expr.arg) + + override fun visit(expr: EtsPostIncExpr): Sequence = sequenceOf(expr.arg) - override fun visit(expr: EtsUnaryOperation): Sequence = + override fun visit(expr: EtsPostDecExpr): Sequence = sequenceOf(expr.arg) - override fun visit(expr: EtsBinaryOperation): Sequence = + override fun visit(expr: EtsEqExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsNotEqExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsStrictEqExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsStrictNotEqExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsLtExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsLtEqExpr): Sequence = sequenceOf(expr.left, expr.right) - override fun visit(expr: EtsRelationOperation): Sequence = + override fun visit(expr: EtsGtExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsGtEqExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsInExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsAddExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsSubExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsMulExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsDivExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsRemExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsExpExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsBitAndExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsBitOrExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsBitXorExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsLeftShiftExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsRightShiftExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsUnsignedRightShiftExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsAndExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsOrExpr): Sequence = + sequenceOf(expr.left, expr.right) + + override fun visit(expr: EtsNullishCoalescingExpr): Sequence = sequenceOf(expr.left, expr.right) override fun visit(expr: EtsInstanceCallExpr): Sequence = @@ -148,18 +287,9 @@ private object EntityGetOperands : EtsEntity.Visitor> { override fun visit(expr: EtsStaticCallExpr): Sequence = expr.args.asSequence() - override fun visit(ref: EtsThis): Sequence = - emptySequence() - - override fun visit(ref: EtsParameterRef): Sequence = - emptySequence() - - override fun visit(ref: EtsArrayAccess): Sequence = - sequenceOf(ref.array, ref.index) - - override fun visit(ref: EtsInstanceFieldRef): Sequence = - sequenceOf(ref.instance) + override fun visit(expr: EtsCommaExpr): Sequence = + sequenceOf(expr.left, expr.right) - override fun visit(ref: EtsStaticFieldRef): Sequence = - emptySequence() + override fun visit(expr: EtsTernaryExpr): Sequence = + sequenceOf(expr.condition, expr.thenExpr, expr.elseExpr) }