Skip to content

Commit

Permalink
Merge branch 'develop' into bugfix/LS24004491/dim-on-constant
Browse files Browse the repository at this point in the history
  • Loading branch information
lanarimarco authored Oct 17, 2024
2 parents 272fe61 + 0cbb848 commit 03d059f
Show file tree
Hide file tree
Showing 39 changed files with 476 additions and 194 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.smeup.dspfparser.linesclassifier

import kotlinx.serialization.Serializable

@Serializable
data class ConstantField(
val value: ConstantValue?,
override val x: Int?,
override val y: Int?
) : DSPFField
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.smeup.dspfparser.linesclassifier

import kotlinx.serialization.Serializable
import kotlinx.serialization.modules.SerializersModule

/**
* Unlike variable fields, a constant field should be initialized with its value in the
* parser phase since it is hardwired into the display file.
* This [DSPFValue] implementation allows the value to be passed into Jariko.
* Importing Jariko's [DSPFValue] implementations is not a good choice because Jariko depends on this
* module and not the vice versa.
* To make serialization / deserialization work proper declarations in [SerializersModule] is needed
* because [DSPFValue] is not sealed (its implementers are in another package,
* in rpgJavaInterpreter-core module).
*/
@Serializable
data class ConstantValue(val value: String) : DSPFValue
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,16 @@ sealed interface DSPF {
fun getRecord(name: String): DSPFRecord

/**
* Retrieve a list of [DSPFField] given its record's name.
* Retrieve a list of [MutableField] given its record's name.
* @param name the name of the record
* @return [List]<[DSPFField]>
* @return [List]<[MutableField]>
*/
fun getFieldsFromRecord(name: String): List<DSPFField>
fun getMutableFieldsFromRecord(name: String): List<MutableField>

/**
* Retrieve a list of [ConstantField] given its record's name.
* @param name the name of the record
* @return [List]<[ConstantField]>
*/
fun getConstantFieldsFromRecord(name: String): List<ConstantField>
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,10 @@ 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).
* Models a [DSPFRecord] field, that can be seen as a variable or a constant, with its record as scope.
*/
@Serializable
sealed interface DSPFField {
val name: String
var value: DSPFValue?
val isNumeric: Boolean
val length: Int?
val precision: Int?
val type: DSPFFieldType
val x: Int?
val y: Int?
val hasError: Boolean
}
Original file line number Diff line number Diff line change
@@ -1,36 +1,38 @@
package com.smeup.dspfparser.linesclassifier

import com.smeup.dspfparser.linesprocessor.DSPFLine
import com.smeup.dspfparser.linesprocessor.LineType
import com.smeup.dspfparser.positionals.FieldType
import kotlinx.serialization.Serializable

