Skip to content

Commit

Permalink
Merge pull request #546 from smeup/feature/exfmt
Browse files Browse the repository at this point in the history
Feature/exfmt
  • Loading branch information
lanarimarco authored Jun 17, 2024
2 parents ddb39dd + cde8da7 commit 8429ca2
Show file tree
Hide file tree
Showing 32 changed files with 249 additions and 87 deletions.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.smeup.dspfparser.domain

import com.smeup.dspfparser.linesclassifier.DSPF
import com.smeup.dspfparser.linesclassifier.DSPFSpecifications
import com.smeup.dspfparser.linesprocessor.LinesProcessor
import java.io.BufferedReader
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.smeup.dspfparser.domain
package com.smeup.dspfparser.linesclassifier

import kotlinx.serialization.Serializable

/**
* Models a display file as a whole logical unit.
*/
interface DSPF {
@Serializable
sealed interface DSPF {
val records: List<DSPFRecord>

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.smeup.dspfparser.domain
package com.smeup.dspfparser.linesclassifier

import kotlinx.serialization.Serializable

/**
* Models a [DSPFRecord] field (that can be seen as a variable, with its record as scope).
*/
interface DSPFField {
@Serializable
sealed interface DSPFField {
val name: String
val value: DSPFValue<String>
var value: DSPFValue?
val isNumeric: Boolean
val length: Int?
val precision: Int?
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package com.smeup.dspfparser.linesclassifier

import com.smeup.dspfparser.domain.DSPFField
import com.smeup.dspfparser.domain.DSPFFieldType
import com.smeup.dspfparser.linesprocessor.DSPFLine
import com.smeup.dspfparser.positionals.FieldType
import kotlinx.serialization.Serializable

@Serializable
internal data class DSPFFieldSpecifications private constructor(
override val name: String,
override val value: DSPFFieldValue<String>,
override var value: DSPFValue? = null,
override val isNumeric: Boolean,
override val length: Int? = null,
override val precision: Int? = null,
Expand All @@ -22,11 +20,10 @@ internal data class DSPFFieldSpecifications private constructor(
companion object {
fun fromLine(declaration: DSPFLine): DSPFFieldSpecifications {
val isNumeric = declaration.decimalsPositions != null
val initialValue = if (isNumeric) "0" else ""

return DSPFFieldSpecifications(
name = declaration.fieldName,
value = DSPFFieldValue(initialValue),
value = null,
isNumeric = isNumeric,
length = declaration.length,
precision = declaration.decimalsPositions,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.smeup.dspfparser.domain
package com.smeup.dspfparser.linesclassifier

/**
* All possible values of a field type (what it can be used for).
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.smeup.dspfparser.linesclassifier

import kotlinx.serialization.Serializable

/**
* Represents a display file record.
*/
@Serializable
sealed interface DSPFRecord {
val name: String
val fields: List<DSPFField>
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.smeup.dspfparser.linesclassifier

import com.smeup.dspfparser.domain.DSPFRecord
import com.smeup.dspfparser.linesprocessor.DSPFLine
import kotlinx.serialization.Serializable

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.smeup.dspfparser.linesclassifier

import com.smeup.dspfparser.domain.DSPF
import com.smeup.dspfparser.linesprocessor.DSPFLine
import kotlinx.serialization.Serializable

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.smeup.dspfparser.linesclassifier

/**
* Value assigned to a [DSPFField] object.
*/
interface DSPFValue
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.smeup.dspfparser.linesclassifier

import com.smeup.dspfparser.domain.DSPFFieldType
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.smeup.dspfparser.serialization

import com.smeup.dspfparser.linesclassifier.DSPFSpecifications
import com.smeup.dspfparser.linesclassifier.DSPF
import com.smeup.dspfparser.linesclassifier.DSPFSpecificationsLoader
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
Expand All @@ -13,9 +13,9 @@ internal class SerializationDeserializationTest : DSPFSpecificationsLoader("./sr

@Test
fun serialize() {
val initial = this.specifications
val initial = this.specifications as DSPF
val string = json.encodeToString(initial)
val deserialized = json.decodeFromString<DSPFSpecifications>(string)
val deserialized = json.decodeFromString<DSPF>(string)
assertEquals(initial, deserialized)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package com.smeup.rpgparser.execution

import com.smeup.dbnative.DBNativeAccessConfig
import com.smeup.dspfparser.linesclassifier.DSPF
import com.smeup.dspfparser.linesclassifier.DSPFField
import com.smeup.rpgparser.interpreter.*
import com.smeup.rpgparser.parsing.ast.Api
import com.smeup.rpgparser.parsing.ast.ApiId
Expand Down Expand Up @@ -73,7 +75,8 @@ data class ReloadConfig(
* @param metadataProducer Produce metadata for a displayFile
* */
data class DspfConfig(
val metadataProducer: (displayFile: String) -> FileMetadata
val metadataProducer: (displayFile: String) -> FileMetadata,
val dspfProducer: (displayFile: String) -> DSPF
)

/**
Expand Down Expand Up @@ -176,6 +179,13 @@ data class JarikoCallback(
* */
var onExitCopy: (copyId: CopyId) -> Unit = { },

/**
* It is invoked on EXFMT execution.
*/
var onExfmt: (fields: List<DSPFField>, runtimeInterpreterSnapshot: RuntimeInterpreterSnapshot) -> OnExfmtResponse? = {
_, _ -> null
},

/**
* It is invoked before statement execution.
* **This callback will be called only if [Options.debuggingInformation] is set to true**.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.smeup.rpgparser.execution

import com.smeup.dspfparser.linesclassifier.DSPF
import com.smeup.dspfparser.domain.DisplayFileParser
import com.smeup.rpgparser.interpreter.FileMetadata
import com.smeup.rpgparser.interpreter.getDbFields
Expand All @@ -13,6 +14,15 @@ import java.io.File
@Serializable
internal data class SimpleDspfConfig(var displayFilePath: String? = null) {

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

return videoFile.bufferedReader().use { reader ->
DisplayFileParser.parse(reader)
}
}

internal fun getMetadata(displayFile: String): FileMetadata {
val videoFile = File(displayFilePath, "$displayFile.dspf")
require(videoFile.exists()) { "$videoFile doesn't exist" }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.smeup.rpgparser.interpreter

/**
* Represents the return state by an EXFMT statement
*/
data class OnExfmtResponse(
val runtimeInterpreterSnapshot: RuntimeInterpreterSnapshot,
val values: Map<String, Value>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.smeup.rpgparser.interpreter

/**
* An instance of this object will be used by the client to inform jariko about
* interpreter state just before the EXFMT statement execution.
*/
class RuntimeInterpreterSnapshot
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package com.smeup.rpgparser.interpreter

import com.smeup.dbnative.file.DBFile
import com.smeup.dbnative.file.Record
import com.smeup.dspfparser.linesclassifier.DSPF
import com.smeup.rpgparser.execution.ErrorEvent
import com.smeup.rpgparser.execution.ErrorEventSource
import com.smeup.rpgparser.execution.MainExecutionContext
Expand Down Expand Up @@ -69,6 +70,7 @@ class InterpreterStatus(
var lastFound = false
var lastDBFile: DBFile? = null
val dbFileMap = DBFileMap()
var displayFiles: Map<String, DSPF>? = null
fun indicator(key: IndicatorKey) = indicators[key] ?: BooleanValue.FALSE
fun getVar(abstractDataDefinition: AbstractDataDefinition): Value {
val tmpValue = symbolTable[abstractDataDefinition]
Expand Down Expand Up @@ -384,6 +386,7 @@ open class InternalInterpreter(
kotlin.runCatching {
configureLogHandlers()

this.status.displayFiles = compilationUnit.displayFiles
status.params = initialValues.size
initialize(compilationUnit, caseInsensitiveMap(initialValues), reinitialization)
execINZSR(compilationUnit)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.smeup.rpgparser.interpreter

import com.smeup.dspfparser.linesclassifier.DSPFValue
import com.smeup.rpgparser.parsing.ast.CompilationUnit
import com.smeup.rpgparser.parsing.parsetreetoast.DateFormat
import com.smeup.rpgparser.parsing.parsetreetoast.RpgType
Expand All @@ -34,7 +35,7 @@ const val PAD_STRING = PAD_CHAR.toString()

val DEFAULT_CHARSET = Charset.forName("Cp037")

interface Value : Comparable<Value> {
interface Value : Comparable<Value>, DSPFValue {
fun asInt(): IntValue = throw UnsupportedOperationException("${this.javaClass.simpleName} cannot be seen as an Int")
fun asDecimal(): DecimalValue = throw UnsupportedOperationException("${this.javaClass.simpleName} cannot be seen as an Decimal")
fun asString(): StringValue
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.smeup.rpgparser.interpreter

import com.smeup.dspfparser.domain.DSPF
import com.smeup.dspfparser.linesclassifier.DSPF
import com.smeup.dspfparser.linesclassifier.DSPFField
import com.smeup.rpgparser.execution.MainExecutionContext
import com.smeup.rpgparser.parsing.parsetreetoast.RpgType

internal fun DSPF.getDbFields(): List<DbField> {
Expand Down Expand Up @@ -30,4 +32,55 @@ internal fun DSPF.getDbFields(): List<DbField> {
}

return fields
}

internal fun List<FileDefinition>.toDSPF(): Map<String, DSPF>? {
val displayFiles = mutableMapOf<String, DSPF>()
val dspfConfig = MainExecutionContext.getConfiguration().dspfConfig

this.filter { it.fileType == FileType.VIDEO }.forEach {
if (dspfConfig != null) {
displayFiles[it.name] = dspfConfig.dspfProducer.invoke(it.name)
}
// if dspfConfig == null then display file fields have already been loaded into
// data definitions from .json metadata (reloadConfig is used as fallback)
}

// should I return null or an empty map?
return if (dspfConfig != null) displayFiles else null
}

/**
* Fields of specified record will be returned and updated with the latest
* value of the corrisponding data definition just before EXFMT starts.
*/
internal fun copyDataDefinitionsIntoRecordFields(interpreter: InterpreterCore, recordName: String): List<DSPFField> {
val fields = mutableListOf<DSPFField>()
val symbolTable = interpreter.getGlobalSymbolTable()
val displayFiles = interpreter.getStatus().displayFiles

displayFiles?.forEach { dspf ->
val record = dspf.value.records.first { it.name == recordName }
record.fields.forEach { field ->
field.value = symbolTable[field.name]
fields.add(field)
}
}

return fields
}

/**
* Fields edited during EXFMT will be available just after returning from it as response
* and used to update corresponding data definitions.
*/
internal fun copyRecordFieldsIntoDataDefinitions(interpreter: InterpreterCore, response: OnExfmtResponse) {
val symbolTable = interpreter.getGlobalSymbolTable()

response.values.forEach { field ->
val dataDefinition = symbolTable.dataDefinitionByName(field.key)
dataDefinition ?: error("Data definition ${field.key} does not exists in symbol table")

interpreter.assign(dataDefinition, field.value)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.smeup.rpgparser.parsing.ast

import com.smeup.dspfparser.linesclassifier.DSPF
import com.smeup.rpgparser.interpreter.AbstractDataDefinition
import com.smeup.rpgparser.interpreter.DataDefinition
import com.smeup.rpgparser.interpreter.FileDefinition
Expand Down Expand Up @@ -47,7 +48,8 @@ data class CompilationUnit(
// - if 'CompilationUnit' is an 'RpgFunction', this list contains procedure parameters (if any)
val proceduresParamsDataDefinitions: List<DataDefinition>? = null,
val source: String? = null,
val copyBlocks: CopyBlocks? = null
val copyBlocks: CopyBlocks? = null,
val displayFiles: Map<String, DSPF>? = null
) : Node(position) {

var timeouts = emptyList<MuteTimeoutAnnotation>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2382,12 +2382,20 @@ data class ResetStmt(

@Serializable
data class ExfmtStmt(
override val position: Position? = null
) : Statement(position), MockStatement {
override val position: Position? = null,
val factor2: String
) : Statement(position) {
override val loggableEntityName: String
get() = "EXFMT"

override fun execute(interpreter: InterpreterCore) {}
override fun execute(interpreter: InterpreterCore) {
val jarikoCallback = MainExecutionContext.getConfiguration().jarikoCallback
val fields = copyDataDefinitionsIntoRecordFields(interpreter, factor2)
val snapshot = RuntimeInterpreterSnapshot()
val response = jarikoCallback.onExfmt(fields, snapshot)
response ?: error("RuntimeInterpreterSnapshot is not yet handled")
copyRecordFieldsIntoDataDefinitions(interpreter, response)
}
}

@Serializable
Expand Down
Loading

0 comments on commit 8429ca2

Please sign in to comment.