Skip to content

Commit

Permalink
Merge branch 'develop' into bugfix/LS24003177/comptime-define-on-subr…
Browse files Browse the repository at this point in the history
…outine
  • Loading branch information
dom-apuliasoft committed Jul 12, 2024
2 parents 8392853 + 85f87d6 commit 03999c3
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ interface Evaluator {
fun eval(expression: LessEqualThanExpr): Value
fun eval(expression: LessThanExpr): Value
fun eval(expression: BlanksRefExpr): BlanksValue
fun eval(expression: DecExpr): Value
fun eval(expression: DecNumericExpr): Value
fun eval(expression: DecTimeExpr): Value
fun eval(expression: PlusExpr): Value
fun eval(expression: MinusExpr): Value
fun eval(expression: MultExpr): Value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ class ExpressionEvaluation(

override fun eval(expression: BlanksRefExpr) = proxyLogging(expression) { BlanksValue } as BlanksValue

override fun eval(expression: DecExpr): Value = proxyLogging(expression) {
override fun eval(expression: DecNumericExpr): Value = proxyLogging(expression) {
val decDigits = expression.decDigits.evalWith(this).asInt().value
val valueAsString = expression.value.evalWith(this).asString().value
val valueAsBigDecimal = valueAsString.asBigDecimal()
Expand All @@ -165,6 +165,23 @@ class ExpressionEvaluation(
}
}

override fun eval(expression: DecTimeExpr): Value = proxyLogging(expression) {
val value = expression.timestamp.evalWith(this)
val format = expression.format

return@proxyLogging when (value) {
is TimeStampValue -> {
if (format != null) error("%DEC(time:format) is allowed only when time is DateValue")
value.toDecimal()
}
is DateValue -> {
if (format != null) TODO("%DEC(time{:format}) with custom format is not implemented yet")
value.toDecimal()
}
else -> error("%DEC(time{:format}) is allowed only when time is TimeStampValue or DateValue")
}
}

override fun eval(expression: PlusExpr): Value = proxyLogging(expression) {
val left = expression.left.evalWith(this)
val right = expression.right.evalWith(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ data class StringValue(var value: String, var varying: Boolean = false) : Abstra
return BooleanValue.FALSE
}

override fun asInt() = value.toInt().asValue()
override fun asDecimal() = value.toBigDecimal().asValue()

override fun asTimeStamp(): TimeStampValue = TimeStampValue.of(value)

fun setSubstring(startOffset: Int, endOffset: Int, substringValue: StringValue) {
Expand Down Expand Up @@ -459,6 +462,7 @@ data class TimeStampValue(@Contextual val value: LocalDateTime) : Value {

companion object {
val DEFAULT_FORMAT = "yyyy-MM-dd-HH.mm.ss.SSSSSS"
val DECIMAL_FORMAT = "yyyyMMddHHmmssSSSSSS"
val LOVAL: TimeStampValue by lazy {
TimeStampValue(LocalDateTime.parse("0001-01-01-00.00.00.000000", DateTimeFormatter.ofPattern(DEFAULT_FORMAT)))
}
Expand All @@ -480,6 +484,15 @@ data class TimeStampValue(@Contextual val value: LocalDateTime) : Value {
override fun asString(): StringValue {
return StringValue(DateTimeFormatter.ofPattern(DEFAULT_FORMAT).format(value))
}

fun format(pattern: String): StringValue {
val formatter = DateTimeFormatter.ofPattern(pattern)
return format(formatter)
}

fun format(formatter: DateTimeFormatter) = formatter.format(value).asValue()

fun toDecimal() = format(DECIMAL_FORMAT).asDecimal()
}

/**
Expand All @@ -489,6 +502,10 @@ data class TimeStampValue(@Contextual val value: LocalDateTime) : Value {
*/
@Serializable
data class DateValue(val value: Long, val format: DateFormat) : Value {
private val isoDate: String by lazy {
SimpleDateFormat("YYYY-MM-dd").format(Date(value))
}

override fun assignableTo(expectedType: Type): Boolean {
return expectedType is DateType
}
Expand All @@ -504,13 +521,27 @@ data class DateValue(val value: Long, val format: DateFormat) : Value {
* @return String with date formatted.
*/
fun adapt(format: DateFormat): String {
val dateISO = SimpleDateFormat("YYYY-MM-dd").format(Date(value))
return when (format) {
DateFormat.JUL -> {
LocalDate.parse(dateISO).format(DateTimeFormatter.ISO_ORDINAL_DATE)
LocalDate.parse(isoDate).format(DateTimeFormatter.ISO_ORDINAL_DATE)
.let { "${it.substring(2, 4)}/${it.substring(5)}" }
}
DateFormat.ISO -> dateISO
DateFormat.ISO -> isoDate
}
}

fun format(pattern: String): StringValue {
val formatter = DateTimeFormatter.ofPattern(pattern)
return format(formatter)
}

fun format(formatter: DateTimeFormatter) = formatter.format(LocalDate.parse(isoDate)).asValue()

fun toDecimal(): DecimalValue {
return when (format) {
DateFormat.JUL -> format("yyDDD").asDecimal()
DateFormat.ISO -> format("yyyyMMdd").asDecimal()
else -> TODO()
}
}
}
Expand Down Expand Up @@ -1077,6 +1108,7 @@ data class DataStructValue(var value: String, private val optionalExternalLen: I

fun Int.asValue() = IntValue(this.toLong())
fun Boolean.asValue() = BooleanValue(this)
fun BigDecimal.asValue() = DecimalValue(this)

fun areEquals(value1: Value, value2: Value): Boolean {
return when {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import com.smeup.rpgparser.interpreter.Evaluator
import com.smeup.rpgparser.interpreter.Value
import com.strumenta.kolasu.model.Position
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient

/**
* For expressions with this interface there isn't resolution but will be called the callback `onMockExpression` and returned a null value.
Expand Down Expand Up @@ -254,22 +255,40 @@ data class RemExpr(
override fun evalWith(evaluator: Evaluator): Value = evaluator.eval(this)
}

// %DEC
// Abstract %DEC definition
@Serializable
data class DecExpr(
var value: Expression,
var intDigits: Expression,
val decDigits: Expression,
abstract class DecExpr(
override val position: Position? = null
) : Expression(position) {
override val loggableEntityName: String
get() = "%DEC"
}

// %DEC with numeric value
@Serializable
data class DecNumericExpr(
var value: Expression,
var intDigits: Expression,
val decDigits: Expression,
@Transient override val position: Position? = null
) : DecExpr(position) {
override fun render(): String {
return this.value.render()
}
override fun evalWith(evaluator: Evaluator): Value = evaluator.eval(this)
}

// %DEC with timestamp value
@Serializable
data class DecTimeExpr(
var timestamp: Expression,
var format: Expression?,
@Transient override val position: Position? = null
) : DecExpr(position) {
override fun render() = timestamp.render()
override fun evalWith(evaluator: Evaluator) = evaluator.eval(this)
}

// %INT
@Serializable
data class IntExpr(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ private val modules = SerializersModule {
subclass(CharExpr::class)
subclass(CheckExpr::class)
subclass(DataRefExpr::class)
subclass(DecExpr::class)
subclass(DecNumericExpr::class)
subclass(DecTimeExpr::class)
subclass(DiffExpr::class)
subclass(DifferentThanExpr::class)
subclass(DivExpr::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,20 @@ internal fun RpgParser.Bif_charContext.toAst(conf: ToAstConfiguration = ToAstCon
}

internal fun RpgParser.Bif_decContext.toAst(conf: ToAstConfiguration = ToAstConfiguration()): DecExpr {
return DecExpr(
this.expression(0).toAst(conf),
this.expression(1).toAst(conf),
this.expression(2).toAst(conf),
toPosition(conf.considerPosition))
val position = toPosition(conf.considerPosition)

// Target is mandatory
val target = this.expression(0).toAst(conf)
return if (this.expression().size < 3) {
// %DEC(date time or timestamp expression {:format})
val format = kotlin.runCatching { this.expression(1) }.getOrNull()?.toAst(conf)
DecTimeExpr(target, format, position)
} else {
// %DEC(Numeric expression :digits : dec pos)
val digits = this.expression(1).toAst(conf)
val decPos = this.expression(2).toAst(conf)
DecNumericExpr(target, digits, decPos, position)
}
}

internal fun RpgParser.Bif_intContext.toAst(conf: ToAstConfiguration = ToAstConfiguration()): IntExpr {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,14 @@ open class MULANGT04EssentialsCodopAndBifTest : MULANGTTest() {
)
assertEquals(expected, "smeup/MUDRNRAPU00228".outputOf())
}

/**
* %DEC with dates and timestamps
* @see #LS24003289
*/
@Test
fun executeMUDRNRAPU00229() {
val expected = listOf("19700101000000000000", "19700101")
assertEquals(expected, "smeup/MUDRNRAPU00229".outputOf())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
D NTIMES S 20 0
D timestamp S Z INZ(Z'1970-01-01-00.00.00.000000')
D date S D INZ(D'1970-01-01')
C EVAL NTIMES=%DEC(timestamp)
C NTIMES DSPLY
C EVAL NTIMES=%DEC(date)
C NTIMES DSPLY

0 comments on commit 03999c3

Please sign in to comment.