Skip to content

Commit

Permalink
Merge pull request #654 from smeup/bugfix/LS24004772/MOVEA-ProjectedA…
Browse files Browse the repository at this point in the history
…rrayValue-to-ConcreteArrayValue

Bugfix/LS24004772/`MOVEA` from `ProjectedArrayValue` to `ConcreteArrayValue`
  • Loading branch information
lanarimarco authored Nov 11, 2024
2 parents f348f40 + 048951c commit 37754c3
Show file tree
Hide file tree
Showing 11 changed files with 337 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ fun coerce(value: Value, type: Type): Value {
}
is ArrayType -> {
val coercedValue = coerce(value, type.element)
ConcreteArrayValue(MutableList(type.element.size) { coercedValue }, type.element)
ConcreteArrayValue(MutableList(type.nElements) { coercedValue }, type.element)
}
else -> TODO("Converting DecimalValue to $type")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.smeup.rpgparser.interpreter

import com.smeup.rpgparser.parsing.ast.*
import kotlin.math.pow

fun movea(operationExtenter: String?, target: AssignableExpression, valueExpression: Expression, interpreterCore: InterpreterCore): Value {
return when (target) {
Expand Down Expand Up @@ -62,21 +63,22 @@ private fun moveaNumber(
targetArray.getElement(it + 1)
} else {
val newValueIndex = it - startIndex + 1
if (newValueIndex < newValue.elements.size) {
newValue.elements[newValueIndex]
var elementValue = if (newValueIndex < newValue.arrayLength()) {
newValue.getElement(newValueIndex + 1)
} else {
if (operationExtenter == null) {
targetArray.getElement(it + 1)
} else {
IntValue.ZERO
}
}
internalCoercing(elementValue, targetArray.elementType, newValue.elementType)
}
}
return arrayValue
}

private fun InterpreterCore.toArray(expression: Expression, targetType: Type): ConcreteArrayValue =
private fun InterpreterCore.toArray(expression: Expression, targetType: Type): ArrayValue =
when (expression) {
is ArrayAccessExpr -> {
val arrayValueRaw = eval(expression.array)
Expand All @@ -90,7 +92,7 @@ private fun InterpreterCore.toArray(expression: Expression, targetType: Type): C
}
is DataRefExpr -> {
if (expression.type() is ArrayType) {
eval(expression) as ConcreteArrayValue
eval(expression) as ArrayValue
} else {
ConcreteArrayValue(mutableListOf(eval(expression)), expression.type())
}
Expand Down Expand Up @@ -152,4 +154,44 @@ private fun valueFromSourceExpression(interpreterCore: InterpreterCore, valueExp
} else {
interpreterCore.eval(valueExpression)
}
}

/**
* Coerces `sourceValue` to match `targetType` based on specified numeric conversion rules, especially
* for conversions between decimal and integer types with varying decimal precision. This function
* validates that the number of digits between `sourceType` and `targetType` are equal before performing
* the conversion.
*
* @param sourceValue The `Value` to be coerced, generally a numeric type such as `DecimalValue` or `IntValue`.
* @param targetType The target `Type` for the coercion, used to guide the conversion, particularly
* regarding the number of decimal places.
* @param sourceType The `Type` representing the original type of `sourceValue`, assisting in determining
* the required scale and format for conversion.
*
* @return The resulting `Value` after coercion, transformed to align with `targetType`.
*
* @throws IllegalStateException if the total number of digits between `sourceType` and `targetType`
* do not match, indicating incompatible numeric sizes for conversion.
* @throws ClassCastException if `sourceValue` is not a `DecimalValue` or `IntValue`, or if `targetType`
* or `sourceType` are not of numeric types.
*/
private fun internalCoercing(
sourceValue: Value,
targetType: Type,
sourceType: Type
): Value {
// Number of digits between source and target must be equals.
if (sourceType is NumberType && targetType is NumberType && sourceType.numberOfDigits != targetType.numberOfDigits) {
throw IllegalStateException("Factor 2 and Result with different type and size.")
}

return when {
// Proper conversion between a left side as decimal to right side as integer
sourceValue is DecimalValue && sourceType is NumberType && targetType is NumberType && targetType.decimalDigits == 0 ->
DecimalValue(sourceValue.value * 10.0.pow(targetType.entireDigits - sourceType.entireDigits).toBigDecimal())
// Or integer to decimal
sourceValue is IntValue && targetType is NumberType && targetType.decimalDigits > 0 ->
DecimalValue((sourceValue.value / 10.0.pow(targetType.decimalDigits)).toBigDecimal())
else -> sourceValue
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -960,6 +960,30 @@ class JarikoCallbackTest : AbstractTest() {
assertEquals(rpgProgramTraces.filter { it.description == "TRACETST2" }.size, 1)
}

@Test
fun executeERROR45CallBackTest() {
executePgmCallBackTest("ERROR45", SourceReferenceType.Program, "ERROR45", mapOf(
18 to "Factor 2 and Result with different type and size."
))
}

@Test
fun executeERROR45SourceLineTest() {
executeSourceLineTest("ERROR45")
}

@Test
fun executeERROR46CallBackTest() {
executePgmCallBackTest("ERROR46", SourceReferenceType.Program, "ERROR46", mapOf(
18 to "Factor 2 and Result with different type and size."
))
}

@Test
fun executeERROR46SourceLineTest() {
executeSourceLineTest("ERROR46")
}

@Test
fun bypassSyntaxErrorTest() {
val configuration = Configuration().apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -558,4 +558,60 @@ open class MULANGT10BaseCodopTest : MULANGTTest() {
val expected = listOf("1", "1", "1", "1", "1", "1", "2", "2")
assertEquals(expected, "smeup/MUDRNRAPU00148".outputOf(configuration = smeupConfig))
}

/**
* MOVEA between a DS field declared as array and a standalone array. Both as integer.
* @see #LS24004772
*/
@Test
fun executeMUDRNRAPU00155() {
val expected = listOf("2", "2", "2", "2", "2", "1", "1", "1", "1", "1")
assertEquals(expected, "smeup/MUDRNRAPU00155".outputOf(configuration = smeupConfig))
}

/**
* MOVEA between a DS field declared as array and a standalone array. Both as integer.
* Size of DS field as array is lower than standalone.
* @see #LS24004772
*/
@Test
fun executeMUDRNRAPU00156() {
val expected = listOf("2", "2", "2", "2", "2", "1", "1", "1", "0", "0")
assertEquals(expected, "smeup/MUDRNRAPU00156".outputOf(configuration = smeupConfig))
}

/**
* MOVEA between a DS field declared as array and a standalone array. Both as integer.
* Size of DS field as array is greater than standalone.
* @see #LS24004772
*/
@Test
fun executeMUDRNRAPU00157() {
val expected = listOf("2", "2", "2", "1", "1", "1")
assertEquals(expected, "smeup/MUDRNRAPU00157".outputOf(configuration = smeupConfig))
}

/**
* MOVEA between a DS field declared as array and a standalone array. DS field array is declared as decimal;
* standalone array as integer.
* Size of DS field as array is lower than standalone.
* @see #LS24004772
*/
@Test
fun executeMUDRNRAPU00158() {
val expected = listOf("2", "2", "2", "2", "2", "1200", "1200", "1200", "0", "0")
assertEquals(expected, "smeup/MUDRNRAPU00158".outputOf(configuration = smeupConfig))
}

/**
* MOVEA between a DS field declared as array and a standalone array. DS field array is declared as integer;
* standalone array as decimal.
* Size of DS field as array is lower than standalone.
* @see #LS24004772
*/
@Test
fun executeMUDRNRAPU00159() {
val expected = listOf("2.200", "2.200", "2.200", "2.200", "2.200", ".001", ".001", ".001", ".000", ".000")
assertEquals(expected, "smeup/MUDRNRAPU00159".outputOf(configuration = smeupConfig))
}
}
25 changes: 25 additions & 0 deletions rpgJavaInterpreter-core/src/test/resources/ERROR45.rpgle
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
V* ==============================================================
D* 05/11/24
D* Purpose: Must fire the following errors during execution of
D* C MOVEA(P) DS1_ARR1 ARR1
D* line 18 - "Factor 2 and Result with different type and size."
V* ==============================================================
D DS1 DS 100
D DS1_ARR1 5 3 DIM(3) INZ(12.345)
D ARR1 S 3 0 DIM(5) INZ(9)
D TMP S 7
D COUNT S 2 0 INZ(1)

C FOR COUNT=1 TO %ELEM(ARR1)
C EVAL TMP=%CHAR(ARR1(COUNT))
C TMP DSPLY
C ENDFOR

C MOVEA(P) DS1_ARR1 ARR1

C FOR COUNT=1 TO %ELEM(ARR1)
C EVAL TMP=%CHAR(ARR1(COUNT))
C TMP DSPLY
C ENDFOR

C SETON LR
25 changes: 25 additions & 0 deletions rpgJavaInterpreter-core/src/test/resources/ERROR46.rpgle
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
V* ==============================================================
D* 05/11/24
D* Purpose: Must fire the following errors during execution of
D* C MOVEA(P) DS1_ARR1 ARR1
D* line 18 - "Factor 2 and Result with different type and size."
V* ==============================================================
D DS1 DS 100
D DS1_ARR1 3 0 DIM(3) INZ(123)
D ARR1 S 5 3 DIM(5) INZ(9.9)
D TMP S 7
D COUNT S 2 0 INZ(1)

C FOR COUNT=1 TO %ELEM(ARR1)
C EVAL TMP=%CHAR(ARR1(COUNT))
C TMP DSPLY
C ENDFOR

C MOVEA(P) DS1_ARR1 ARR1

C FOR COUNT=1 TO %ELEM(ARR1)
C EVAL TMP=%CHAR(ARR1(COUNT))
C TMP DSPLY
C ENDFOR

C SETON LR
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
V* ==============================================================
V* 05/11/2024 APU001 Creation
V* ==============================================================
O * PROGRAM GOAL
O * MOVEA between a DS field declared as array and a standalone
O * array. Both as integer.
V* ==============================================================
O * JARIKO ANOMALY
O * Before the fix:
O * `ProjectedArrayValue cannot be cast to
O * class ConcreteArrayValue`
V* ==============================================================
D DS1 DS 100
D DS1_ARR1 2 0 DIM(5) INZ(1)
D ARR1 S 2 0 DIM(5) INZ(2)
D TMP S 2
D COUNT S 2 0 INZ(1)

C FOR COUNT=1 TO %ELEM(ARR1)
C EVAL TMP=%CHAR(ARR1(COUNT))
C TMP DSPLY
C ENDFOR

C MOVEA(P) DS1_ARR1 ARR1 #ProjectedArrayValue cannot be cast to class ConcreteArrayValue

C FOR COUNT=1 TO %ELEM(ARR1)
C EVAL TMP=%CHAR(ARR1(COUNT))
C TMP DSPLY
C ENDFOR

C SETON LR
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
V* ==============================================================
V* 05/11/2024 APU001 Creation
V* ==============================================================
O * PROGRAM GOAL
O * MOVEA between a DS field declared as array and a standalone
O * array. Both as integer.
O * Size of DS field as array is lower than standalone.
V* ==============================================================
O * JARIKO ANOMALY
O * Before the fix:
O * `ProjectedArrayValue cannot be cast to
O * class ConcreteArrayValue`
V* ==============================================================
D DS1 DS 100
D DS1_ARR1 2 0 DIM(3) INZ(1)
D ARR1 S 2 0 DIM(5) INZ(2)
D TMP S 2
D COUNT S 2 0 INZ(1)

C FOR COUNT=1 TO %ELEM(ARR1)
C EVAL TMP=%CHAR(ARR1(COUNT))
C TMP DSPLY
C ENDFOR

C MOVEA(P) DS1_ARR1 ARR1 #ProjectedArrayValue cannot be cast to class ConcreteArrayValue

C FOR COUNT=1 TO %ELEM(ARR1)
C EVAL TMP=%CHAR(ARR1(COUNT))
C TMP DSPLY
C ENDFOR

C SETON LR
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
V* ==============================================================
V* 05/11/2024 APU001 Creation
V* ==============================================================
O * PROGRAM GOAL
O * MOVEA between a DS field declared as array and a standalone
O * array. Both as integer.
O * Size of DS field as array is greater than standalone.
V* ==============================================================
O * JARIKO ANOMALY
O * Before the fix:
O * `ProjectedArrayValue cannot be cast to
O * class ConcreteArrayValue`
V* ==============================================================
D DS1 DS 100
D DS1_ARR1 2 0 DIM(5) INZ(1)
D ARR1 S 2 0 DIM(3) INZ(2)
D TMP S 2
D COUNT S 2 0 INZ(1)

C FOR COUNT=1 TO %ELEM(ARR1)
C EVAL TMP=%CHAR(ARR1(COUNT))
C TMP DSPLY
C ENDFOR

C MOVEA(P) DS1_ARR1 ARR1 #ProjectedArrayValue cannot be cast to class ConcreteArrayValue

C FOR COUNT=1 TO %ELEM(ARR1)
C EVAL TMP=%CHAR(ARR1(COUNT))
C TMP DSPLY
C ENDFOR

C SETON LR
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
V* ==============================================================
V* 05/11/2024 APU001 Creation
V* ==============================================================
O * PROGRAM GOAL
O * MOVEA between a DS field declared as array and a standalone
O * array. DS field array is declared as decimal;
O * standalone array as integer.
O * Size of DS field as array is lower than standalone.
V* ==============================================================
O * JARIKO ANOMALY
O * Before the fix:
O * `Issue arose while setting field DS1_ARR1`
V* ==============================================================
D DS1 DS 100
D DS1_ARR1 5 3 DIM(3) INZ(1.2)
D ARR1 S 5 0 DIM(5) INZ(2)
D TMP S 5
D COUNT S 2 0 INZ(1)

C FOR COUNT=1 TO %ELEM(ARR1)
C EVAL TMP=%CHAR(ARR1(COUNT))
C TMP DSPLY
C ENDFOR

C MOVEA(P) DS1_ARR1 ARR1 #Issue arose while setting field DS1_ARR1

C FOR COUNT=1 TO %ELEM(ARR1)
C EVAL TMP=%CHAR(ARR1(COUNT))
C TMP DSPLY
C ENDFOR

C SETON LR
Loading

0 comments on commit 37754c3

Please sign in to comment.