Skip to content

Commit

Permalink
Merge pull request #558 from smeup/bugfix/LS24003187/like-variable-fr…
Browse files Browse the repository at this point in the history
…om-copy

Bugfix/ls24003187/like variable from copy
  • Loading branch information
lanarimarco authored Jul 9, 2024
2 parents f4d404d + 12920f8 commit d0ecf7f
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package com.smeup.rpgparser.interpreter
import com.smeup.rpgparser.RpgParser
import com.smeup.rpgparser.RpgParser.Cspec_fixedContext
import com.smeup.rpgparser.RpgParser.Parm_fixedContext
import com.smeup.rpgparser.RpgParser.StatementContext
import com.smeup.rpgparser.execution.MainExecutionContext
import com.smeup.rpgparser.parsing.ast.*
import com.smeup.rpgparser.parsing.facade.findAllDescendants
Expand All @@ -34,8 +35,8 @@ import com.strumenta.kolasu.model.tryToResolve
*/
interface CompileTimeInterpreter {
fun evaluate(rContext: RpgParser.RContext, expression: Expression): Value
fun evaluateElementSizeOf(rContext: RpgParser.RContext, expression: Expression, conf: ToAstConfiguration): Int
fun evaluateTypeOf(rContext: RpgParser.RContext, expression: Expression, conf: ToAstConfiguration): Type
fun evaluateElementSizeOf(rContext: RpgParser.RContext, expression: Expression, conf: ToAstConfiguration, procedureName: String? = null): Int
fun evaluateTypeOf(rContext: RpgParser.RContext, expression: Expression, conf: ToAstConfiguration, procedureName: String? = null): Type
fun evaluateNumberOfElementsOf(rContext: RpgParser.RContext, declName: String): Int
}

Expand All @@ -50,12 +51,12 @@ class InjectableCompileTimeInterpreter(
return mockedDecls[declName]?.numberOfElements() ?: super.evaluateNumberOfElementsOf(rContext, declName)
}

