Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix/zero number literal initialization #406

Merged
merged 3 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ fun Expression.type(): Type {
NumberType(BigDecimal.valueOf(this.value).precision(), decimalDigits = 0)
}
is RealLiteral -> {
NumberType(this.value.precision() - this.value.scale(), this.value.scale())
NumberType(this.precision - this.value.scale(), this.value.scale())
}
is ArrayAccessExpr -> {
val type = this.array.type().asArray()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,21 @@ abstract class Expression(@Transient override val position: Position? = null) :
abstract class NumberLiteral(@Transient override val position: Position? = null) : Expression(position)

@Serializable
data class IntLiteral(val value: Long, override val position: Position? = null) : NumberLiteral(position) {
data class IntLiteral(
val value: Long,
override val position: Position? = null,
val precision: Int = BigDecimal(value).precision()
) : NumberLiteral(position) {
override fun render() = value.toString()
override fun evalWith(evaluator: Evaluator): Value = evaluator.eval(this)
}
@Serializable
data class RealLiteral(@Contextual val value: BigDecimal, override val position: Position? = null) : NumberLiteral(position) {
data class RealLiteral(
@Contextual val value: BigDecimal,
override val position: Position? = null,
val precision: Int = value.precision()
) : NumberLiteral(position) {

override fun render() = value.toString()
override fun evalWith(evaluator: Evaluator): Value = evaluator.eval(this)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,30 +85,31 @@ internal fun RpgParser.LiteralContext.toAst(conf: ToAstConfiguration = ToAstConf
internal fun RpgParser.NumberContext.toAst(conf: ToAstConfiguration = ToAstConfiguration()): NumberLiteral {
val position = this.toPosition(conf.considerPosition)
require(this.NumberPart().isEmpty()) { "Number not empty $position" }
val text = (this.MINUS()?.text ?: "") + this.NUMBER().text

// When assigning a value to a numeric field we could either use
// a comma or a dot as decimal separators

// TODO Rifattorizzare con literalToNumber(text, position)
return when {
text.contains('.') -> {
text.toRealLiteral(position, Locale.US)
}
text.contains(',') -> {
text.toRealLiteral(position, Locale.ITALIAN)
}
else -> IntLiteral(text.toLong(), position)
}
return literalToNumber(this.text, position)
}

fun String.toRealLiteral(position: Position?, locale: Locale): RealLiteral {
val nf = NumberFormat.getNumberInstance(locale)
val formatter = nf as DecimalFormat
formatter.isParseBigDecimal = true
val bd = (formatter.parse(this) as BigDecimal)
// in case of zero precision returned by big decimal il always 1
val precision = if (bd.toDouble() == 0.0) {
this.replace(Regex("[^0-9]"), "").length
} else {
bd.precision()
}
return RealLiteral(value = bd, position = position, precision = precision)
}

val bd = formatter.parse(this) as BigDecimal
return RealLiteral(bd, position)
fun String.toIntLiteral(position: Position?): IntLiteral {
val value = this.toLong()
val precision = if (value == 0L) {
this.replace(Regex("[^0-9]"), "").length
} else {
BigDecimal(value).precision()
}
return IntLiteral(value = value, position = position, precision = precision)
}

internal fun RpgParser.IdentifierContext.toAst(conf: ToAstConfiguration = ToAstConfiguration()): Expression {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ internal fun FactorContentContext.toAst(conf: ToAstConfiguration): Expression {
fun literalToNumber(
text: String,
position: Position?
): Expression {
): NumberLiteral {
// fix minus at right
val value = if (text.endsWith('-')) {
"-" + text.replaceFirst("-", "")
Expand All @@ -647,7 +647,7 @@ fun literalToNumber(
value.toRealLiteral(position, Locale.ITALIAN)
}
else -> {
IntLiteral(value.toLong(), position)
value.toIntLiteral(position)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.smeup.rpgparser.parsing.ast

import com.smeup.rpgparser.*
import com.smeup.rpgparser.assertExpressionCanBeParsed
import com.smeup.rpgparser.dataRef
import com.smeup.rpgparser.parsing.parsetreetoast.ToAstConfiguration
import com.smeup.rpgparser.parsing.parsetreetoast.toAst
import com.strumenta.kolasu.model.ReferenceByName
import java.math.BigDecimal
import kotlin.test.Ignore
import kotlin.test.assertEquals
import org.junit.Test as test
Expand Down Expand Up @@ -144,4 +146,20 @@ class ExpressionsTest {
@test fun parseIndicatorsInParenthesis() {
assertExpressionCanBeParsed("X=*IN(01)")
}

@test fun intLiteralParsingNumberWithPrecision() {
assertEquals(IntLiteral(value = 100, precision = 3), expression("100"))
}

@test fun intLiteralParsingZeroWithPrecision() {
assertEquals(IntLiteral(value = 0, precision = 3), expression("000"))
}

@test fun realLiteralParsingNumberWithPrecision() {
assertEquals(RealLiteral(value = BigDecimal("100.00"), precision = 5), expression("100.00"))
}

@test fun realLiteralParsingZeroWithPrecision() {
assertEquals(RealLiteral(value = BigDecimal("0.00"), precision = 3), expression("0.00"))
}
}
Loading