Skip to content

Commit aa07b0a

Browse files
authored
Merge branch 'develop' into feature/LS24002651/implements-douxx
2 parents f70928f + d19bac4 commit aa07b0a

File tree

11 files changed

+222
-6
lines changed

11 files changed

+222
-6
lines changed

rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/compile_time_interpreter.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,12 @@ open class BaseCompileTimeInterpreter(
154154
private fun findSize(statements: List<RpgParser.StatementContext>, declName: String, conf: ToAstConfiguration, innerBlock: Boolean = true): Int? {
155155
statements.forEach {
156156
when {
157+
it.fspec_fixed() != null -> {
158+
val size = it.fspec_fixed().runParserRuleContext(conf) { context ->
159+
kotlin.runCatching { context.toAst(conf).let { fileDefinition -> fileDefinition.toDataDefinitions() } }.getOrNull()
160+
}?.find { dataDefinition -> dataDefinition.name.equals(declName, ignoreCase = true) }?.elementSize()
161+
if (size != null) return size
162+
}
157163
it.dspec() != null -> {
158164
val name = it.dspec().ds_name()?.text ?: it.dspec().dspecConstant().ds_name()?.text
159165
if (declName.equals(name, ignoreCase = true)) {
@@ -234,6 +240,12 @@ open class BaseCompileTimeInterpreter(
234240
statements
235241
.forEach { it ->
236242
when {
243+
it.fspec_fixed() != null -> {
244+
val type = it.fspec_fixed().runParserRuleContext(conf) { context ->
245+
kotlin.runCatching { context.toAst(conf).let { fileDefinition -> fileDefinition.toDataDefinitions() } }.getOrNull()
246+
}?.find { dataDefinition -> dataDefinition.name.equals(declName, ignoreCase = true) }?.type
247+
if (type != null) return type
248+
}
237249
it.dcl_ds() != null -> {
238250
val type = it.dcl_ds().parm_fixed().find { it.ds_name().text.equals(declName, ignoreCase = true) }?.findType(conf)
239251
if (type != null) return type

rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/serialization.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ private val modules = SerializersModule {
101101
subclass(SubStmt::class)
102102
subclass(SubstStmt::class)
103103
subclass(TagStmt::class)
104+
subclass(TestnStmt::class)
104105
subclass(TimeStmt::class)
105106
subclass(UnlockStmt::class)
106107
subclass(UpdateStmt::class)

rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/statements.kt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2386,4 +2386,47 @@ data class BitOffStmt(
23862386
) : Statement(position), StatementThatCanDefineData, MockStatement {
23872387
override fun execute(interpreter: InterpreterCore) { }
23882388
override fun dataDefinition(): List<InStatementDataDefinition> = dataDefinition?.let { listOf(it) } ?: emptyList()
2389+
}
2390+
2391+
@Serializable
2392+
data class TestnStmt(
2393+
var expression: Expression,
2394+
@Derived val dataDefinition: InStatementDataDefinition? = null,
2395+
val rightIndicators: WithRightIndicators,
2396+
override val position: Position? = null
2397+
2398+
) :
2399+
Statement(position), StatementThatCanDefineData, WithRightIndicators by rightIndicators {
2400+
override val loggableEntityName: String
2401+
get() = "TESTN"
2402+
2403+
override fun dataDefinition(): List<InStatementDataDefinition> {
2404+
if (dataDefinition != null) {
2405+
return listOf(dataDefinition)
2406+
}
2407+
return emptyList()
2408+
}
2409+
2410+
override fun execute(interpreter: InterpreterCore) {
2411+
if (expression.type() !is StringType) {
2412+
throw UnsupportedOperationException("The result expression is not a String type")
2413+
}
2414+
val valStr = (interpreter.eval(expression) as StringValue).value
2415+
val regex = "-?[0-9]+(\\.[0-9]+)?".toRegex()
2416+
val isNumeric = valStr.matches(regex)
2417+
2418+
if (isNumeric) {
2419+
interpreter.setIndicators(this, BooleanValue.TRUE, BooleanValue.FALSE, BooleanValue.FALSE)
2420+
} else {
2421+
if (valStr.trim().isEmpty()) {
2422+
interpreter.setIndicators(this, BooleanValue.FALSE, BooleanValue.FALSE, BooleanValue.TRUE)
2423+
} else {
2424+
if (valStr.startsWith(" ")) {
2425+
interpreter.setIndicators(this, BooleanValue.FALSE, BooleanValue.TRUE, BooleanValue.FALSE)
2426+
} else {
2427+
interpreter.setIndicators(this, BooleanValue.FALSE, BooleanValue.FALSE, BooleanValue.FALSE)
2428+
}
2429+
}
2430+
}
2431+
}
23892432
}

rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/parsetreetoast/misc.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ private fun MutableMap<String, DataDefinition>.addIfNotPresent(dataDefinition: D
155155
dataDefinition.error("${dataDefinition.name} has been defined twice")
156156
}
157157

158-
private fun FileDefinition.toDataDefinitions(): List<DataDefinition> {
158+
internal fun FileDefinition.toDataDefinitions(): List<DataDefinition> {
159159
val dataDefinitions = mutableListOf<DataDefinition>()
160160
val reloadConfig = MainExecutionContext.getConfiguration()
161161
.reloadConfig ?: error("Not found metadata for $this because missing property reloadConfig in configuration")
@@ -934,6 +934,9 @@ internal fun Cspec_fixed_standardContext.toAst(conf: ToAstConfiguration = ToAstC
934934
this.csBITOFF() != null -> this.csBITOFF()
935935
.let { it.cspec_fixed_standard_parts().validate(stmt = it.toAst(conf), conf = conf) }
936936

937+
this.csTESTN() != null -> this.csTESTN()
938+
.let { it.cspec_fixed_standard_parts().validate(stmt = it.toAst(conf), conf = conf) }
939+
937940
else -> todo(conf = conf)
938941
}
939942
}
@@ -2018,6 +2021,14 @@ internal fun CsUNLOCKContext.toAst(conf: ToAstConfiguration = ToAstConfiguration
20182021
return UnlockStmt(position)
20192022
}
20202023

2024+
internal fun CsTESTNContext.toAst(conf: ToAstConfiguration = ToAstConfiguration()): TestnStmt {
2025+
val position = toPosition(conf.considerPosition)
2026+
val resultExpression = this.cspec_fixed_standard_parts().resultExpression(conf) as AssignableExpression
2027+
val result = this.cspec_fixed_standard_parts().result.text
2028+
val dataDefinition = this.cspec_fixed_standard_parts().toDataDefinition(result, position, conf)
2029+
return TestnStmt(resultExpression, dataDefinition, cspec_fixed_standard_parts().rightIndicators(), position)
2030+
}
2031+
20212032
// TODO
20222033
internal fun CsFEODContext.toAst(conf: ToAstConfiguration = ToAstConfiguration()): Statement {
20232034
val position = toPosition(conf.considerPosition)

rpgJavaInterpreter-core/src/test/kotlin/com/smeup/rpgparser/smeup/MULANGT02ConstAndDSpecTest.kt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,31 @@
11
package com.smeup.rpgparser.smeup
22

3+
import com.smeup.rpgparser.db.utilities.DBServer
4+
import com.smeup.rpgparser.smeup.dbmock.MULANGTLDbMock
35
import org.junit.Test
6+
import kotlin.test.AfterTest
7+
import kotlin.test.BeforeTest
48
import kotlin.test.assertEquals
59

610
open class MULANGT02ConstAndDSpecTest : MULANGTTest() {
11+
@BeforeTest
12+
override fun setUp() {
13+
if (!DBServer.isRunning()) {
14+
DBServer.startDB()
15+
}
16+
17+
super.setUp()
18+
}
19+
20+
@AfterTest()
21+
override fun tearDown() {
22+
/*
23+
* This causes `connection exception: connection failure: java.net.SocketException: Pipe interrotta (Write failed)`
24+
* during `./gradle check`
25+
*/
26+
// DBServer.stopDB()
27+
}
28+
729
/**
830
* /COPY recognized in CTDATA
931
* @see #268
@@ -158,4 +180,21 @@ open class MULANGT02ConstAndDSpecTest : MULANGTTest() {
158180
val expected = listOf("A50_A14(A) A50_B14(ABCDEFGHIJ)")
159181
assertEquals(expected, "smeup/MU025014".outputOf(configuration = smeupConfig))
160182
}
183+
184+
/**
185+
* Data definition not resolved for a specification that uses `LIKE` to a field from file. In addition,
186+
* there is a DS with an `%ELEM()` built-in function to that field.
187+
* @see #LS24002645
188+
*/
189+
@Test
190+
fun executeMUDRNRAPU00101() {
191+
MULANGTLDbMock().use {
192+
com.smeup.rpgparser.db.utilities.execute(listOf(it.createTable(), it.populateTable()))
193+
val expected = listOf("HELLO THERE")
194+
assertEquals(
195+
expected = expected,
196+
"smeup/MUDRNRAPU00101".outputOf(configuration = smeupConfig)
197+
)
198+
}
199+
}
161200
}

rpgJavaInterpreter-core/src/test/kotlin/com/smeup/rpgparser/smeup/MULANGT10BaseCodopTest.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,13 @@ open class MULANGT10BaseCodopTest : MULANGTTest() {
103103
val expected = listOf("CALL(mod:inp )")
104104
assertEquals(expected, "smeup/MU106011".outputOf())
105105
}
106+
107+
/**
108+
* TESTN
109+
*/
110+
@Test
111+
fun executeMU102501() {
112+
val expected = listOf("51=1,52=0,53=0")
113+
assertEquals(expected, "smeup/MU102501".outputOf())
114+
}
106115
}

rpgJavaInterpreter-core/src/test/kotlin/com/smeup/rpgparser/smeup/MULANGTTest.kt

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ package com.smeup.rpgparser.smeup
33
import com.smeup.dbnative.DBNativeAccessConfig
44
import com.smeup.rpgparser.AbstractTest
55
import com.smeup.rpgparser.execution.Configuration
6+
import com.smeup.rpgparser.execution.ConnectionConfig
67
import com.smeup.rpgparser.execution.ReloadConfig
78
import com.smeup.rpgparser.execution.SimpleReloadConfig
9+
import kotlin.test.AfterTest
810
import kotlin.test.BeforeTest
911

1012
/**
@@ -14,21 +16,38 @@ import kotlin.test.BeforeTest
1416
* @see MULANGT60VideoTestCompiled see above
1517
*/
1618
abstract class MULANGTTest : AbstractTest() {
17-
1819
/**
1920
* The configuration used to execute some kind of tests, for example all test required files.
2021
* The required files are placed in the resources/smeup/metadata folder.
2122
*/
2223
lateinit var smeupConfig: Configuration
2324

2425
@BeforeTest
25-
fun setUp() {
26+
open fun setUp() {
2627
smeupConfig = Configuration()
2728
val path = javaClass.getResource("/smeup/metadata")!!.path
28-
val reloadConfig = SimpleReloadConfig(metadataPath = path, connectionConfigs = listOf())
29+
val connectionConfigs = listOf(ConnectionConfig(
30+
fileName = "*",
31+
url = "jdbc:hsqldb:hsql://127.0.0.1:9001/mainDb",
32+
user = "SA",
33+
password = "",
34+
driver = "org.hsqldb.jdbc.JDBCDriver"
35+
))
36+
val reloadConfig = SimpleReloadConfig(metadataPath = path, connectionConfigs = connectionConfigs)
2937
smeupConfig.reloadConfig = ReloadConfig(
30-
nativeAccessConfig = DBNativeAccessConfig(emptyList()),
38+
nativeAccessConfig = DBNativeAccessConfig(connectionConfigs.map {
39+
com.smeup.dbnative.ConnectionConfig(
40+
fileName = it.fileName,
41+
url = it.url,
42+
user = it.user,
43+
password = it.password,
44+
driver = it.driver,
45+
impl = it.impl
46+
)
47+
}),
3148
metadataProducer = { dbFile: String -> reloadConfig.getMetadata(dbFile = dbFile) })
32-
smeupConfig.options.debuggingInformation = true
3349
}
50+
51+
@AfterTest()
52+
open fun tearDown() {}
3453
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.smeup.rpgparser.smeup.dbmock
2+
3+
import com.smeup.rpgparser.interpreter.DbField
4+
import com.smeup.rpgparser.interpreter.NumberType
5+
import com.smeup.rpgparser.interpreter.StringType
6+
import kotlin.test.todo
7+
8+
interface DbMock : AutoCloseable {
9+
fun createTable(): String
10+
fun dropTable(): String
11+
fun populateTable(): String
12+
13+
override fun close() {
14+
dropTable()
15+
}
16+
17+
fun buildDbColumnsFromDbFields(fields: List<DbField>): String {
18+
return fields.mapIndexed { i, it ->
19+
when {
20+
it.type is StringType -> "${it.fieldName} VARCHAR(${it.type.size}) DEFAULT '' NOT NULL".plus(if (fields.lastIndex != i) ",\n" else "\n")
21+
it.type is NumberType -> {
22+
var columnDeclaration = it.fieldName
23+
if ((it.type as NumberType).decimal) {
24+
columnDeclaration += " DECIMAL(${(it.type as NumberType).entireDigits}, ${(it.type as NumberType).decimalDigits}) DEFAULT 0.0"
25+
} else {
26+
columnDeclaration += " BIGINT DEFAULT 0"
27+
}
28+
29+
columnDeclaration += " NOT NULL".plus(if (fields.lastIndex != i) ",\n" else "\n")
30+
31+
columnDeclaration
32+
}
33+
else -> todo { "Implements ${it.type} for 'buildDbColumnsFromDbFields'." }
34+
}
35+
}
36+
.joinToString("")
37+
}
38+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.smeup.rpgparser.smeup.dbmock
2+
3+
import com.smeup.rpgparser.interpreter.FileMetadata
4+
import java.io.File
5+
6+
class MULANGTLDbMock : DbMock {
7+
val metadata = FileMetadata.createInstance(File("src/test/resources/smeup/metadata/MULANGTL.json").inputStream())
8+
9+
override fun createTable(): String = """
10+
CREATE TABLE IF NOT EXISTS ${metadata.tableName} (
11+
${this.buildDbColumnsFromDbFields(metadata.fields)})
12+
"""
13+
.trimIndent()
14+
override fun dropTable(): String = "DROP TABLE IF EXISTS ${metadata.tableName}"
15+
override fun populateTable(): String {
16+
return """
17+
INSERT INTO ${metadata.tableName}(MLSYST, MLLIBR, MLFILE, MLTIPO, MLPROG, MLPSEZ, MLPPAS, MLPDES, MLSQIN, MLSQFI, MLAAAT, MLAAVA, MLNNAT, MLNNVA, MLINDI, MLTEES, MLUSES, MLDTES, MLORES, MLASLA, MLASNR, MLLIBE)
18+
VALUES ('FOO', 'FOO', 'FOO', 'FOO', 'FOO', 'FOO', 'FOO', 'FOO', 'FOO', 'FOO', 'FOO', 'FOO', 1.0, 1.0, 'FOO', 1, 'FOO', 1, 1, 'FOO', 1, 'FOO')
19+
"""
20+
.trimIndent()
21+
}
22+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
D £DBG_Str S 50 VARYING
2+
C MOVEL '0399999' AAA003 3
3+
C TESTN AAA003 515253
4+
C EVAL £DBG_Str='51='+%CHAR(*IN51)+
5+
C ',52='+%CHAR(*IN52)+
6+
C ',53='+%CHAR(*IN53)
7+
* 51=1,52=0,53=0
8+
C £DBG_Str DSPLY
9+
*
10+
C SETON LR

0 commit comments

Comments
 (0)