Skip to content

Commit

Permalink
Merge pull request #69 from smeup/data-package-merge-6
Browse files Browse the repository at this point in the history
Data package merge 6
  • Loading branch information
ftomassetti authored Jan 2, 2020
2 parents 956191d + 3b9cc74 commit edca0f1
Showing 33 changed files with 1,551 additions and 316 deletions.
Original file line number Diff line number Diff line change
@@ -12,15 +12,15 @@ class SymbolTable {
if (data is FieldDefinition) {
val containerValue = get(data.container)
return if (data.container.isArray()) {
ProjectedArrayValue(containerValue as ArrayValue, data)
TODO("We do not yet handle an array container")
} else if (data.declaredArrayInLine != null) {
ProjectedArrayValue.forData(containerValue as DataStructValue, data)
} else {
// Should be always a DataStructValue
if (containerValue is DataStructValue) {
return coerce(containerValue.get(data), data.type)
return coerce(containerValue[data], data.type)
} else {
val structValue = (containerValue as? StructValue)
?: throw IllegalStateException("Container expected to be a struct value: $containerValue")
structValue.elements[data]!!
throw IllegalStateException("The container value is expected to be a DataStructValue, instead it is $containerValue")
}
}
}
@@ -32,13 +32,19 @@ class SymbolTable {
if (data != null) {
return values[data] ?: throw IllegalArgumentException("Cannot find searched value for $data")
}
for (e in values) {
if (e.key is DataDefinition) {
val field = (e.key as DataDefinition).fields.firstOrNull {
// We did not find a top-level declaration with that name,
// looking among fields
for (topLevelValue in values) {
if (topLevelValue.key is DataDefinition) {
val field = (topLevelValue.key as DataDefinition).fields.firstOrNull {
it.name.equals(dataName, ignoreCase = true) && it.canBeUsedUnqualified()
}
if (field != null) {
return ProjectedArrayValue(e.value as ArrayValue, field)
return if (topLevelValue.key.type is ArrayValue) {
TODO("We do not yet handle top level values of array type")
} else {
(topLevelValue.value as DataStructValue)[field]
}
}
}
}
@@ -52,14 +58,17 @@ class SymbolTable {
require(!(data !in this && data.name in this)) {
"This data definition would conflict with an existing data definition with the same name. This data definition: $data. Existing data definition: ${this[data.name]}"
}
require(data.type.canBeAssigned(value))
values[data] = value.forType(data.type)
}
}

// Review required

private fun Value.forType(type: Type): Value {
if (type is StringType && this is StringValue) {
if (type.varying) {
this.trimEnd()
// this.trimEnd()
} else {
if (this.value.length < type.length) this.pad(type.length)
}
Original file line number Diff line number Diff line change
@@ -25,6 +25,9 @@ private fun coerceBlanks(type: Type): Value {
is DataStructureType -> {
type.blank()
}
is BooleanType -> {
BooleanValue.FALSE
}
else -> TODO("Converting BlanksValue to $type")
}
}
@@ -35,15 +38,22 @@ private fun coerceString(value: StringValue, type: Type): Value {
if (value.value.length > type.length) {
return StringValue(value.value.substring(0, type.length))
}
return StringValue(value.value)
return StringValue(value.value, type.varying)
}
is ArrayType -> {
if (type.element is StringType) {
// We are coercing a String into an array of Strings
// We split the string in substrings and copy each piece into
// an element of the array

var i = 0
val elementSize = type.element.size
val valueForArray = value.value.padEnd(elementSize).take(elementSize)
createArrayValue(type.element, type.nElements) {
// TODO Since value property of StringValue is a var, we cannot share instances of StringValue
StringValue(valueForArray)
val valueForArray = value.value.substring(0, Math.min(elementSize, value.value.length)).padEnd(elementSize)
val res = StringValue(valueForArray)
i += elementSize
res
}
} else {
createArrayValue(type.element, type.nElements) {
@@ -55,22 +65,35 @@ private fun coerceString(value: StringValue, type: Type): Value {
is NumberType -> {
if (type.integer) {
when {
value.isBlank() -> IntValue.ZERO
// TODO commented out see #45
// value.isBlank() -> IntValue.ZERO
type.rpgType == RpgType.BINARY.rpgType -> {
val intValue = decodeBinary(value.value, type.entireDigits)
val intValue = decodeBinary(value.value, type.size.toInt())
IntValue(intValue.longValueExact())
}
type.rpgType == RpgType.INTEGER.rpgType -> {
val intValue = decodeInteger(value.value, type.entireDigits)
val intValue = decodeInteger(value.value, type.size.toInt())
IntValue(intValue.longValueExact())
}
type.rpgType == RpgType.UNSIGNED.rpgType -> {
val intValue = decodeUnsigned(value.value, type.entireDigits)
val intValue = decodeUnsigned(value.value, type.size.toInt())
IntValue(intValue.longValueExact())
}
type.rpgType == RpgType.ZONED.rpgType -> {
if (!value.isBlank()) {
val intValue = decodeFromZoned(value.value.trim(), type.entireDigits, type.decimalDigits)
IntValue(intValue.longValueExact())
} else {
DecimalValue(BigDecimal.ZERO)
}
}
else -> {
val intValue = decodeFromDS(value.value.trim(), type.entireDigits, type.decimalDigits)
IntValue(intValue.longValueExact())
if (!value.isBlank()) {
val intValue = decodeFromDS(value.value.trim(), type.entireDigits, type.decimalDigits)
IntValue(intValue.longValueExact())
} else {
IntValue(0)
}
}
}
} else {
@@ -119,12 +142,12 @@ fun coerce(value: Value, type: Type): Value {
coerceString(value, type)
}
is ArrayValue -> {
when (type) {
return when (type) {
is StringType -> {
return value.asString()
value.asString()
}
is ArrayType -> {
return value
value
}
else -> TODO("Converting ArrayValue to $type")
}
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ import com.smeup.rpgparser.RpgParser
import com.smeup.rpgparser.parsing.ast.*
import com.smeup.rpgparser.parsing.parsetreetoast.*
import com.smeup.rpgparser.utils.asInt
import java.lang.RuntimeException

/**
* This is a very limited interpreter used at compile time, mainly
@@ -14,11 +15,15 @@ import com.smeup.rpgparser.utils.asInt
interface CompileTimeInterpreter {
fun evaluate(rContext: RpgParser.RContext, expression: Expression): Value
fun evaluateElementSizeOf(rContext: RpgParser.RContext, expression: Expression): Int
fun evaluateNumberOfElementsOf(rContext: RpgParser.RContext, declName: String): Int
}

object CommonCompileTimeInterpreter : BaseCompileTimeInterpreter()
object CommonCompileTimeInterpreter : BaseCompileTimeInterpreter(emptyList())

class InjectableCompileTimeInterpreter : BaseCompileTimeInterpreter() {
class InjectableCompileTimeInterpreter(
knownDataDefinitions: List<DataDefinition> = emptyList(),
delegatedCompileTimeInterpreter: CompileTimeInterpreter? = null
) : BaseCompileTimeInterpreter(knownDataDefinitions, delegatedCompileTimeInterpreter) {
override fun evaluateNumberOfElementsOf(rContext: RpgParser.RContext, declName: String): Int {
return mockedDecls[declName]?.numberOfElements() ?: super.evaluateNumberOfElementsOf(rContext, declName)
}
@@ -34,7 +39,12 @@ class InjectableCompileTimeInterpreter : BaseCompileTimeInterpreter() {
}
}

open class BaseCompileTimeInterpreter : CompileTimeInterpreter {
class NotFoundAtCompileTimeException(val declName: String) : RuntimeException("Unable to calculate element size of $declName")

open class BaseCompileTimeInterpreter(
val knownDataDefinitions: List<DataDefinition>,
val delegatedCompileTimeInterpreter: CompileTimeInterpreter? = null
) : CompileTimeInterpreter {
override fun evaluate(rContext: RpgParser.RContext, expression: Expression): Value {
return when (expression) {
is NumberOfElementsExpr -> IntValue(evaluateNumberOfElementsOf(rContext, expression.value).toLong())
@@ -43,14 +53,34 @@ open class BaseCompileTimeInterpreter : CompileTimeInterpreter {
else -> TODO(expression.toString())
}
}

private fun evaluateNumberOfElementsOf(rContext: RpgParser.RContext, expression: Expression): Int {
return when (expression) {
is DataRefExpr -> evaluateNumberOfElementsOf(rContext, expression.variable.name)
is DataRefExpr -> {
try {
evaluateNumberOfElementsOf(rContext, expression.variable.name)
} catch (e: NotFoundAtCompileTimeException) {
if (delegatedCompileTimeInterpreter != null) {
return delegatedCompileTimeInterpreter!!.evaluateNumberOfElementsOf(rContext, expression.variable.name)
} else {
throw RuntimeException(e)
}
}
}
else -> TODO(expression.toString())
}
}

protected open fun evaluateNumberOfElementsOf(rContext: RpgParser.RContext, declName: String): Int {
override fun evaluateNumberOfElementsOf(rContext: RpgParser.RContext, declName: String): Int {
knownDataDefinitions.forEach {
if (it.name == declName) {
return it.numberOfElements()
}
val field = it.fields.find { it.name == declName }
if (field != null) {
return field.numberOfElements()
}
}
rContext.statement()
.forEach {
when {
@@ -71,10 +101,23 @@ open class BaseCompileTimeInterpreter : CompileTimeInterpreter {
}
}
}
TODO("Not found: $declName")
throw NotFoundAtCompileTimeException(declName)
}

open fun evaluateElementSizeOf(rContext: RpgParser.RContext, declName: String): Int {
knownDataDefinitions.forEach {
if (it.name == declName) {
return it.elementSize().toInt()
}
val field = it.fields.find { it.name == declName }
if (field != null) {
if (field.declaredArrayInLine != null) {
return (field.elementSize() /*/ field.declaredArrayInLine!!*/).toInt()
}
return field.elementSize().toInt()
}
}

rContext.statement()
.forEach {
when {
@@ -93,12 +136,22 @@ open class BaseCompileTimeInterpreter : CompileTimeInterpreter {
}
}
}
TODO("Not found: $declName")
throw NotFoundAtCompileTimeException(declName)
}

override fun evaluateElementSizeOf(rContext: RpgParser.RContext, expression: Expression): Int {
return when (expression) {
is DataRefExpr -> evaluateElementSizeOf(rContext, expression.variable.name)
is DataRefExpr -> {
try {
evaluateElementSizeOf(rContext, expression.variable.name)
} catch (e: NotFoundAtCompileTimeException) {
if (delegatedCompileTimeInterpreter != null) {
return delegatedCompileTimeInterpreter!!.evaluateElementSizeOf(rContext, expression)
} else {
throw RuntimeException(e)
}
}
}
else -> TODO(expression.toString())
}
}
Loading

0 comments on commit edca0f1

Please sign in to comment.