Skip to content

Commit

Permalink
Merge pull request #542 from smeup/feature/data_definition_from_dspf
Browse files Browse the repository at this point in the history
Feature/data definition from dspf
  • Loading branch information
lanarimarco authored Jun 10, 2024
2 parents 0dbbe29 + 29409a0 commit 8970cd9
Show file tree
Hide file tree
Showing 23 changed files with 250 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package com.smeup.dspfparser.domain
* Models a display file as a whole logical unit.
*/
interface DSPF {
val name: String?
val records: List<DSPFRecord>

/**
* Retrieve a [DSPFRecord] given its name.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface DSPFField {
val length: Int?
val precision: Int?
val type: DSPFFieldType
val x: Int
val y: Int
val x: Int?
val y: Int?
val hasError: Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ internal data class DSPFFieldSpecifications private constructor(
override val length: Int? = null,
override val precision: Int? = null,
override val type: DSPFFieldType,
override val x: Int,
override val y: Int,
override val x: Int?,
override val y: Int?,
override var hasError: Boolean = false
) : DSPFField {

Expand All @@ -31,8 +31,8 @@ internal data class DSPFFieldSpecifications private constructor(
length = declaration.length,
precision = declaration.decimalsPositions,
type = this.getType(declaration),
x = declaration.x!!,
y = declaration.y!!
x = declaration.x,
y = declaration.y
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,13 @@ import kotlinx.serialization.Serializable

@Serializable
internal data class DSPFSpecifications(
override val name: String?
override val records: MutableList<DSPFRecordSpecifications> = mutableListOf()
) : DSPF {
val records: MutableList<DSPFRecordSpecifications> = mutableListOf()

companion object {
fun fromLines(
lines: MutableList<DSPFLine>,
name: String? = null
lines: MutableList<DSPFLine>
): DSPFSpecifications {
return DSPFSpecificationsFactory(name, lines).create()
return DSPFSpecificationsFactory(lines).create()
}
}

Expand All @@ -39,10 +36,9 @@ private class DSPFSpecificationsFactory {
private var isLineNone: Boolean = false
private var isLineRecord: Boolean = false
private var isLineField: Boolean = false
private var result: DSPFSpecifications
private var result: DSPFSpecifications = DSPFSpecifications()

constructor(name: String?, lines: MutableList<DSPFLine>) {
this.result = DSPFSpecifications(name)
constructor(lines: MutableList<DSPFLine>) {
this.updateResultWith(lines)
}

Expand Down
1 change: 1 addition & 0 deletions rpgJavaInterpreter-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
api project(":kolasu")
api project(":dspfparser")

implementation "org.apache.logging.log4j:log4j-api-kotlin:1.0.0"
implementation "org.apache.logging.log4j:log4j-api:2.23.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,15 @@ data class Configuration(
val memorySliceStorage: IMemorySliceStorage? = null,
var jarikoCallback: JarikoCallback = JarikoCallback(),
var reloadConfig: ReloadConfig? = null,
var dspfConfig: DspfConfig? = null,
val defaultActivationGroupName: String = DEFAULT_ACTIVATION_GROUP_NAME,
var options: Options = Options()
) {
constructor(memorySliceStorage: IMemorySliceStorage?) :
this(memorySliceStorage, JarikoCallback(), null, DEFAULT_ACTIVATION_GROUP_NAME, Options())
this(memorySliceStorage, JarikoCallback(), null, null, DEFAULT_ACTIVATION_GROUP_NAME, Options())

constructor(memorySliceStorage: IMemorySliceStorage?, defaultActivationGroupName: String) :
this(memorySliceStorage, JarikoCallback(), null, defaultActivationGroupName, Options())
this(memorySliceStorage, JarikoCallback(), null, null, defaultActivationGroupName, Options())
}

/**
Expand All @@ -64,6 +65,14 @@ data class ReloadConfig(
val metadataProducer: (dbFile: String) -> FileMetadata
)

/**
* DSPF parser configuration
* @param metadataProducer Produce metadata for a displayFile
* */
data class DspfConfig(
val metadataProducer: (displayFile: String) -> FileMetadata
)

/**
* Options object
* @param muteSupport Used to enable/disable scan execution of mute annotations into rpg sources
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.smeup.rpgparser.execution

import com.smeup.dspfparser.domain.DisplayFileParser
import com.smeup.rpgparser.interpreter.FileMetadata
import com.smeup.rpgparser.interpreter.getDbFields
import kotlinx.serialization.Serializable
import java.io.File

/**
* Helper class used to load dspf configuration from a display file
* @param displayFilePath path where display file is located
* */
@Serializable
internal data class SimpleDspfConfig(var displayFilePath: String? = null) {

internal fun getMetadata(displayFile: String): FileMetadata {
val videoFile = File(displayFilePath, "$displayFile.dspf")
require(videoFile.exists()) { "$videoFile doesn't exist" }

return videoFile.bufferedReader().use { reader ->
val dspf = DisplayFileParser.parse(reader)
val fields = dspf.getDbFields()

FileMetadata(
name = displayFile,
tableName = "",
recordFormat = "",
fields = fields,
accessFields = emptyList()
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.smeup.rpgparser.interpreter

import com.smeup.dspfparser.domain.DSPF
import com.smeup.rpgparser.parsing.parsetreetoast.RpgType

internal fun DSPF.getDbFields(): List<DbField> {
val fields = mutableListOf<DbField>()

records.forEach { record ->
record.fields.forEach { field ->
val type: Type
val rpgType: RpgType
// currently parser can't handle REFFLD, so I created random fallback values
val fallbackLength = 10
val fallbackPrecision = 10

if (field.isNumeric) {
if (field.precision!! > 0) rpgType = RpgType.ZONED
else rpgType = RpgType.INTEGER

type = NumberType(
field.length ?: fallbackLength,
field.precision ?: fallbackPrecision, rpgType
)
} else {
type = StringType.createInstance(field.length ?: fallbackLength)
}
fields.add(DbField(fieldName = field.name, type = type))
}
}

return fields
}
Original file line number Diff line number Diff line change
Expand Up @@ -187,23 +187,47 @@ private fun MutableMap<String, DataDefinition>.addIfNotPresent(dataDefinition: D
}
}

private fun FileDefinition.loadMetadata(): FileMetadata {
return when {
(fileType == FileType.DB) -> {
val reloadConfig = MainExecutionContext.getConfiguration()
.reloadConfig
?: error("Not found metadata for $this because missing property reloadConfig in configuration")

kotlin.runCatching {
reloadConfig.metadataProducer.invoke(name)
}.onFailure { error ->
error("Not found metadata for $this", error)
}.getOrNull() ?: error("Not found metadata for $this")
}
(fileType == FileType.VIDEO) -> {
val dspfConfig = MainExecutionContext.getConfiguration()
.dspfConfig ?: error("Not found metadata for $this because missing property dspfConfig in configuration")

kotlin.runCatching {
dspfConfig.metadataProducer.invoke(name)
}.onFailure { error ->
error("Not found metadata for $this", error)
}.getOrNull() ?: error("Not found metadata for $this")
}
else -> error("Unhandled file type $fileType")
}
}

internal fun FileDefinition.toDataDefinitions(): List<DataDefinition> {
val dataDefinitions = mutableListOf<DataDefinition>()
val reloadConfig = MainExecutionContext.getConfiguration()
.reloadConfig ?: error("Not found metadata for $this because missing property reloadConfig in configuration")
val metadata = kotlin.runCatching {
reloadConfig.metadataProducer.invoke(name)
}.onFailure { error ->
error("Not found metadata for $this", error)
}.getOrNull() ?: error("Not found metadata for $this")
val metadata = loadMetadata()

if (internalFormatName == null) internalFormatName = metadata.recordFormat

dataDefinitions.addAll(
metadata.fields.map { dbField ->
dbField.toDataDefinition(prefix = prefix, position = position).apply {
createDbFieldDataDefinitionRelation(dbField.fieldName, name)
}
}
)

// These are the fields related the record format, these fields will
// be used in assignment operation to lookup for the DataDefinitions related these fields
val fieldsDefinition = dataDefinitions.map {
Expand All @@ -218,8 +242,10 @@ internal fun FileDefinition.toDataDefinitions(): List<DataDefinition> {
position = position,
fields = fieldsDefinition
)

dataDefinitions.add(recordFormatDefinition)
}

return dataDefinitions
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import com.smeup.dbnative.DBNativeAccessConfig
import com.smeup.rpgparser.AbstractTest
import com.smeup.rpgparser.execution.Configuration
import com.smeup.rpgparser.execution.ConnectionConfig
import com.smeup.rpgparser.execution.DspfConfig
import com.smeup.rpgparser.execution.ReloadConfig
import com.smeup.rpgparser.execution.SimpleDspfConfig
import com.smeup.rpgparser.execution.SimpleReloadConfig
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
Expand Down Expand Up @@ -46,6 +48,10 @@ abstract class MULANGTTest : AbstractTest() {
)
}),
metadataProducer = { dbFile: String -> reloadConfig.getMetadata(dbFile = dbFile) })
val dspfConfig = SimpleDspfConfig(displayFilePath = path)
smeupConfig.dspfConfig = DspfConfig { displayFile ->
dspfConfig.getMetadata(displayFile)
}
}

@AfterTest()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,16 @@ fun compileAllMutes(
?: error("resource $dbFile.json not found in $metadataPaths")
}
)

