diff --git a/.gitignore b/.gitignore index c3a04f401..cb5496040 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ bin/ .project .settings/ .idea/ +.kotlin/ **/.DS_Store rpgJavaInterpreter-core/generated-src/ rpgJavaInterpreter-core/src/main/gen/ diff --git a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/compile_time_interpreter.kt b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/compile_time_interpreter.kt index ca38f74de..506fc8656 100644 --- a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/compile_time_interpreter.kt +++ b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/compile_time_interpreter.kt @@ -286,6 +286,21 @@ open class BaseCompileTimeInterpreter( return findType(rContext.getStatements(procedureName), declName, conf, false)!! } + /** + * Find type of declaration by specifically look for it in DEFINE statements. + */ + open fun evaluateTypeOfDefine(rContext: RContext, declName: String, conf: ToAstConfiguration, procedureName: String?): Type? { + val statements = rContext.getStatements(procedureName) + val define = statements + .mapNotNull { it.cspec_fixed() } + .mapNotNull { it.cspec_fixed_standard() } + .mapNotNull { it.csDEFINE() } + .map { it.toAst(conf) } + val match = define.firstOrNull { it.newVarName.equals(declName, ignoreCase = true) } ?: return null + + return findType(statements, match.originalName, conf) + } + private fun findType(statements: List, declName: String, conf: ToAstConfiguration, innerBlock: Boolean = true): Type? { statements .forEach { it -> diff --git a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/internal_interpreter.kt b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/internal_interpreter.kt index 3d89e0f9b..b2387786f 100644 --- a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/internal_interpreter.kt +++ b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/internal_interpreter.kt @@ -1111,7 +1111,6 @@ open class InternalInterpreter( is QualifiedAccessExpr -> { when (val container = eval(target.container)) { is DataStructValue -> { - container[target.field.referred!!] container.set(target.field.referred!!, coerce(value, target.field.referred!!.type)) } diff --git a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/parsetreetoast/data_definitions.kt b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/parsetreetoast/data_definitions.kt index acc03bae0..4d282cb56 100644 --- a/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/parsetreetoast/data_definitions.kt +++ b/rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/parsetreetoast/data_definitions.kt @@ -890,7 +890,6 @@ private fun RpgParser.Parm_fixedContext.toFieldInfo( } if (overlay != null) { - this.name val pos = overlay.keyword_overlay().pos val nameExpr = overlay.keyword_overlay().name val targetFieldName = nameExpr.identifier().text @@ -904,16 +903,16 @@ private fun RpgParser.Parm_fixedContext.toFieldInfo( val hasInitValue = this.keyword().find { it.keyword_inz() != null } // compileTimeInterpreter.evaluate(this.rContext(), dim!!).asInt().value.toInt(), val varName = like?.variable?.name ?: this.name + val compileTimeInterpreter = InjectableCompileTimeInterpreter( + knownDataDefinitions = knownDataDefinitions.toList(), + delegatedCompileTimeInterpreter = conf.compileTimeInterpreter + ) val explicitElementType: Type? = this.calculateExplicitElementType(arraySizeDeclared, conf) ?: knownDataDefinitions.firstOrNull { it.name.equals(varName, ignoreCase = true) }?.type ?: knownDataDefinitions.flatMap { it.fields }.firstOrNull { fe -> fe.name.equals(varName, ignoreCase = true) }?.type ?: fieldsExtname?.firstOrNull { it.name.equals(varName, ignoreCase = true) }?.elementType - ?: like?.let { - InjectableCompileTimeInterpreter( - knownDataDefinitions = knownDataDefinitions.toList(), - delegatedCompileTimeInterpreter = conf.compileTimeInterpreter - ).evaluateTypeOf(this.rContext(), it, conf) - } + ?: like?.let { compileTimeInterpreter.evaluateTypeOf(this.rContext(), it, conf) } + ?: compileTimeInterpreter.evaluateTypeOfDefine(this.rContext(), varName, conf, null) if (hasInitValue != null) { initializationValue = if (hasInitValue.keyword_inz().simpleExpression() != null) { 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 b3beda60d..f4dfbd806 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 @@ -783,4 +783,14 @@ open class MULANGT02ConstAndDSpecTest : MULANGTTest() { val expected = listOf("ABCFG") assertEquals(expected, "smeup/MUDRNRAPU00165".outputOf(configuration = smeupConfig)) } + + /** + * Fields in a DS based on existing definitions + * @see #LS24004911 + */ + @Test + fun executeMUDRNRAPU00270() { + val expected = listOf("OK", "OK") + assertEquals(expected, "smeup/MUDRNRAPU00270".outputOf(configuration = smeupConfig)) + } } diff --git a/rpgJavaInterpreter-core/src/test/resources/smeup/MUDRNRAPU00270.rpgle b/rpgJavaInterpreter-core/src/test/resources/smeup/MUDRNRAPU00270.rpgle new file mode 100644 index 000000000..781b858d0 --- /dev/null +++ b/rpgJavaInterpreter-core/src/test/resources/smeup/MUDRNRAPU00270.rpgle @@ -0,0 +1,34 @@ + V* ============================================================== + V* 13/11/2024 APU002 Creation + V* ============================================================== + O * PROGRAM GOAL + O * Define a DS with fields based on existing definitions + V* ============================================================== + O * JARIKO ANOMALY + O * Before the fix, the error was about the CKEY not being resolved + V* ============================================================== + D CKEY DS + D §OAVT1 + D §OAVP1 + D §OAVT2 + D §OAVP2 + D §OAVAT + + D £OAVT1 S 2 + D £OAVP1 S 10 + D £OAVT2 S 2 + D £OAVP2 S 10 + D £OAVAT S 15 + + C EVAL £OAVT1='OK' + C EVAL §OAVT1='OK' + C £OAVT1 DSPLY + C §OAVT1 DSPLY + + C *LIKE DEFINE £OAVT1 §OAVT1 + C *LIKE DEFINE £OAVP1 §OAVP1 + C *LIKE DEFINE £OAVT2 §OAVT2 + C *LIKE DEFINE £OAVP2 §OAVP2 + C *LIKE DEFINE £OAVAT §OAVAT + + C SETON LR \ No newline at end of file