@Serializable
internal data class DSPFFieldSpecifications private constructor(
override val name: String,
override var value: DSPFValue? = null,
override val isNumeric: Boolean,
override val length: Int? = null,
override val precision: Int? = null,
override val type: DSPFFieldType,
override val x: Int?,
override val y: Int?,
override var hasError: Boolean = false
override val y: Int?
) : DSPFField {

companion object {
fun fromLine(declaration: DSPFLine): DSPFFieldSpecifications {
val isNumeric = declaration.decimalsPositions != null
fun fromLine(declaration: DSPFLine): DSPFField {
if (declaration.type == LineType.CONSTANT) {
return ConstantField(
value = ConstantValue(declaration.keywords!!.getConstantValue()),
x = declaration.x,
y = declaration.y
)
} else {
val isNumeric = declaration.decimalsPositions != null

return DSPFFieldSpecifications(
name = declaration.fieldName,
value = null,
isNumeric = isNumeric,
length = declaration.length,
precision = declaration.decimalsPositions,
type = this.getType(declaration),
x = declaration.x,
y = declaration.y
)
return MutableField(
name = declaration.fieldName,
value = null,
isNumeric = isNumeric,
length = declaration.length,
precision = declaration.decimalsPositions,
type = this.getType(declaration),
x = declaration.x,
y = declaration.y
)
}
}

private fun getType(declaration: DSPFLine): DSPFFieldType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ import kotlinx.serialization.Serializable
@Serializable
sealed interface DSPFRecord {
val name: String
val fields: List<DSPFField>
val mutables: List<MutableField>
val constants: List<ConstantField>
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import kotlinx.serialization.Serializable
internal data class DSPFRecordSpecifications private constructor(
override val name: String
) : DSPFRecord {
override val fields: MutableList<DSPFFieldSpecifications> = mutableListOf()
override val mutables: MutableList<MutableField> = mutableListOf()
override val constants: MutableList<ConstantField> = mutableListOf()

companion object {
fun fromLine(declaration: DSPFLine): DSPFRecordSpecifications {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.smeup.dspfparser.linesclassifier

import com.smeup.dspfparser.linesprocessor.DSPFLine
import com.smeup.dspfparser.linesprocessor.LineType
import kotlinx.serialization.Serializable

@Serializable
Expand All @@ -19,22 +20,24 @@ internal data class DSPFSpecifications(
return this.records.first { it.name == name.uppercase() }
}

override fun getFieldsFromRecord(name: String): MutableList<DSPFFieldSpecifications> {
return this.records.first { it.name == name.uppercase() }.fields
override fun getMutableFieldsFromRecord(name: String): MutableList<MutableField> {
return this.records.first { it.name == name.uppercase() }.mutables
}

override fun getConstantFieldsFromRecord(name: String): List<ConstantField> {
return this.records.first { it.name == name.uppercase() }.constants
}
}

private enum class CurrentContext {
FILE,
RECORD,
FIELD,
FIELD
}

private class DSPFSpecificationsFactory {
private var context: CurrentContext = CurrentContext.FILE
private var isLineNone: Boolean = false
private var isLineRecord: Boolean = false
private var isLineField: Boolean = false
private var currentLineType: LineType = LineType.NULL
private var result: DSPFSpecifications = DSPFSpecifications()

constructor(lines: MutableList<DSPFLine>) {
Expand All @@ -46,35 +49,50 @@ private class DSPFSpecificationsFactory {
}

private fun tryInsertNewRecord(line: DSPFLine) {
if (this.isLineRecord) {
if (this.currentLineType == LineType.RECORD) {
this.result.records.add(DSPFRecordSpecifications.fromLine(line))
this.context = CurrentContext.RECORD
}
}

private fun tryInsertNewFieldOnRecordContext(line: DSPFLine) {
if (this.context == CurrentContext.RECORD && this.isLineField) {
this.result.records.last().fields.add(DSPFFieldSpecifications.fromLine(line))
if (this.context == CurrentContext.RECORD && this.currentLineType == LineType.FIELD) {
this.result.records.last().mutables.add(DSPFFieldSpecifications.fromLine(line) as MutableField)
this.context = CurrentContext.FIELD
}
}

private fun tryInsertNewFieldOnFieldContext(line: DSPFLine) {
if (this.context == CurrentContext.FIELD && this.isLineField) {
this.result.records.last().fields.add(DSPFFieldSpecifications.fromLine(line))
if (this.context == CurrentContext.FIELD && this.currentLineType == LineType.FIELD) {
this.result.records.last().mutables.add(DSPFFieldSpecifications.fromLine(line) as MutableField)
}
}

private fun tryInsertNewConstantOnFieldContext(line: DSPFLine) {
if (this.context == CurrentContext.FIELD && this.currentLineType == LineType.CONSTANT) {
this.result.records.last().constants.add(DSPFFieldSpecifications.fromLine(line) as ConstantField)
}
}

private fun tryInsertNewConstantOnRecordContext(line: DSPFLine) {
if (this.context == CurrentContext.RECORD && this.currentLineType == LineType.CONSTANT) {
this.result.records.last().constants.add(DSPFFieldSpecifications.fromLine(line) as ConstantField)
this.context = CurrentContext.FIELD
}
}

private fun updateResultWith(lines: MutableList<DSPFLine>) {
lines.forEach {
this.isLineNone = it.isNone()
this.isLineField = it.isField()
this.isLineRecord = it.isRecord()
this.currentLineType = it.type

// order is important, do not change it
this.tryInsertNewRecord(it)
// try with field context before record context because after matching
// record context, context is switched to field leading to a double match
this.tryInsertNewFieldOnFieldContext(it)
this.tryInsertNewFieldOnRecordContext(it)
this.tryInsertNewConstantOnFieldContext(it)
this.tryInsertNewConstantOnRecordContext(it)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.smeup.dspfparser.linesclassifier

import kotlinx.serialization.Serializable

@Serializable
data class MutableField(
val name: String,
var value: DSPFValue?,
val isNumeric: Boolean,
val length: Int?,
val precision: Int?,
val type: DSPFFieldType,
override val x: Int?,
override val y: Int?
) : DSPFField
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ internal data class DSPFKeyword private constructor(
}

private fun getConstantMessage(text: String): String? {
return Regex("^'[^']*'\$").find(text.trim())?.value?.removeFirst('\'')?.removeLast('\'')
return Regex("^'.*'\$").find(text.trim())?.value?.removeFirst('\'')?.removeLast('\'')
}

private fun getName(text: String): String? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,31 @@ import kotlinx.serialization.Serializable
internal data class DSPFKeywordsGroup private constructor(val group: MutableList<DSPFKeyword> = mutableListOf()) {
companion object {
fun fromString(text: String): DSPFKeywordsGroup {
return DSPFKeywordsGroup(this.getParametrized(text))
val constants = this.getConstant(text)

// no other keywords are allowed than constant ones
// so if constant is not found simply return an empty group
// E.G. keywords like DATSEP(''), SFL, DSPATR(HI), ... are not supported yet
if (constants.isNotEmpty()) return DSPFKeywordsGroup(constants)
return DSPFKeywordsGroup()
}

private fun getParametrized(text: String): MutableList<DSPFKeyword> {
private fun getConstant(text: String): MutableList<DSPFKeyword> {
val group: MutableList<DSPFKeyword> = mutableListOf()
Regex("[a-zA-Z]{1,}\\([^(^)]*\\)").find(text)?.groupValues?.forEach {
Regex("^'.*'\$").find(text)?.groupValues?.forEach {
group.add(DSPFKeyword.fromString(it))
}
return group
}
}

fun areConstant(): Boolean {
return this.group.size == 1 &&
this.group[0].name != null &&
this.group[0].parameters.isEmpty()
}

fun getConstantValue(): String {
return this.group[0].name!!
}
}
Loading

0 comments on commit 03d059f

Please sign in to comment.