dspfConfig = DspfConfig { displayFile ->
metadataPaths.asSequence()
.map { Path.of(rpgTestSrcDir, it) }
.map { it.resolve("$displayFile.dspf").toFile() }
.firstOrNull { it.exists() }?.let {
SimpleDspfConfig(displayFilePath = it!!.parent).getMetadata(displayFile)
} ?: error("resource $displayFile.dspf not found in $metadataPaths")
}

options = Options(debuggingInformation = true)
jarikoCallback.onError = { error ->
error.sourceReference?.let { sourceReference ->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package com.smeup.rpgparser.video

import com.smeup.dbnative.DBNativeAccessConfig
import com.smeup.rpgparser.AbstractTest
import com.smeup.rpgparser.execution.Configuration
import com.smeup.rpgparser.execution.ReloadConfig
import com.smeup.rpgparser.execution.SimpleReloadConfig
import com.smeup.rpgparser.execution.DspfConfig
import com.smeup.rpgparser.execution.SimpleDspfConfig
import kotlin.test.BeforeTest
import kotlin.test.DefaultAsserter
import kotlin.test.Test
import kotlin.test.assertEquals

Expand All @@ -18,17 +16,14 @@ class VideoInterpeterTest : AbstractTest() {
fun setUp() {
configuration = Configuration()
val path = javaClass.getResource("/video/metadata")!!.path
val reloadConfig = SimpleReloadConfig(metadataPath = path, connectionConfigs = listOf())
configuration.reloadConfig = ReloadConfig(
nativeAccessConfig = DBNativeAccessConfig(emptyList()),
metadataProducer = { dbFile: String -> reloadConfig.getMetadata(dbFile = dbFile) })
val dspfConfig = SimpleDspfConfig(displayFilePath = path)
configuration.dspfConfig = DspfConfig(
metadataProducer = { displayFile: String -> dspfConfig.getMetadata(displayFile = displayFile) }
)
}

@Test
fun executeFILEDEF() {
configuration.jarikoCallback.onExitPgm = { _, symbolTable, _ ->
DefaultAsserter.assertNotNull(message = "field £RASDI should be defined", actual = symbolTable["£RASDI"])
}
val expected = listOf("W\$PERI:12", "£RASDI:HELLO_WORLD")
assertEquals(expected = expected, actual = "video/FILEDEF".outputOf(configuration = configuration))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
A*%%TS SD 20240119 112614 GUAGIA REL-V7R4M0 5770-WDS
A*%%EC
A DSPSIZ(24 80 *DS3)
A REF(*LIBL/DIZ_BR)
A CHGINPDFT(HI CS)
A PRINT
A CA22
A CF02
A R FMT1
A*%%TS SD 20240119 112614 GUAGIA REL-V7R4M0 5770-WDS
A TEXT('Videata Guida')
A CF03
A CF14
A £RASDI 15A O 1 2DSPATR(HI)
A 1 26'** GESTIONE ARTICOLI (Menu) **'
A DSPATR(RI)
A 1 60SYSNAME
A £PDSNP 10A O 1 71
A 2 2DATE
A EDTCDE(Y)
A 2 34'Formato guida'
A DSPATR(HI)
A £PDSJN 10A O 2 60
A £PDSNU 10A O 2 71
A 22 2'F14=Entra nella schermata'
A 23 2'F03=Fine Lavoro'
A 60 W$MESV 76A O 24 2DSPATR(RI)
A W$RISC 8A B 3 72
A 62 DSPATR(RI)
A 62 DSPATR(PC)
Loading

0 comments on commit 8970cd9

Please sign in to comment.