Skip to content

Commit

Permalink
Merged develep
Browse files Browse the repository at this point in the history
  • Loading branch information
davidepalladino-apuliasoft committed Dec 10, 2024
2 parents e1926d5 + 9cf1550 commit e237706
Show file tree
Hide file tree
Showing 12 changed files with 212 additions and 97 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ private fun coerceString(value: StringValue, type: Type): Value {
if (value.isBlank()) {
type.blank()
} else {
DataStructValue(value.value)
DataStructValue(value.value.padEnd(type.elementSize))
}
}
is CharacterType -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -817,9 +817,9 @@ data class SetgtStmt(

@Serializable
data class CheckStmt(
val comparatorString: Expression, // Factor1
val baseString: Expression,
val start: Int = 1,
var comparatorString: Expression, // Factor1
var baseString: Expression,
var startPosition: Expression?,
val wrongCharPosition: AssignableExpression?,
@Derived val dataDefinition: InStatementDataDefinition? = null,
override val position: Position? = null
Expand All @@ -828,9 +828,10 @@ data class CheckStmt(
get() = "CHECK"

override fun execute(interpreter: InterpreterCore) {
val start = startPosition?.let { interpreter.eval(it).asString().value.toInt() } ?: 1
var baseString = interpreter.eval(this.baseString).asString().value
if (this.baseString is DataRefExpr) {
baseString = baseString.padEnd(this.baseString.size())
baseString = baseString.padEnd((this.baseString as DataRefExpr).size())
}
val charSet = interpreter.eval(comparatorString).asString().value
val wrongIndex = wrongCharPosition
Expand All @@ -854,9 +855,9 @@ data class CheckStmt(

@Serializable
data class CheckrStmt(
val comparatorString: Expression, // Factor1
val baseString: Expression,
val start: Int = 1,
var comparatorString: Expression, // Factor1
var baseString: Expression,
var startPosition: Expression?,
val wrongCharPosition: AssignableExpression?,
@Derived val dataDefinition: InStatementDataDefinition? = null,
override val position: Position? = null
Expand All @@ -865,9 +866,10 @@ data class CheckrStmt(
get() = "CHECKR"

override fun execute(interpreter: InterpreterCore) {
val start = startPosition?.let { interpreter.eval(it).asString().value.toInt() } ?: 1
var baseString = interpreter.eval(this.baseString).asString().value
if (this.baseString is DataRefExpr) {
baseString = baseString.padEnd(this.baseString.size())
baseString = baseString.padEnd((this.baseString as DataRefExpr).size())
}
val charSet = interpreter.eval(comparatorString).asString().value
val wrongIndex = wrongCharPosition
Expand Down Expand Up @@ -2351,10 +2353,10 @@ data class LookupStmt(

@Serializable
data class ScanStmt(
val left: Expression,
val leftLength: Int?,
val right: Expression,
val startPosition: Expression?,
var left: Expression,
var leftLengthExpression: Expression?,
var right: Expression,
var startPosition: Expression?,
val target: AssignableExpression?,
val rightIndicators: WithRightIndicators,
@Derived val dataDefinition: InStatementDataDefinition? = null,
Expand All @@ -2364,6 +2366,7 @@ data class ScanStmt(
get() = "SCAN"

override fun execute(interpreter: InterpreterCore) {
val leftLength = leftLengthExpression?.let { interpreter.eval(it).asString().value.toInt() }
val start = startPosition?.let { interpreter.eval(it).asString().value.toInt() } ?: 1

val stringToSearch = interpreter.eval(left).asString().value.substringOfLength(leftLength)
Expand Down Expand Up @@ -2589,10 +2592,10 @@ data class CloseStmt(
*/
@Serializable
data class XlateStmt(
val from: Expression,
val to: Expression,
val string: Expression,
val startPos: Int,
var from: Expression,
var to: Expression,
var string: Expression,
var startPosition: Expression?,
val target: AssignableExpression,
val rightIndicators: WithRightIndicators,
@Derived val dataDefinition: InStatementDataDefinition? = null,
Expand All @@ -2604,7 +2607,7 @@ data class XlateStmt(
override fun execute(interpreter: InterpreterCore) {
val originalChars = interpreter.eval(from).asString().value
val newChars = interpreter.eval(to).asString().value
val start = startPos
val start = startPosition?.let { interpreter.eval(it).asString().value.toInt() } ?: 1
val s = interpreter.eval(string).asString().value
val pair = s.divideAtIndex(start - 1)
var right = pair.second
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1146,7 +1146,7 @@ internal fun RpgParser.Dcl_dsContext.toAst(
knownDataDefinitions: Collection<DataDefinition>,
parentDataDefinitions: List<DataDefinition>?,
fileDefinitions: Map<FileDefinition, List<DataDefinition>>?
): DataDefinition? {
): DataDefinition {
// Using `LIKEDS`
if (this.keyword().any { it.keyword_likeds() != null }) {
val referredDs = this.findDs(knownDataDefinitions, parentDataDefinitions, conf)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import com.smeup.rpgparser.parsing.facade.findAllDescendants
import com.smeup.rpgparser.utils.ComparisonOperator
import com.smeup.rpgparser.utils.asIntOrNull
import com.smeup.rpgparser.utils.isEmptyTrim
import com.smeup.rpgparser.utils.mapNotNullOrError
import com.strumenta.kolasu.mapping.toPosition
import com.strumenta.kolasu.model.Node
import com.strumenta.kolasu.model.Position
Expand Down Expand Up @@ -117,9 +118,19 @@ private fun List<StatementContext?>.getDataDefinition(
/**
* Statements sorting to accommodate processing needs
* Step 1: Move the D specs with like because depending on other D specs definitions
* Step 2: Move statements marked as CONST to the start because they might be used as a dependency
* Step 2: Split statements marked as CONST from the rest
*/
val sortedStatements = this.filterNotNull().moveLikeStatementToTheEnd(conf = conf).moveConstantsToStart()
val (constants, sortedStatements) = this.filterNotNull().moveLikeStatementToTheEnd(conf = conf).splitConstants()

// Define constants
val constantProviders = constants.getValidDataDefinitionHolders(
conf = conf,
knownDataDefinitions = knownDataDefinitions,
fileDefinitions = fileDefinitions,
parentDataDefinitions = parentDataDefinitions,
procedureName = procedureName
)
dataDefinitionProviders.addAll(constantProviders)

// First pass ignore exception and all the know definitions
val firstPassProviders = sortedStatements.mapNotNull {
Expand All @@ -133,34 +144,40 @@ private fun List<StatementContext?>.getDataDefinition(
dataDefinitionProviders.addAll(firstPassProviders)

// Second pass, everything, I mean everything
val secondPassProviders = sortedStatements.mapNotNull {
kotlin.runCatching {
when {
it.dspec() != null -> {
it.dspec()
.toAst(
conf = conf,
knownDataDefinitions = knownDataDefinitions.values.toList(),
parentDataDefinitions = parentDataDefinitions,
fileDefinitions = fileDefinitions,
procedureName = procedureName
)
.updateKnownDataDefinitionsAndGetHolder(knownDataDefinitions)
}
val secondPassProviders = sortedStatements.getValidDataDefinitionHolders(
conf = conf,
knownDataDefinitions = knownDataDefinitions,
fileDefinitions = fileDefinitions,
parentDataDefinitions = parentDataDefinitions,
procedureName = procedureName
)
dataDefinitionProviders.addAll(secondPassProviders)

it.dcl_c() != null -> {
it.dcl_c()
.toAst(conf)
.updateKnownDataDefinitionsAndGetHolder(knownDataDefinitions)
}
return Pair(dataDefinitionProviders, knownDataDefinitions)
}

else -> null
private fun List<StatementContext>.getValidDataDefinitionHolders(
conf: ToAstConfiguration = ToAstConfiguration(),
knownDataDefinitions: KnownDataDefinitionInstance,
fileDefinitions: Map<FileDefinition, List<DataDefinition>>? = null,
parentDataDefinitions: List<DataDefinition>? = null,
procedureName: String? = null
): List<DataDefinitionHolder> {
return this.mapNotNullOrError {
when {
it.dspec() != null -> {
it.dspec().toAst(
conf = conf,
knownDataDefinitions = knownDataDefinitions.values.toList(),
parentDataDefinitions = parentDataDefinitions,
fileDefinitions = fileDefinitions,
procedureName = procedureName
).updateKnownDataDefinitionsAndGetHolder(knownDataDefinitions)
}
}.getOrNull()
it.dcl_c() != null -> it.dcl_c().toAst(conf).updateKnownDataDefinitionsAndGetHolder(knownDataDefinitions)
else -> null
}
}
dataDefinitionProviders.addAll(secondPassProviders)

return Pair(dataDefinitionProviders, knownDataDefinitions)
}

private fun RContext.getDataDefinitions(
Expand All @@ -187,16 +204,16 @@ private fun List<StatementContext>.moveLikeStatementToTheEnd(conf: ToAstConfigur
return otherStatements + likeStatements
}

private fun List<StatementContext>.moveConstantsToStart(): List<StatementContext> {
private fun List<StatementContext>.splitConstants(): Pair<List<StatementContext>, List<StatementContext>> {
val constantStatements = this.filter { it.isConstant() }
val otherStatements = this.filter { !it.isConstant() }

return constantStatements + otherStatements
return Pair(constantStatements, otherStatements)
}

private fun StatementContext.isConstant() = when {
this.dcl_c() != null -> this.dcl_c().keyword_const() != null
this.dspec() != null -> this.dspec().keyword().any { keyword -> keyword.keyword_const() != null }
this.dspec() != null -> this.dspec().keyword().any { keyword -> keyword.keyword_const() != null } || this.dspec().dspecConstant() != null
else -> false
}

Expand Down Expand Up @@ -621,7 +638,7 @@ private fun StatementContext.toDataDefinitionProvider(
knownDataDefinitions = knownDataDefinitions.values,
parentDataDefinitions = parentDataDefinitions,
fileDefinitions = fileDefinitions
)?.updateKnownDataDefinitionsAndGetHolder(knownDataDefinitions)
).updateKnownDataDefinitionsAndGetHolder(knownDataDefinitions)
// these errors can be caught because they don't introduce sneaky errors
} catch (e: CannotRetrieveDataStructureElementSizeException) {
null
Expand Down Expand Up @@ -1447,17 +1464,11 @@ internal fun CsSCANContext.toAst(conf: ToAstConfiguration = ToAstConfiguration()
val rightIndicators = cspec_fixed_standard_parts().rightIndicators()
val target = if (result.text.isNotBlank()) result.toAst(conf) else null

val baseExpression = factor2.factorContent(0).toAst(conf)
val positionExpression =
if (factor2.factorContent().size > 1) {
factor2.factorContent(1).toAst(conf)
} else {
null
}
val (baseExpression, positionExpression) = factor2.toIndexedExpression(conf)

return ScanStmt(
left = compareExpression,
leftLength = compareLength,
leftLengthExpression = compareLength,
right = baseExpression,
startPosition = positionExpression,
target = target,
Expand All @@ -1470,7 +1481,7 @@ internal fun CsSCANContext.toAst(conf: ToAstConfiguration = ToAstConfiguration()
internal fun CsCHECKContext.toAst(conf: ToAstConfiguration): Statement {
val position = toPosition(conf.considerPosition)
val factor1 = this.factor1Context()?.content?.toAst(conf) ?: throw UnsupportedOperationException("CHECK operation requires factor 1: ${this.text} - ${position.atLine()}")
val (expression, startPosition) = this.cspec_fixed_standard_parts().factor2.toIndexedExpression(conf)
val (expression, startExpression) = this.cspec_fixed_standard_parts().factor2.toIndexedExpression(conf)

val result = this.cspec_fixed_standard_parts().result
val dataDefinition = this.cspec_fixed_standard_parts().toDataDefinition(result.text, position, conf)
Expand All @@ -1486,7 +1497,7 @@ internal fun CsCHECKContext.toAst(conf: ToAstConfiguration): Statement {
return CheckStmt(
factor1,
expression,
startPosition ?: 1,
startExpression,
wrongCharExpression,
dataDefinition,
position
Expand All @@ -1496,7 +1507,8 @@ internal fun CsCHECKContext.toAst(conf: ToAstConfiguration): Statement {
internal fun CsCHECKRContext.toAst(conf: ToAstConfiguration): Statement {
val position = toPosition(conf.considerPosition)
val factor1 = this.factor1Context()?.content?.toAst(conf) ?: throw UnsupportedOperationException("CHECKR operation requires factor 1: ${this.text} - ${position.atLine()}")
val (expression, startPosition) = this.cspec_fixed_standard_parts().factor2.toIndexedExpression(conf)
val factor2 = this.cspec_fixed_standard_parts().factor2
val (expression, positionExpression) = factor2.toIndexedExpression(conf)

val result = this.cspec_fixed_standard_parts().result
val dataDefinition = this.cspec_fixed_standard_parts().toDataDefinition(result.text, position, conf)
Expand All @@ -1512,13 +1524,24 @@ internal fun CsCHECKRContext.toAst(conf: ToAstConfiguration): Statement {
return CheckrStmt(
factor1,
expression,
startPosition ?: 1,
positionExpression,
wrongCharExpression,
dataDefinition,
position
)
}

private fun FactorContext.toIndexedExpression(conf: ToAstConfiguration): Pair<Expression, Expression?> {
// factor is formed by TEXT:B
// where "TEXT" is the content to be referenced positionally
val expression = this.factorContent(0).toAst(conf)
val positionExpression = if (this.factorContent().size > 1) {
this.factorContent(1).toAst(conf)
} else null

return expression to positionExpression
}

private fun FactorContext.toDoubleExpression(conf: ToAstConfiguration, index: Int): Expression =
if (this.text.contains(":")) this.text.toDoubleExpression(toPosition(conf.considerPosition), index) else this.content.toAst(conf)

Expand All @@ -1537,29 +1560,6 @@ private fun String.toDoubleExpression(position: Position?, index: Int): Expressi
return ret
}

private fun FactorContext.toIndexedExpression(conf: ToAstConfiguration): Pair<Expression, Int?> =
if (this.text.contains(":")) this.text.toIndexedExpression(toPosition(conf.considerPosition)) else this.content.toAst(conf) to null

private fun String.toIndexedExpression(position: Position?): Pair<Expression, Int?> {
val quoteAwareSplitPattern = Regex(""":(?=([^']*'[^']*')*[^']*$)""")
val baseStringTokens = this.split(quoteAwareSplitPattern)

val startPosition =
when (baseStringTokens.size) {
!in 1..2 -> throw UnsupportedOperationException("Wrong base string expression at line ${position?.line()}: $this")
2 -> baseStringTokens[1].toInt()
else -> null
}
val reference = baseStringTokens[0]
return when {
reference.isStringLiteral() -> StringLiteral(reference.trim('\''), position)
reference.contains('(') && reference.endsWith(")") -> {
annidatedReferenceExpression(this, position)
}
else -> DataRefExpr(ReferenceByName(reference), position)
} to startPosition
}

internal fun CsMOVEAContext.toAst(conf: ToAstConfiguration = ToAstConfiguration()): MoveAStmt {
val position = toPosition(conf.considerPosition)
val expression = this.cspec_fixed_standard_parts().factor2Expression(conf) ?: throw UnsupportedOperationException("MOVEA operation requires factor 2: ${this.text} - ${position.atLine()}")
Expand Down Expand Up @@ -2028,17 +2028,7 @@ internal fun CsSUBSTContext.toAst(conf: ToAstConfiguration = ToAstConfiguration(
// Left expression contain length
val length = leftExpr(conf)

// factor2 is formed by TEXT:B
// where "TEXT" is the content to be substringed
val stringExpression = this.cspec_fixed_standard_parts().factor2.factorContent(0).toAst(conf)
// and "B" is the start position to substring, if not specified it returns null
val positionExpression =
if (this.cspec_fixed_standard_parts().factor2.factorContent().size > 1) {
this.cspec_fixed_standard_parts().factor2.factorContent(1).toAst(conf)
} else {
null
}

val (stringExpression, positionExpression) = this.cspec_fixed_standard_parts().factor2.toIndexedExpression(conf)
val result = this.cspec_fixed_standard_parts().result.text
val dataDefinition = this.cspec_fixed_standard_parts().toDataDefinition(result, position, conf)

Expand Down Expand Up @@ -2083,8 +2073,8 @@ internal fun CsXLATEContext.toAst(conf: ToAstConfiguration = ToAstConfiguration(
from = from,
to = to,
string = string,
startPos = startPosition ?: 1,
target = this.cspec_fixed_standard_parts()!!.result!!.toAst(conf),
startPosition = startPosition,
target = this.cspec_fixed_standard_parts().result.toAst(conf),
rightIndicators = rightIndicators,
dataDefinition = dataDefinition,
position = position
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,4 +178,8 @@ internal fun Node.getContainingCompilationUnit() = ancestor(CompilationUnit::cla

internal fun List<UnwrappedStatementData>.indexOfTag(tag: String) = indexOfFirst {
it.statement is TagStmt && (it.statement as TagStmt).tag.lowercase() == tag.lowercase()
}

internal inline fun <T, R> Iterable<T>.mapNotNullOrError(transform: (T) -> R?): List<R> {
return this.mapNotNull { kotlin.runCatching { transform(it) }.getOrNull() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -2581,6 +2581,12 @@ Test 6
assertEquals(expected, "PRSLTCALLERDUPLICATE".outputOf())
}

@Test
fun executeFUNCALLMUTABILITY() {
val expected = listOf("ok")
assertEquals(expected, "FUNCALLMUTABILITY".outputOf())
}

@Test
fun missingDefinitionOnPListShouldThrowResolutionError() {
val systemInterface = JavaSystemInterface()
Expand Down
Loading

0 comments on commit e237706

Please sign in to comment.