Skip to content

Commit

Permalink
Merge pull request #465 from smeup/feature/NW23001440/monitor-stmt
Browse files Browse the repository at this point in the history
Feature/nw23001440/monitor stmt
  • Loading branch information
lanarimarco authored Mar 20, 2024
2 parents 5fdf8bd + 267fc47 commit da712af
Show file tree
Hide file tree
Showing 11 changed files with 306 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -206,21 +206,19 @@ class ExpressionEvaluation(

override fun eval(expression: CharExpr): Value {
val value = expression.value.evalWith(this)
return if (expression.value is DivExpr) {
// are always return 10 decimal digits
// fill with 0 if necessary
if (value.asDecimal().value.scale() != 0) {
val numeDecimals = value.asDecimal().value.scale()
if (numeDecimals < 10) {
StringValue(value.stringRepresentation(expression.format) + "0".repeat(10 - numeDecimals))
} else {
StringValue(value.stringRepresentation(expression.format).trim())
}
} else {
StringValue(value.stringRepresentation(expression.format) + ".0000000000")
}
} else {
StringValue(value.stringRepresentation(expression.format))
val representation = value.stringRepresentation(expression.format)

if (expression.value !is DivExpr) {
return StringValue(representation)
}

// Decimals are always returned with 10 decimal digits
// fill with 0 if necessary
val numDecimals = value.asDecimal().value.scale()
return when {
numDecimals == 0 -> StringValue("$representation.0000000000")
numDecimals < 10 -> StringValue(representation + "0".repeat(10 - numDecimals))
else -> StringValue(representation.trim())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,17 @@ class CasOtherExecutionLogEntry(programName: String, val other: CaseOtherClause,
}
}

class MonitorExecutionLogEntry(programName: String, val statement: MonitorStmt) : LogEntry(programName) {
override fun toString(): String {
return "executing MONITOR"
}

override fun renderStatement(channel: String, filename: String, sep: String): String {
val data = "MONITOR"
return renderHeader(channel, filename, statement.startLine(), sep) + data
}
}

class IfExecutionLogEntry(programName: String, val statement: IfStmt, val result: Value) : LogEntry(programName) {
override fun toString(): String {
return "executing IF"
Expand Down Expand Up @@ -442,6 +453,16 @@ class ElseExecutionLogEntry(programName: String, val statement: ElseClause, val
}
}

class OnErrorExecutionLogEntry(programName: String, val statement: OnErrorClause) : LogEntry(programName) {
override fun toString(): String {
return "executing ON-ERROR"
}
override fun renderStatement(channel: String, filename: String, sep: String): String {
val data = "ON-ERROR"
return renderHeader(channel, filename, statement.startLine(), sep) + data
}
}

class EvaluationLogEntry(programName: String, val statement: EvalStmt, val value: Value?) : LogEntry(programName) {
override fun toString(): String {
return "evaluating $statement as $value"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ private val modules = SerializersModule {
subclass(LeaveSrStmt::class)
subclass(LeaveStmt::class)
subclass(LookupStmt::class)
subclass(MonitorStmt::class)
subclass(MoveAStmt::class)
subclass(MoveLStmt::class)
subclass(MoveStmt::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,62 @@ private constructor(val name: String, val fields: List<String>, override val pos
}
}

@Serializable
data class MonitorStmt(
@SerialName("body")
val monitorBody: List<Statement>,
val onErrorClauses: List<OnErrorClause> = emptyList(),
override val position: Position? = null
) : Statement(position), CompositeStatement {

// Since that this property is a collection achieved from thenBody + elseIfClauses + elseClause, this annotation
// is necessary to avoid that the same node is processed more than ones, thing that it would cause that the same
// ErrorEvent is fired more times
@Derived
@Transient
override val body: List<Statement> = mutableListOf<Statement>().apply {
addAll(monitorBody)
onErrorClauses.forEach { addAll(it.body) }
}

override fun accept(mutes: MutableMap<Int, MuteParser.MuteLineContext>, start: Int, end: Int): MutableList<MuteAnnotationResolved> {
// check if the annotation is just before the ELSE
val muteAttached: MutableList<MuteAnnotationResolved> = mutableListOf()

// Process the body statements
muteAttached.addAll(
acceptBody(monitorBody, mutes, this.position!!.start.line, this.position.end.line)
)

// Process the ON ERROR
onErrorClauses.forEach {
muteAttached.addAll(
acceptBody(it.body, mutes, it.position!!.start.line, it.position.end.line)
)
}

return muteAttached
}

override fun execute(interpreter: InterpreterCore) {
interpreter.log {
MonitorExecutionLogEntry(
interpreter.getInterpretationContext().currentProgramName,
this
)
}

try {
interpreter.execute(this.monitorBody)
} catch (_: Exception) {
onErrorClauses.forEach {
interpreter.log { OnErrorExecutionLogEntry(interpreter.getInterpretationContext().currentProgramName, it) }
interpreter.execute(it.body)
}
}
}
}

@Serializable
data class IfStmt(
val condition: Expression,
Expand Down Expand Up @@ -889,6 +945,9 @@ data class IfStmt(
}
}

@Serializable
data class OnErrorClause(override val body: List<Statement>, override val position: Position? = null) : Node(position), CompositeStatement

@Serializable
data class ElseClause(override val body: List<Statement>, override val position: Position? = null) : Node(position), CompositeStatement

Expand Down Expand Up @@ -1061,7 +1120,7 @@ data class DefineStmt(
} else {
val inStatementDataDefinition =
containingCU.main.stmts
.filterIsInstance(StatementThatCanDefineData::class.java)
.filterIsInstance<StatementThatCanDefineData>()
.filter { it != this }
.asSequence()
.map(StatementThatCanDefineData::dataDefinition)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1121,10 +1121,7 @@ internal fun Cspec_fixed_standard_partsContext.toDataDefinition(
position: Position?,
conf: ToAstConfiguration
): InStatementDataDefinition? {
val len = this.len.asInt()
if (len == null) {
return null
}
val len = this.len.asInt() ?: return null
val decimals = this.decimalPositions.asInt()
val initialValue = this.factor2Expression(conf)
return InStatementDataDefinition(name, dataType(len, decimals), position, initializationValue = initialValue)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ internal fun BlockContext.toAst(conf: ToAstConfiguration = ToAstConfiguration())
this.csDOWxx() != null -> this.csDOWxx().toAst(blockContext = this, conf = conf)
this.forstatement() != null -> this.forstatement().toAst(conf)
this.begindou() != null -> this.begindou().toAst(blockContext = this, conf = conf)
this.monitorstatement() != null -> this.monitorstatement().let {
it.beginmonitor().csMONITOR().cspec_fixed_standard_parts().validate(
stmt = it.toAst(conf = conf),
conf = conf
)
}
else -> todo(message = "Missing composite statement implementation for this block: ${this.text}", conf = conf)
}
}
Expand Down Expand Up @@ -358,6 +364,18 @@ internal fun toAst(conf: ToAstConfiguration = ToAstConfiguration()): SelectOther
TODO("OtherContext.toAst with $conf")
}

internal fun RpgParser.MonitorstatementContext.toAst(conf: ToAstConfiguration = ToAstConfiguration()): MonitorStmt {
val position = toPosition(conf.considerPosition)
val statements = this.statement().mapNotNull {
it.toAst(conf)
}
val onErrorClauses = this.onError().mapNotNull {
it.toAst(conf)
}

return MonitorStmt(statements, onErrorClauses, position)
}

internal fun RpgParser.IfstatementContext.toAst(conf: ToAstConfiguration = ToAstConfiguration()): IfStmt {
val position = toPosition(conf.considerPosition)
return if (this.beginif().fixedexpression != null) {
Expand Down Expand Up @@ -387,6 +405,12 @@ internal fun RpgParser.IfstatementContext.toAst(conf: ToAstConfiguration = ToAst
}
}

internal fun RpgParser.OnErrorContext.toAst(conf: ToAstConfiguration = ToAstConfiguration()): OnErrorClause {
val body = this.statement().mapNotNull { kotlin.runCatching { it.toAst(conf) }.getOrNull() }
val position = toPosition(conf.considerPosition)
return OnErrorClause(body, position)
}

internal fun RpgParser.ElseClauseContext.toAst(conf: ToAstConfiguration = ToAstConfiguration()): ElseClause {
return ElseClause(this.statement().mapNotNull { kotlin.runCatching { it.toAst(conf) }.getOrNull() }, toPosition(conf.considerPosition))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,46 @@
package com.smeup.rpgparser.smeup

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

open class MULANGT11Codop2Test : MULANGTTest() {
/**
* MONITOR and error catching
* @see #241
*/
@Test
fun executeT11_A10_P01() {
val expected = listOf("BLOCCO; ERR_ZERO_DIV;")
assertEquals(expected, "smeup/T11_A10_P01".outputOf())
}

/**
* Nested MONITOR statements
* @see #241
*/
@Test
fun executeT11_A10_P02() {
val expected = listOf("BLOCCO1; BLOCCO2; BLOCCO3; ERR_ZERO_DIV; FINE_BLOCCO3;; ERR_ZERO_DIV; FINE_BLOCCO2;; ERR_ZERO_DIV; FINE_BLOCCO1;")
assertEquals(expected, "smeup/T11_A10_P02".outputOf())
}

/**
* MONITOR nested in IF, DO and SELECT
* @see #241
*/
@Test
fun executeT11_A10_P03() {
val expected = listOf("DENTRO_IF(BLOCCO; ERR_ZERO_DIV;) DENTRO_DO(BLOCCO; ERR_ZERO_DIV;BLOCCO; ERR_ZERO_DIV;) DENTRO_WHEN(BLOCCO; ERR_ZERO_DIV;) DENTRO_OTHER(BLOCCO; ERR_ZERO_DIV;)")
assertEquals(expected, "smeup/T11_A10_P03".outputOf())
}

/**
* IF, DO and SELECT in MONITOR
* @see #241
*/
@Test
fun executeT11_A10_P04() {
val expected = listOf("DENTRO_IF(BLOCCO; ERR_ZERO_DIV;) DENTRO_DO(BLOCCO; ERR_ZERO_DIV;) DENTRO_WHEN(BLOCCO; ERR_ZERO_DIV;) DENTRO_OTHER(BLOCCO; ERR_ZERO_DIV;)")
assertEquals(expected, "smeup/T11_A10_P04".outputOf())
}
}
13 changes: 13 additions & 0 deletions rpgJavaInterpreter-core/src/test/resources/smeup/T11_A10_P01.rpgle
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
D £DBG_Str S 150 VARYING
D T11_A10_A20A S 2 0 INZ(10)
D T11_A10_A20B S 2 0 INZ(0)
C MONITOR
C EVAL £DBG_Str=%TRIM(£DBG_Str)+'BLOCCO'
C EVAL £DBG_Str=%TRIM(£DBG_Str)+'; '+
C %CHAR(T11_A10_A20A/T11_A10_A20B)
C EVAL £DBG_Str=%TRIM(£DBG_Str)+'; FINE_BLOCCO;'
C ON-ERROR
C EVAL £DBG_Str=%TRIM(£DBG_Str)+
C '; ERR_ZERO_DIV;'
C ENDMON
C £DBG_Str DSPLY
31 changes: 31 additions & 0 deletions rpgJavaInterpreter-core/src/test/resources/smeup/T11_A10_P02.rpgle
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
D £DBG_Str S 150 VARYING
D T11_A10_A20A S 2 0 INZ(10)
D T11_A10_A20B S 2 0 INZ(0)
C MONITOR
C EVAL £DBG_Str=%TRIM(£DBG_Str)+'BLOCCO1;'
C MONITOR
C EVAL £DBG_Str=%TRIM(£DBG_Str)+' BLOCCO2;'
C MONITOR
C EVAL £DBG_Str=%TRIM(£DBG_Str)+' BLOCCO3'
C EVAL £DBG_Str=%TRIM(£DBG_Str)+'; '+
C %CHAR(T11_A10_A20A/T11_A10_A20B)
C ON-ERROR
C EVAL £DBG_Str=%TRIM(£DBG_Str)+
C '; ERR_ZERO_DIV;'
C ENDMON
C EVAL £DBG_Str=%TRIM(£DBG_Str)+' FINE_BLOCCO3;'
C EVAL £DBG_Str=%TRIM(£DBG_Str)+'; '+
C %CHAR(T11_A10_A20A/T11_A10_A20B)
C ON-ERROR
C EVAL £DBG_Str=%TRIM(£DBG_Str)+
C '; ERR_ZERO_DIV;'
C ENDMON
C EVAL £DBG_Str=%TRIM(£DBG_Str)+' FINE_BLOCCO2;'
C EVAL £DBG_Str=%TRIM(£DBG_Str)+'; '+
C %CHAR(T11_A10_A20A/T11_A10_A20B)
C ON-ERROR
C EVAL £DBG_Str=%TRIM(£DBG_Str)+
C '; ERR_ZERO_DIV;'
C ENDMON
C EVAL £DBG_Str=%TRIM(£DBG_Str)+' FINE_BLOCCO1;'
C £DBG_Str DSPLY
36 changes: 36 additions & 0 deletions rpgJavaInterpreter-core/src/test/resources/smeup/T11_A10_P03.rpgle
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
D £DBG_Str S 180 VARYING
D T11_A10_A20A S 2 0 INZ(10)
D T11_A10_A20B S 2 0 INZ(0)
C EVAL £DBG_Str='DENTRO_IF('
C IF 'A'='A'
C EXSR SUB_SEZ_A10
C ENDIF
C EVAL £DBG_Str=%TRIM(£DBG_Str)+') DENTRO_DO('
C DO 2
C EXSR SUB_SEZ_A10
C ENDDO
C EVAL £DBG_Str=%TRIM(£DBG_Str)+') DENTRO_WHEN('
C SELECT
C WHEN 'A'='A'
C EXSR SUB_SEZ_A10
C ENDSL
C EVAL £DBG_Str=%TRIM(£DBG_Str)+') DENTRO_OTHER('
C SELECT
C WHEN 'A'='B'
C OTHER
C EXSR SUB_SEZ_A10
C ENDSL
C EVAL £DBG_Str=%TRIM(£DBG_Str)+')'
C £DBG_Str DSPLY

C SUB_SEZ_A10 BEGSR
C MONITOR
C EVAL £DBG_Str=%TRIM(£DBG_Str)+'BLOCCO'
C EVAL £DBG_Str=%TRIM(£DBG_Str)+'; '+
C %CHAR(T11_A10_A20A/T11_A10_A20B)
C EVAL £DBG_Str=%TRIM(£DBG_Str)+'; FINE_BLOCCO;'
C ON-ERROR
C EVAL £DBG_Str=%TRIM(£DBG_Str)+
C '; ERR_ZERO_DIV;'
C ENDMON
C ENDSR
Loading

0 comments on commit da712af

Please sign in to comment.