diff --git a/dspfparser/build.gradle b/dspfparser/build.gradle index 8a718c345..fa1c90501 100644 --- a/dspfparser/build.gradle +++ b/dspfparser/build.gradle @@ -32,7 +32,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion" testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlinVersion" testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion" - testImplementation 'junit:junit:4.12' + testImplementation 'junit:junit:4.13.1' implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion" implementation "org.jetbrains.kotlinx:kotlinx-serialization-cbor:$serializationVersion" diff --git a/examples/build.gradle b/examples/build.gradle index 59494a228..bc0fa675a 100644 --- a/examples/build.gradle +++ b/examples/build.gradle @@ -22,7 +22,7 @@ dependencies { implementation project(":rpgJavaInterpreter-core") testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlinVersion" testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion" - testImplementation 'junit:junit:4.12' + testImplementation 'junit:junit:4.13.1' } task javadocJar(type: Jar) { diff --git a/kolasu/build.gradle b/kolasu/build.gradle index 333c5d6ed..9fca56e30 100644 --- a/kolasu/build.gradle +++ b/kolasu/build.gradle @@ -39,7 +39,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion" testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlinVersion" testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion" - testImplementation 'junit:junit:4.12' + testImplementation 'junit:junit:4.13.1' implementation 'com.fifesoft:rsyntaxtextarea:2.5.8' implementation 'com.fifesoft:autocomplete:2.5.8' diff --git a/rpgJavaInterpreter-core/build.gradle b/rpgJavaInterpreter-core/build.gradle index 57f507044..bc1c14049 100644 --- a/rpgJavaInterpreter-core/build.gradle +++ b/rpgJavaInterpreter-core/build.gradle @@ -57,10 +57,10 @@ dependencies { api project(":dspfparser") implementation "org.apache.logging.log4j:log4j-api-kotlin:1.0.0" - implementation "org.apache.logging.log4j:log4j-api:2.15.0" - implementation "org.apache.logging.log4j:log4j-core:2.15.0" + implementation "org.apache.logging.log4j:log4j-api:2.23.0" + implementation 'org.apache.logging.log4j:log4j-core:2.23.0' - implementation 'commons-io:commons-io:2.6' + implementation 'commons-io:commons-io:2.7' implementation 'com.github.ajalt:clikt:2.1.0' api "io.github.smeup.reload:base:$reloadVersion" @@ -76,8 +76,8 @@ dependencies { testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlinVersion" testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion" - testImplementation 'junit:junit:4.12' - testImplementation 'org.hsqldb:hsqldb:2.5.0' + testImplementation 'junit:junit:4.13.1' + testImplementation 'org.hsqldb:hsqldb:2.7.1' testImplementation 'org.mockito.kotlin:mockito-kotlin:5.3.1' } diff --git a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/Evaluator.kt b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/Evaluator.kt index e90dcb8f0..9910e77b5 100644 --- a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/Evaluator.kt +++ b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/Evaluator.kt @@ -42,6 +42,10 @@ interface Evaluator { fun eval(expression: MultExpr): Value fun eval(expression: CharExpr): Value fun eval(expression: LookupExpr): Value + fun eval(expression: LookupGtExpr): Value + fun eval(expression: LookupGeExpr): Value + fun eval(expression: LookupLtExpr): Value + fun eval(expression: LookupLeExpr): Value fun eval(expression: ArrayAccessExpr): Value fun eval(expression: HiValExpr): HiValValue fun eval(expression: LowValExpr): LowValValue diff --git a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/ExpressionEvaluation.kt b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/ExpressionEvaluation.kt index 997bb21f3..23e6d69b2 100644 --- a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/ExpressionEvaluation.kt +++ b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/ExpressionEvaluation.kt @@ -20,10 +20,7 @@ import com.smeup.rpgparser.execution.MainExecutionContext import com.smeup.rpgparser.logging.ProgramUsageType import com.smeup.rpgparser.parsing.ast.* import com.smeup.rpgparser.parsing.parsetreetoast.LogicalCondition -import com.smeup.rpgparser.utils.asBigDecimal -import com.smeup.rpgparser.utils.asLong -import com.smeup.rpgparser.utils.divideAtIndex -import com.smeup.rpgparser.utils.moveEndingString +import com.smeup.rpgparser.utils.* import com.strumenta.kolasu.model.Position import com.strumenta.kolasu.model.specificProcess import java.math.BigDecimal @@ -33,10 +30,7 @@ import java.time.LocalDate import java.time.ZoneId import java.time.format.DateTimeFormatter import java.time.temporal.ChronoUnit -import kotlin.math.abs -import kotlin.math.pow -import kotlin.math.roundToLong -import kotlin.math.sqrt +import kotlin.math.* import kotlin.time.Duration.Companion.nanoseconds class ExpressionEvaluation( @@ -248,25 +242,58 @@ class ExpressionEvaluation( } override fun eval(expression: LookupExpr): Value = proxyLogging(expression) { - val searchValued = expression.searchedValued.evalWith(this) - val array = expression.array.evalWith(this) as ArrayValue - var index = array.elements().indexOfFirst { - areEquals(it, searchValued) - } - // If 'start' and/or 'length' specified (both optional) - // Start: is the index of array element to start search - // Length: is the limit number of elements to search forward - var start = expression.start?.evalWith(this)?.asInt() - start = start?.minus(1.asValue()) ?: 0.asValue() + lookup( + array = expression.array.evalWith(this) as ArrayValue, + arrayType = expression.array.type() as ArrayType, + searchedValue = expression.searchedValued.evalWith(this), + start = expression.start?.evalWith(this)?.asInt(), + length = expression.length?.evalWith(this)?.asInt(), + operator = ComparisonOperator.EQ + ) + } - val arrayElements = expression.array.type().numberOfElements().asValue() - val length = expression.length?.evalWith(this)?.asInt() ?: arrayElements + override fun eval(expression: LookupGtExpr): Value = proxyLogging(expression) { + lookup( + array = expression.array.evalWith(this) as ArrayValue, + arrayType = expression.array.type() as ArrayType, + searchedValue = expression.searchedValue.evalWith(this), + start = expression.start?.evalWith(this)?.asInt(), + length = expression.length?.evalWith(this)?.asInt(), + operator = ComparisonOperator.GT + ) + } - val lowerLimit = start.value - val upperLimit = start.plus(length).value - 1 - if (lowerLimit > index || upperLimit < index) index = -1 + override fun eval(expression: LookupGeExpr): Value = proxyLogging(expression) { + lookup( + array = expression.array.evalWith(this) as ArrayValue, + arrayType = expression.array.type() as ArrayType, + searchedValue = expression.searchedValue.evalWith(this), + start = expression.start?.evalWith(this)?.asInt(), + length = expression.length?.evalWith(this)?.asInt(), + operator = ComparisonOperator.GE + ) + } - return@proxyLogging if (index == -1) 0.asValue() else (index + 1).asValue() + override fun eval(expression: LookupLtExpr): Value = proxyLogging(expression) { + lookup( + array = expression.array.evalWith(this) as ArrayValue, + arrayType = expression.array.type() as ArrayType, + searchedValue = expression.searchedValue.evalWith(this), + start = expression.start?.evalWith(this)?.asInt(), + length = expression.length?.evalWith(this)?.asInt(), + operator = ComparisonOperator.LT + ) + } + + override fun eval(expression: LookupLeExpr): Value = proxyLogging(expression) { + lookup( + array = expression.array.evalWith(this) as ArrayValue, + arrayType = expression.array.type() as ArrayType, + searchedValue = expression.searchedValue.evalWith(this), + start = expression.start?.evalWith(this)?.asInt(), + length = expression.length?.evalWith(this)?.asInt(), + operator = ComparisonOperator.LE + ) } override fun eval(expression: ArrayAccessExpr): Value = proxyLogging(expression) { @@ -792,6 +819,117 @@ class ExpressionEvaluation( } } + private fun lookupLinearSearch(values: List, target: Value): Int { + for ((index, value) in values.withIndex()) { + if (areEquals(value, target)) + return index + } + + return -1 + } + + private inline fun lookupBinarySearchWithComparator( + values: List, + predicate: (Value) -> Boolean, + isAscending: Boolean, + searchingForLower: Boolean + ): Int { + var (left, right) = Pair(0, values.lastIndex) + var bestCandidateIndex = -1 + + while (left <= right) { + val mid = left + (right - left) / 2 + val currentValue = values[mid] + val matchesCondition = predicate(currentValue) + if (matchesCondition) bestCandidateIndex = mid + + /* + * Detect if sorting order follows search direction in order to decide which endpoint to move + * - if it follows direction: move left on match and move right else-wise + * - if it does not follow direction: move right on match and move left else-wise + */ + val shouldSearchRight = if (isAscending == searchingForLower) matchesCondition else !matchesCondition + if (shouldSearchRight) left = mid + 1 else right = mid - 1 + } + + return bestCandidateIndex + } + + private inline fun lookupBinarySearchWithCondition(values: List, predicate: (Value) -> Boolean, target: Value): Int { + var (left, right) = Pair(0, values.lastIndex) + + while (left <= right) { + val mid = left + (right - left) / 2 + val currentValue = values[mid] + + if (predicate(currentValue)) { + return mid + } + + if (currentValue < target) { + right = mid - 1 + continue + } + + // This means currentValue > target + left = mid + 1 + } + + return -1 + } + + private fun lookupBinarySearch( + values: List, + target: Value, + operator: ComparisonOperator, + isAscending: Boolean + ): Int { + return when (operator) { + ComparisonOperator.LE -> + lookupBinarySearchWithComparator(values, { it <= target }, isAscending, true) + ComparisonOperator.LT -> + lookupBinarySearchWithComparator(values, { it < target }, isAscending, true) + ComparisonOperator.GE -> + lookupBinarySearchWithComparator(values, { it >= target }, isAscending, false) + ComparisonOperator.GT -> + lookupBinarySearchWithComparator(values, { it > target }, isAscending, false) + ComparisonOperator.EQ -> lookupBinarySearchWithCondition(values, { areEquals(it, target) }, target) + else -> -1 + } + } + + private fun lookup( + array: ArrayValue, + arrayType: ArrayType, + searchedValue: Value, + start: IntValue?, + length: IntValue?, + operator: ComparisonOperator + ): Value { + val arrayLength = arrayType.numberOfElements() + val isSequenced = arrayType.ascend != null + + when (operator) { + ComparisonOperator.GE, ComparisonOperator.GT, ComparisonOperator.LE, ComparisonOperator.LT -> { + if (!isSequenced) + throw UnsupportedOperationException("Array must be defined with ASCEND or DESCEND keyword") + } + else -> {} + } + + val computedLength = length?.value?.toInt() ?: arrayLength + val lowerBound: Int = start?.value?.let { it - 1 }?.toInt() ?: 0 + val upperBound = min(lowerBound + computedLength, arrayLength) + val searchRange = array.elements().slice(lowerBound until upperBound) + + val index = if (isSequenced) + lookupBinarySearch(searchRange, searchedValue, operator, arrayType.ascend!!) + else lookupLinearSearch(searchRange, searchedValue) + + val offsetIndex = if (index == -1) 0 else index + lowerBound + 1 + return offsetIndex.asValue() + } + private fun cleanNumericString(s: String): String { val result = s.moveEndingString("-") return when { diff --git a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/builtin_functions.kt b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/builtin_functions.kt index 08a44cda5..da35707fd 100644 --- a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/builtin_functions.kt +++ b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/builtin_functions.kt @@ -22,11 +22,6 @@ import com.strumenta.kolasu.model.Position import kotlinx.serialization.Serializable // %LOOKUP -// To be supported: -// * %LOOKUPLT -// * %LOOKUPLE -// * %LOOKUPGT -// * %LOOKUPGE @Serializable data class LookupExpr( var searchedValued: Expression, @@ -40,6 +35,62 @@ data class LookupExpr( override fun evalWith(evaluator: Evaluator): Value = evaluator.eval(this) } +// %LOOKUPGT +@Serializable +data class LookupGtExpr( + var searchedValue: Expression, + val array: Expression, + val start: Expression? = null, + val length: Expression? = null, + override val position: Position? = null +) : Expression(position) { + override val loggableEntityName: String + get() = "%LOOKUPGT" + override fun evalWith(evaluator: Evaluator): Value = evaluator.eval(this) +} + +// %LOOKUPGE +@Serializable +data class LookupGeExpr( + var searchedValue: Expression, + val array: Expression, + val start: Expression? = null, + val length: Expression? = null, + override val position: Position? = null +) : Expression(position) { + override val loggableEntityName: String + get() = "%LOOKUPGE" + override fun evalWith(evaluator: Evaluator): Value = evaluator.eval(this) +} + +// %LOOKUPLT +@Serializable +data class LookupLtExpr( + var searchedValue: Expression, + val array: Expression, + val start: Expression? = null, + val length: Expression? = null, + override val position: Position? = null +) : Expression(position) { + override val loggableEntityName: String + get() = "%LOOKUPLT" + override fun evalWith(evaluator: Evaluator): Value = evaluator.eval(this) +} + +// %LOOKUPLE +@Serializable +data class LookupLeExpr( + var searchedValue: Expression, + val array: Expression, + val start: Expression? = null, + val length: Expression? = null, + override val position: Position? = null +) : Expression(position) { + override val loggableEntityName: String + get() = "%LOOKUPLE" + override fun evalWith(evaluator: Evaluator): Value = evaluator.eval(this) +} + // %SCAN @Serializable data class ScanExpr( diff --git a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/cu_components.kt b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/cu_components.kt index 281bd7276..213d00926 100644 --- a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/cu_components.kt +++ b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/cu_components.kt @@ -75,6 +75,8 @@ data class CompilationUnit( private val inStatementsDataDefinitions = mutableListOf() + fun getInStatementDataDefinitions() = inStatementsDataDefinitions + fun addInStatementDataDefinitions(dataDefinitions: List) { inStatementsDataDefinitions.addAll(dataDefinitions) } diff --git a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/serialization.kt b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/serialization.kt index 67ffc5213..f2d84c36a 100644 --- a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/serialization.kt +++ b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/serialization.kt @@ -153,6 +153,10 @@ private val modules = SerializersModule { subclass(LogicalCondition::class) subclass(LogicalOrExpr::class) subclass(LookupExpr::class) + subclass(LookupGtExpr::class) + subclass(LookupGeExpr::class) + subclass(LookupLtExpr::class) + subclass(LookupLeExpr::class) subclass(LowValExpr::class) subclass(MinusExpr::class) subclass(MultExpr::class) diff --git a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/statements.kt b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/statements.kt index e6db6b823..75c8f8d7e 100644 --- a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/statements.kt +++ b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/statements.kt @@ -1188,7 +1188,10 @@ data class DefineStmt( val containingCU = this.ancestor(CompilationUnit::class.java) ?: return emptyList() + // Search standalone 'D spec' or InStatement definition val originalDataDefinition = containingCU.dataDefinitions.find { it.name == originalName } + ?: containingCU.getInStatementDataDefinitions().find { it.name == originalName } + // If definition was not found as a 'standalone' 'D spec' declaration, // maybe it can be found as a sub-field of DS in 'D specs' declarations containingCU.dataDefinitions.forEach { diff --git a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/parsetreetoast/bif.kt b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/parsetreetoast/bif.kt index e77d9cae1..e0c6e95cd 100644 --- a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/parsetreetoast/bif.kt +++ b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/parsetreetoast/bif.kt @@ -29,6 +29,10 @@ internal fun RpgParser.BifContext.toAst(conf: ToAstConfiguration = ToAstConfigur position = position ) this.bif_lookup() != null -> this.bif_lookup().toAst(conf) + this.bif_lookupge() != null -> this.bif_lookupge().toAst(conf) + this.bif_lookupgt() != null -> this.bif_lookupgt().toAst(conf) + this.bif_lookuple() != null -> this.bif_lookuple().toAst(conf) + this.bif_lookuplt() != null -> this.bif_lookuplt().toAst(conf) this.bif_xlate() != null -> this.bif_xlate().toAst(conf) this.bif_scan() != null -> this.bif_scan().toAst(conf) this.bif_check() != null -> this.bif_check().toAst(conf) @@ -249,6 +253,46 @@ internal fun RpgParser.Bif_lookupContext.toAst(conf: ToAstConfiguration = ToAstC toPosition(conf.considerPosition)) } +internal fun RpgParser.Bif_lookupgeContext.toAst(conf: ToAstConfiguration = ToAstConfiguration()): LookupGeExpr { + return LookupGeExpr( + this.bif_lookupargs().arg.toAst(conf), + this.bif_lookupargs().array.toAst(conf), + this.bif_lookupargs().startindex?.toAst(conf), + this.bif_lookupargs().numberelements?.toAst(conf), + toPosition(conf.considerPosition) + ) +} + +internal fun RpgParser.Bif_lookupgtContext.toAst(conf: ToAstConfiguration = ToAstConfiguration()): LookupGtExpr { + return LookupGtExpr( + this.bif_lookupargs().arg.toAst(conf), + this.bif_lookupargs().array.toAst(conf), + this.bif_lookupargs().startindex?.toAst(conf), + this.bif_lookupargs().numberelements?.toAst(conf), + toPosition(conf.considerPosition) + ) +} + +internal fun RpgParser.Bif_lookupleContext.toAst(conf: ToAstConfiguration = ToAstConfiguration()): LookupLeExpr { + return LookupLeExpr( + this.bif_lookupargs().arg.toAst(conf), + this.bif_lookupargs().array.toAst(conf), + this.bif_lookupargs().startindex?.toAst(conf), + this.bif_lookupargs().numberelements?.toAst(conf), + toPosition(conf.considerPosition) + ) +} + +internal fun RpgParser.Bif_lookupltContext.toAst(conf: ToAstConfiguration = ToAstConfiguration()): LookupLtExpr { + return LookupLtExpr( + this.bif_lookupargs().arg.toAst(conf), + this.bif_lookupargs().array.toAst(conf), + this.bif_lookupargs().startindex?.toAst(conf), + this.bif_lookupargs().numberelements?.toAst(conf), + toPosition(conf.considerPosition) + ) +} + internal fun RpgParser.Bif_parmsContext.toAst(conf: ToAstConfiguration = ToAstConfiguration()): ParmsExpr { return ParmsExpr( this.text, diff --git a/rpgJavaInterpreter-core/src/test/kotlin/com/smeup/rpgparser/smeup/MULANGT02ConstAndDSpecTest.kt b/rpgJavaInterpreter-core/src/test/kotlin/com/smeup/rpgparser/smeup/MULANGT02ConstAndDSpecTest.kt index 328c549d6..4344cbfa9 100644 --- a/rpgJavaInterpreter-core/src/test/kotlin/com/smeup/rpgparser/smeup/MULANGT02ConstAndDSpecTest.kt +++ b/rpgJavaInterpreter-core/src/test/kotlin/com/smeup/rpgparser/smeup/MULANGT02ConstAndDSpecTest.kt @@ -312,4 +312,14 @@ open class MULANGT02ConstAndDSpecTest : MULANGTTest() { val expected = listOf("A40DS1(ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ) DS1_FL1(1)(BCDEFGHIJK) DS1_FL1(2)(LMNOPQRSTU) | A40DS1(A88 LMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ) DS1_FL1(1)(88 ) DS1_FL1(2)(LMNOPQRSTU) | A40DS1(A88 00 VWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ) DS1_FL1(1)(88 ) DS1_FL1(2)(00 )") assertEquals(expected, "smeup/MU024014".outputOf(configuration = smeupConfig)) } + + /** + * DefineStmt on instatement data definitions + * @see #LS24002930 + */ + @Test + fun executeMUDRNRAPU00213() { + val expected = listOf("ok") + assertEquals(expected, "smeup/MUDRNRAPU00213".outputOf(configuration = smeupConfig)) + } } \ No newline at end of file diff --git a/rpgJavaInterpreter-core/src/test/kotlin/com/smeup/rpgparser/smeup/MULANGT15BaseBif1Test.kt b/rpgJavaInterpreter-core/src/test/kotlin/com/smeup/rpgparser/smeup/MULANGT15BaseBif1Test.kt index f7699a704..84dddf98d 100644 --- a/rpgJavaInterpreter-core/src/test/kotlin/com/smeup/rpgparser/smeup/MULANGT15BaseBif1Test.kt +++ b/rpgJavaInterpreter-core/src/test/kotlin/com/smeup/rpgparser/smeup/MULANGT15BaseBif1Test.kt @@ -2,6 +2,7 @@ package com.smeup.rpgparser.smeup import org.junit.Test import kotlin.test.assertEquals +import kotlin.test.assertFailsWith open class MULANGT15BaseBif1Test : MULANGTTest() { /** @@ -53,4 +54,25 @@ open class MULANGT15BaseBif1Test : MULANGTTest() { val expected = listOf("1(10 - North York) 2(5 - North) 3(15 - North )") assertEquals(expected, "smeup/T15_A80_P09".outputOf()) } + + /** + * %LOOKUPxx tests + * @see #LS24002887 + */ + @Test + fun executeMUDRNRAPU00210() { + val expected = listOf("4", "0", "0", "3", "0", "6", "0", "3", "0", "2", "4", "0") + assertEquals(expected, "smeup/MUDRNRAPU00210".outputOf()) + } + + /** + * %LOOKUPxx fails with arrays that are not sequenced + * @see #LS24002887 + */ + @Test + fun executeMUDRNRAPU00211() { + assertFailsWith(RuntimeException::class) { + "smeup/MUDRNRAPU00211".outputOf(configuration = smeupConfig) + } + } } \ No newline at end of file diff --git a/rpgJavaInterpreter-core/src/test/resources/smeup/MUDRNRAPU00210.rpgle b/rpgJavaInterpreter-core/src/test/resources/smeup/MUDRNRAPU00210.rpgle new file mode 100644 index 000000000..65966e5ce --- /dev/null +++ b/rpgJavaInterpreter-core/src/test/resources/smeup/MUDRNRAPU00210.rpgle @@ -0,0 +1,60 @@ + D ARRAY S 5 DIM(10) PERRCD(1) CTDATA ASCEND _NOTXT + D INDEX S 2 0 + *--------------------------------------------------------------- + D* M A I N + *--------------------------------------------------------------- + C EXSR ROUTINE + C SETON LR + *--------------------------------------------------------------- + D* Routine + *--------------------------------------------------------------- + C ROUTINE BEGSR + * GT - some items are greater + C EVAL INDEX=%LOOKUPGT('CCCCC':ARRAY:1:6) + C INDEX DSPLY + * GT - no item is greater + C EVAL INDEX=%LOOKUPGT('IIIII':ARRAY:1:6) + C INDEX DSPLY + * GT - last item is equal + C EVAL INDEX=%LOOKUPGT('FFFFF':ARRAY:1:6) + C INDEX DSPLY + * GE - some items are greater + C EVAL INDEX=%LOOKUPGE('CCCCC':ARRAY:1:6) + C INDEX DSPLY + * GE - no item is greater + C EVAL INDEX=%LOOKUPGE('IIIII':ARRAY:1:6) + C INDEX DSPLY + * GE - last item is equal + C EVAL INDEX=%LOOKUPGE('FFFFF':ARRAY:1:6) + C INDEX DSPLY + * LT - first item is equal + C EVAL INDEX=%LOOKUPLT('BBBBB':ARRAY:2:4) + C INDEX DSPLY + * LT - some items are less + C EVAL INDEX=%LOOKUPLT('DDDDD':ARRAY:2:4) + C INDEX DSPLY + * LT - no item is less + C EVAL INDEX=%LOOKUPLT('AAAAA':ARRAY:2:4) + C INDEX DSPLY + * LE - first item is equal + C EVAL INDEX=%LOOKUPLE('BBBBB':ARRAY:2:4) + C INDEX DSPLY + * LE - some items are less + C EVAL INDEX=%LOOKUPLE('DDDDD':ARRAY:2:4) + C INDEX DSPLY + * LE - no item is less + C EVAL INDEX=%LOOKUPLE('AAAAA':ARRAY:2:4) + C INDEX DSPLY + * + C ENDSR + *--------------------------------------------------------------- +** TXT1 +AAAAA +BBBBB +CCCCC +DDDDD +EEEEE +FFFFF +GGGGG +HHHHH +IIIII \ No newline at end of file diff --git a/rpgJavaInterpreter-core/src/test/resources/smeup/MUDRNRAPU00211.rpgle b/rpgJavaInterpreter-core/src/test/resources/smeup/MUDRNRAPU00211.rpgle new file mode 100644 index 000000000..6c2b781b4 --- /dev/null +++ b/rpgJavaInterpreter-core/src/test/resources/smeup/MUDRNRAPU00211.rpgle @@ -0,0 +1,60 @@ + D ARRAY S 5 DIM(10) PERRCD(1) CTDATA _NOTXT + D INDEX S 2 0 + *--------------------------------------------------------------- + D* M A I N + *--------------------------------------------------------------- + C EXSR ROUTINE + C SETON LR + *--------------------------------------------------------------- + D* Routine + *--------------------------------------------------------------- + C ROUTINE BEGSR + * GT - last item is greater + C EVAL INDEX=%LOOKUPGT('AAAAA':ARRAY:1:3) + C INDEX DSPLY + * GT - last item is equal + C EVAL INDEX=%LOOKUPGT('CCCCC':ARRAY:1:3) + C INDEX DSPLY + * GT - no item found + C EVAL INDEX=%LOOKUPGT('DDDDD':ARRAY:1:3) + C INDEX DSPLY + * GE - last item is greater + C EVAL INDEX=%LOOKUPGE('BBBBB':ARRAY:1:3) + C INDEX DSPLY + * GE - last item is equal + C EVAL INDEX=%LOOKUPGE('CCCCC':ARRAY:1:3) + C INDEX DSPLY + * GE - no item found + C EVAL INDEX=%LOOKUPGE('DDDDD':ARRAY:1:3) + C INDEX DSPLY + * LT - no item found + C EVAL INDEX=%LOOKUPLT('BBBBB':ARRAY:2:2) + C INDEX DSPLY + * LT - one item found + C EVAL INDEX=%LOOKUPLT('DDDDD':ARRAY:2:2) + C INDEX DSPLY + * LT - one item equal + C EVAL INDEX=%LOOKUPLT('CCCCC':ARRAY:2:2) + C INDEX DSPLY + * LE - no item found + C EVAL INDEX=%LOOKUPLE('BBBBB':ARRAY:2:2) + C INDEX DSPLY + * LE - one item found + C EVAL INDEX=%LOOKUPLE('DDDDD':ARRAY:2:2) + C INDEX DSPLY + * LE - one item equal + C EVAL INDEX=%LOOKUPLE('CCCCC':ARRAY:2:2) + C INDEX DSPLY + * + C ENDSR + *--------------------------------------------------------------- +** TXT1 +AAAAA +BBBBB +CCCCC +DDDDD +EEEEE +FFFFF +GGGGG +HHHHH +IIIII \ No newline at end of file diff --git a/rpgJavaInterpreter-core/src/test/resources/smeup/MUDRNRAPU00213.rpgle b/rpgJavaInterpreter-core/src/test/resources/smeup/MUDRNRAPU00213.rpgle new file mode 100644 index 000000000..c1afe69bd --- /dev/null +++ b/rpgJavaInterpreter-core/src/test/resources/smeup/MUDRNRAPU00213.rpgle @@ -0,0 +1,34 @@ + D £DBG_Str S 2 + C £G00 BEGSR + * + C Z-ADD $1 £G00$1 + C Z-ADD $2 £G00$2 + C Z-ADD $3 £G00$3 + + C Z-ADD 01 £G00A1 2 0 + C Z-ADD 02 £G00A2 2 0 + C Z-ADD 03 £G00A3 2 0 + C Z-ADD 04 £G00D1 2 0 + C Z-ADD 05 £G00D2 2 0 + C Z-ADD 06 £G00D3 2 0 + C Z-ADD 07 £G00E2 2 0 + C Z-ADD 08 £G00E3 2 0 + C Z-ADD 10 £G00R1 2 0 + C Z-ADD 60 £G00R2 2 0 + * + C 0 IFEQ 0 + C Z-ADD £G00A1 $1 5 0 + C Z-ADD £G00A2 $2 5 0 + C Z-ADD £G00A3 $3 5 0 + C ENDIF + * + C Z-ADD £G00$1 $1 + C Z-ADD £G00$2 $2 + C Z-ADD £G00$3 $3 + C *LIKE DEFINE $1 £G00$1 + C *LIKE DEFINE $2 £G00$2 + C *LIKE DEFINE $2 £G00$3 + * + C ENDSR + C EVAL £DBG_Str='ok' + C £DBG_Str DSPLY \ No newline at end of file