override fun evaluateElementSizeOf(rContext: RpgParser.RContext, declName: String, conf: ToAstConfiguration): Int {
return mockedDecls[declName]?.elementSize() ?: super.evaluateElementSizeOf(rContext, declName, conf)
override fun evaluateElementSizeOf(rContext: RpgParser.RContext, declName: String, conf: ToAstConfiguration, procedureName: String?): Int {
return mockedDecls[declName]?.elementSize() ?: super.evaluateElementSizeOf(rContext, declName, conf, procedureName)
}

override fun evaluateTypeOf(rContext: RpgParser.RContext, declName: String, conf: ToAstConfiguration): Type {
return mockedDecls[declName] ?: super.evaluateTypeOf(rContext, declName, conf)
override fun evaluateTypeOf(rContext: RpgParser.RContext, declName: String, conf: ToAstConfiguration, procedureName: String?): Type {
return mockedDecls[declName] ?: super.evaluateTypeOf(rContext, declName, conf, procedureName)
}

private val mockedDecls = HashMap<String, Type>()
Expand Down Expand Up @@ -145,7 +146,7 @@ open class BaseCompileTimeInterpreter(
throw NotFoundAtCompileTimeException(declName)
}

open fun evaluateElementSizeOf(rContext: RpgParser.RContext, declName: String, conf: ToAstConfiguration): Int {
open fun evaluateElementSizeOf(rContext: RpgParser.RContext, declName: String, conf: ToAstConfiguration, procedureName: String?): Int {
knownDataDefinitions.forEach {
if (it.name.equals(declName, ignoreCase = true)) {
return it.elementSize()
Expand All @@ -154,7 +155,7 @@ open class BaseCompileTimeInterpreter(
if (field != null) return (field.elementSize() /*/ field.declaredArrayInLine!!*/)
}

return findSize(rContext.statement() + rContext.subroutine().flatMap { it.statement() }, declName, conf, false)!!
return findSize(rContext.getStatements(procedureName), declName, conf, false)!!
}

private fun findSize(statements: List<RpgParser.StatementContext>, declName: String, conf: ToAstConfiguration, innerBlock: Boolean = true): Int? {
Expand Down Expand Up @@ -198,14 +199,14 @@ open class BaseCompileTimeInterpreter(
throw NotFoundAtCompileTimeException(declName)
}

override fun evaluateElementSizeOf(rContext: RpgParser.RContext, expression: Expression, conf: ToAstConfiguration): Int {
override fun evaluateElementSizeOf(rContext: RpgParser.RContext, expression: Expression, conf: ToAstConfiguration, procedureName: String?): Int {
return when (expression) {
is DataRefExpr -> {
try {
evaluateElementSizeOf(rContext, expression.variable.name, conf)
evaluateElementSizeOf(rContext, expression.variable.name, conf, procedureName)
} catch (e: NotFoundAtCompileTimeException) {
if (delegatedCompileTimeInterpreter != null) {
return delegatedCompileTimeInterpreter.evaluateElementSizeOf(rContext, expression, conf)
return delegatedCompileTimeInterpreter.evaluateElementSizeOf(rContext, expression, conf, procedureName)
} else {
expression.error(message = e.message, cause = e)
}
Expand All @@ -215,14 +216,14 @@ open class BaseCompileTimeInterpreter(
}
}

override fun evaluateTypeOf(rContext: RpgParser.RContext, expression: Expression, conf: ToAstConfiguration): Type {
override fun evaluateTypeOf(rContext: RpgParser.RContext, expression: Expression, conf: ToAstConfiguration, procedureName: String?): Type {
return when (expression) {
is DataRefExpr -> {
try {
evaluateTypeOf(rContext, expression.variable.name, conf)
evaluateTypeOf(rContext, expression.variable.name, conf, procedureName)
} catch (e: NotFoundAtCompileTimeException) {
if (delegatedCompileTimeInterpreter != null) {
return delegatedCompileTimeInterpreter.evaluateTypeOf(rContext, expression, conf)
return delegatedCompileTimeInterpreter.evaluateTypeOf(rContext, expression, conf, procedureName)
} else {
throw RuntimeException(e)
}
Expand All @@ -232,7 +233,7 @@ open class BaseCompileTimeInterpreter(
}
}

open fun evaluateTypeOf(rContext: RpgParser.RContext, declName: String, conf: ToAstConfiguration): Type {
open fun evaluateTypeOf(rContext: RpgParser.RContext, declName: String, conf: ToAstConfiguration, procedureName: String?): Type {
knownDataDefinitions.forEach {
if (it.name.equals(declName, ignoreCase = true)) {
return it.type
Expand All @@ -243,7 +244,7 @@ open class BaseCompileTimeInterpreter(
}
}

return findType(rContext.statement() + rContext.subroutine().flatMap { it.statement() }, declName, conf, false)!!
return findType(rContext.getStatements(procedureName), declName, conf, false)!!
}

private fun findType(statements: List<RpgParser.StatementContext>, declName: String, conf: ToAstConfiguration, innerBlock: Boolean = true): Type? {
Expand Down Expand Up @@ -321,4 +322,19 @@ open class BaseCompileTimeInterpreter(
private fun Parm_fixedContext.findType(conf: ToAstConfiguration): Type? {
return this.toAst(conf, emptyList()).type
}

private fun RpgParser.RContext.getStatements(procedureName: String?): List<StatementContext> {
val statements: MutableList<StatementContext> = mutableListOf()
if (procedureName != null) {
val procedureContext: RpgParser.ProcedureContext? = this.procedure().firstOrNull { it.beginProcedure().psBegin().ps_name().text.equals(procedureName, ignoreCase = true) }
if (procedureContext != null) {
statements.addAll(
procedureContext.subprocedurestatement().mapNotNull { it.subroutine() }.flatMap { it.statement() } +
procedureContext.subprocedurestatement().mapNotNull { it.statement() })
}
}
statements.addAll(this.statement() + this.subroutine().flatMap { it.statement() })

return statements.toList()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ internal fun RpgParser.Parm_fixedContext.toAst(

val elementSize = when {
like != null -> {
compileTimeInterpreter.evaluateElementSizeOf(this.rContext(), like!!, conf)
compileTimeInterpreter.evaluateElementSizeOf(this.rContext(), like!!, conf, null)
}
else -> this.TO_POSITION().text.trim().let { if (it.isBlank()) null else it.toInt() }
}
Expand Down Expand Up @@ -297,9 +297,9 @@ internal fun RpgParser.DspecContext.toAst(
conf: ToAstConfiguration = ToAstConfiguration(),
knownDataDefinitions: List<DataDefinition>,
parentDataDefinitions: List<DataDefinition>? = null,
fileDefinitions: Map<FileDefinition, List<DataDefinition>>? = null
fileDefinitions: Map<FileDefinition, List<DataDefinition>>? = null,
procedureName: String? = null
): DataDefinition {

if (dspecConstant() != null) return dspecConstant().toAst(conf = conf)
val compileTimeInterpreter = InjectableCompileTimeInterpreter(
knownDataDefinitions = knownDataDefinitions,
Expand Down Expand Up @@ -381,7 +381,7 @@ internal fun RpgParser.DspecContext.toAst(

val elementSize = when {
like != null -> {
compileTimeInterpreter.evaluateElementSizeOf(this.rContext(), like!!, conf)
compileTimeInterpreter.evaluateElementSizeOf(this.rContext(), like!!, conf, procedureName)
}
else -> this.TO_POSITION().text.trim().let { if (it.isBlank()) null else it.toInt() }
}
Expand All @@ -394,7 +394,7 @@ internal fun RpgParser.DspecContext.toAst(
NumberType(elementSize!! - decimalPositions, decimalPositions)
} else {
if (like != null) {
compileTimeInterpreter.evaluateTypeOf(this.rContext(), like!!, conf)
compileTimeInterpreter.evaluateTypeOf(this.rContext(), like!!, conf, procedureName)
} else {
StringType.createInstance(elementSize!!, varying)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ private fun List<StatementContext?>.getDataDefinition(
fileDefinitions: Map<FileDefinition, List<DataDefinition>>? = null,
inputSpecifications: List<InputSpecificationGroup> = emptyList(),
parentDataDefinitions: List<DataDefinition>? = null,
useKnownDataDefinitionInstance: Boolean = false
useKnownDataDefinitionInstance: Boolean = false,
procedureName: String? = null
): Pair<MutableList<DataDefinitionProvider>, KnownDataDefinitionInstance> {
// We need to calculate first all the data definitions which do not contain the LIKE DS directives
// then we calculate the ones with the LIKE DS clause, as they could have references to DS declared
Expand Down Expand Up @@ -133,7 +134,11 @@ private fun List<StatementContext?>.getDataDefinition(
when {
it.dspec() != null -> {
it.dspec()
.toAst(conf, knownDataDefinitions.values.toList(), parentDataDefinitions)
.toAst(
conf = conf,
knownDataDefinitions = knownDataDefinitions.values.toList(),
parentDataDefinitions = parentDataDefinitions,
procedureName = procedureName)
.updateKnownDataDefinitionsAndGetHolder(knownDataDefinitions)
}

Expand Down Expand Up @@ -490,14 +495,17 @@ internal fun SubroutineContext.toAst(conf: ToAstConfiguration = ToAstConfigurati
}

internal fun ProcedureContext.toAst(conf: ToAstConfiguration = ToAstConfiguration(), parentDataDefinitions: List<DataDefinition>): CompilationUnit {

val procedureName = this.beginProcedure().psBegin().ps_name().text
MainExecutionContext.getParsingProgramStack().peek().parsingFunctionNameStack.push(procedureName)

// TODO FileDefinitions

// DataDefinitions
val dataDefinitions = getDataDefinitions(conf, parentDataDefinitions)
val dataDefinitions = getDataDefinitions(
conf = conf,
parentDataDefinitions = parentDataDefinitions,
procedureName = procedureName
)

// Procedure Parameters DataDefinitions
val proceduresParamsDataDefinitions = getProceduresParamsDataDefinitions(dataDefinitions)
Expand Down Expand Up @@ -610,12 +618,13 @@ private fun StatementContext.toDataDefinitionProvider(
}
}

private fun ProcedureContext.getDataDefinitions(conf: ToAstConfiguration = ToAstConfiguration(), parentDataDefinitions: List<DataDefinition>): List<DataDefinition> {
private fun ProcedureContext.getDataDefinitions(conf: ToAstConfiguration = ToAstConfiguration(), parentDataDefinitions: List<DataDefinition>, procedureName: String): List<DataDefinition> {
val (providers, knownDataDefinitions) = this.subprocedurestatement()
.map { it.statement() }
.getDataDefinition(
conf = conf,
parentDataDefinitions = parentDataDefinitions
parentDataDefinitions = parentDataDefinitions,
procedureName = procedureName
)

// PROCEDURE PARAMETERS pass
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
package com.smeup.rpgparser.smeup

open class MULANGT18ProcedureTest : MULANGTTest()
import org.junit.Test
import kotlin.test.assertEquals

open class MULANGT18ProcedureTest : MULANGTTest() {
/**
* LIKE to variable defined into a COPY. This one is also declared inner of procedure.
* @see #LS24003187
*/
@Test
fun executeMU181003() {
val expected = listOf("O: HT -P:HT_P")
assertEquals(expected, "smeup/MU181003".outputOf(configuration = smeupConfig))
}
}
53 changes: 53 additions & 0 deletions rpgJavaInterpreter-core/src/test/resources/QILEGEN/£RISBS.rpgle
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
*====================================================================
* smeup V6R1.023DV
* Nome sorgente : £RISBS
* Sorgente di origine : SMEUP_DEV/QILEGEN(£RISBS)
* Esportato il : 20240613 143719
*====================================================================
V* ==============================================================
V* MODIFICHE Ril. T Au Descrizione
V* gg/mm/aa nn.mm i xx Breve descrizione
V* ==============================================================
V* 13/03/01 04.00 GG Sostituito £RITST con £RISA5
V* 22/10/04 V2R1 PV Aggiunto livello di chiamata
D*----------------------------------------------------------------
D* OBIETTIVO
D* Eseguire la ricerca alfabetica e/o il controllo validità/deco-
D* difica di subsettori tabelle SMEUP
D*
D* FLUSSO
D* Input : £COSET : Codice settore
D* £COSBS : Codice subsettore
D* Output: £DESBS : Descrizione subsettore
D* *IN35 : Se ON subsettore errato
D* *IN36 : Se ON eseguita ricerca
D*
D* ESEMPIO DI CHIAMATA
D*C MOVEL<settore> £COSET
D*C MOVEL<subsett.>£COSBS
D*C EXSR £RISBS
D*C MOVEL£DESBS <campo descrizione>
D*C 35 N60 MOVE 'BAS0001' £MSGCO
D*C 35 SETON 60<ind.err.>
2 D*C N35 36 SETON 10
D*C N35 36 MOVEL£COSBS <campo subsettore>
D*----------------------------------------------------------------
C £RISBS BEGSR
C 'A' IFEQ 'B'
C MOVEL £COSET £COSET 3
C MOVE £COSBS £COSBS 2
C MOVE £RSSLC £RSSLC 1
C ENDIF
C MOVEL £COSET £RISA5 5
C MOVE £COSBS £RISA5
C 'B£AR80' CAT(P) £RSSLC:0 £RSSPG 10
C CALL £RSSPG
C PARM £RISA5
C PARM £DESBS 30
C PARM £IN35 1
C PARM £IN36 1
C £IN35 COMP '1' 35
C £IN36 COMP '1' 36
C MOVEL £RISA5 £COSET
C MOVE £RISA5 £COSBS
C ENDSR
50 changes: 50 additions & 0 deletions rpgJavaInterpreter-core/src/test/resources/smeup/MU181003.rpgle
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
V* ==============================================================
V* MODIFICHE Ril. T Au Descrizione
V* gg/mm/aa nn.mm i xx Breve descrizione
V* ==============================================================
V* 03/07/24 MUTEST APU001 Creazione
V*=====================================================================
O * OBIETTIVO
O * Testare il funzionamento della definizione di una variabile,
O * all'interno di una procedura, mediante LIKE verso una presente
O * in una COPY.
O * Questa COPY sarà presente all'interno della procedura stessa.
O * A tal proposito, quest'ultima non dovrà contenere specifiche D,
O * ma dichiarazioni inline di specifiche C.
V* ==============================================================
D A10_S10 S 10
* --------------------------------------------------------------
/COPY QILEGEN,MULANG_D_D
*---------------------------------------------------------------------
RD* M A I N
*---------------------------------------------------------------------
C EVAL £DBG_Pgm = 'MU181003'
C EVAL £DBG_Sez = 'A10'
C EVAL £DBG_Fun = '*INZ'
C EXSR £DBG
C EXSR SEZ_A10
C EXSR £DBG
C EVAL £DBG_Fun = '*END'
C EXSR £DBG
C SETON LR
*---------------------------------------------------------------------
RD* Test atomico LIKE ad una variabile in COPY
*---------------------------------------------------------------------
C SEZ_A10 BEGSR
OA* A£.CDOP(LIKE)
C EVAL £DBG_Pas='P03'
C EVAL A10_S10 = ' HT '
C EVAL £DBG_Str = 'O:' +
C A10_S10 + '-P:' +
C %TRIMR(A10_PR03())
C ENDSR
/COPY QILEGEN,MULANG_D_C
*---------------------------------------------------------------------
P A10_PR03 B
D A10_PR03 PI 10
D A10_PR03_V1 S LIKE(£RSSPG)
C EVAL A10_PR03_V1 = A10_S10
C RETURN %TRIM(A10_PR03_V1) + '_P'
/COPY QILEGEN,£RISBS
P A10_PR03 E
*---------------------------------------------------------------------

0 comments on commit d0ecf7f

Please sign in to comment.