Skip to content

Commit

Permalink
Merge pull request #309 from apex-dev-tools/294-check-decimaldouble-l…
Browse files Browse the repository at this point in the history
…iteral-handling

Add tests for Decimals, Longs & Integers being over size limits
  • Loading branch information
pwrightcertinia authored Dec 9, 2024
2 parents 29e3e56 + 78dcc09 commit fdaaef3
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 16 deletions.
64 changes: 52 additions & 12 deletions jvm/src/main/scala/com/nawforce/apexlink/cst/Literals.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ package com.nawforce.apexlink.cst
import com.nawforce.apexlink.types.core.TypeDeclaration
import com.nawforce.apexlink.types.platform.PlatformTypes
import com.nawforce.pkgforce.names.Name
import com.nawforce.pkgforce.path.PathLocation
import com.nawforce.runtime.parsers.CodeParser
import io.github.apexdevtools.apexparser.ApexParser.LiteralContext

sealed abstract class Literal() {
sealed abstract class Literal {
def getType: TypeDeclaration

def verify(context: ExpressionVerifyContext): Unit = {}
Expand All @@ -30,10 +31,28 @@ case object IntegerLiteral extends Literal {
override def getType: TypeDeclaration = PlatformTypes.integerType
}

case class OversizeIntegerLiteral(location: PathLocation) extends Literal {

override def getType: TypeDeclaration = PlatformTypes.integerType

override def verify(context: ExpressionVerifyContext): Unit = {
context.logError(location, "Integer literals can only be up to 10 characters")
}
}

case object LongLiteral extends Literal {
override def getType: TypeDeclaration = PlatformTypes.longType
}

case class OversizeLongLiteral(location: PathLocation) extends Literal {

override def getType: TypeDeclaration = PlatformTypes.longType

override def verify(context: ExpressionVerifyContext): Unit = {
context.logError(location, "Long literals can only be up to 19 characters")
}
}

case object DoubleLiteral extends Literal {
override def getType: TypeDeclaration = PlatformTypes.doubleType
}
Expand All @@ -42,6 +61,15 @@ case object DecimalLiteral extends Literal {
override def getType: TypeDeclaration = PlatformTypes.decimalType
}

case class OversizeDecimalLiteral(location: PathLocation) extends Literal {

override def getType: TypeDeclaration = PlatformTypes.decimalType

override def verify(context: ExpressionVerifyContext): Unit = {
context.logError(location, "Decimal literals can only be up to 50 characters")
}
}

case object StringLiteral extends Literal {
private val boundMatch = ":\\s*[0-9a-zA-Z_]*".r
private val boundPrefix = ":\\s*".r
Expand Down Expand Up @@ -83,37 +111,49 @@ case object NullLiteral extends Literal {
}

object IntegerOrLongLiteral {
def apply(value: String): Literal = {
if (value.endsWith("l") || value.endsWith("L"))
LongLiteral
else
IntegerLiteral
def apply(context: LiteralContext): Literal = {
val value = CodeParser.getText(context)
if (value.last.toLower == 'l') {
if (value.length > 20) // 19 + 1 for 'l'
OversizeLongLiteral(CST.sourceContext.value.get.getLocation(context))
else
LongLiteral
} else {
if (value.length > 10)
OversizeIntegerLiteral(CST.sourceContext.value.get.getLocation(context))
else
IntegerLiteral
}
}
}

object DoubleOrDecimalLiteral {
def apply(value: String): Literal = {
if (value.length() > 50)
def apply(context: LiteralContext): Literal = {
val value = CodeParser.getText(context)
if (value.last.toLower == 'd') {
DoubleLiteral
else
} else if (value.length > 50) {
OversizeDecimalLiteral(CST.sourceContext.value.get.getLocation(context))
} else {
DecimalLiteral
}
}
}

object Literal {
def construct(from: LiteralContext): Literal = {
CodeParser
.toScala(from.IntegerLiteral())
.map(x => IntegerOrLongLiteral(CodeParser.getText(x)))
.map(_ => IntegerOrLongLiteral(from))
.orElse(
CodeParser
.toScala(from.LongLiteral())
.map(x => IntegerOrLongLiteral(CodeParser.getText(x)))
.map(_ => IntegerOrLongLiteral(from))
)
.orElse(
CodeParser
.toScala(from.NumberLiteral())
.map(x => DoubleOrDecimalLiteral(CodeParser.getText(x)))
.map(_ => DoubleOrDecimalLiteral(from))
)
.orElse(
CodeParser
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
*/
package com.nawforce.apexlink.types
package com.nawforce.apexlink.cst

import com.nawforce.apexlink.cst.{BoundStringLiteral, CST, Literal}
import com.nawforce.apexlink.TestHelper
import com.nawforce.apexlink.names.TypeNames
import com.nawforce.pkgforce.names.{Name, Names, TypeName}
import com.nawforce.runtime.parsers.{CodeParser, Source, SourceData}
import com.nawforce.runtime.platform.Path
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers

class LiteralTypeTest extends AnyFunSuite with Matchers {
class LiteralTypeTest extends AnyFunSuite with Matchers with TestHelper {
def typeLiteral(data: String): Literal = {
val source = Source(Path("Dummy.cls"), SourceData(""), 0, 0, None)
CST.sourceContext.withValue(Some(source)) {
Expand Down Expand Up @@ -61,10 +61,58 @@ class LiteralTypeTest extends AnyFunSuite with Matchers {
literal("False", TypeNames.Boolean)
literal("null", TypeName(Name("Null$"), Nil, Some(TypeName(Names.Internal))))
literal("0.0", TypeNames.Decimal)
literal("0.0d", TypeNames.Double)
literal(".0", TypeNames.Decimal)
literal(".0D", TypeNames.Double)
literal("0.123", TypeNames.Decimal)
literal("0.123D", TypeNames.Double)
literal("0.123456789012345678901234567890123456789012345678", TypeNames.Decimal)
literal("0.1234567890123456789012345678901234567890123456789", TypeNames.Double)
literal("0.123456789012345678901234567890123456789012345678d", TypeNames.Double)
}

test("Max Decimal") {
typeDeclaration(
"public class Dummy { Object a = 0.123456789012345678901234567890123456789012345678; }"
)
assert(dummyIssues.isEmpty)
}

test("Oversize Decimal") {
typeDeclaration(
"public class Dummy { Object a = 0.1234567890123456789012345678901234567890123456789; }"
)
assert(
dummyIssues == "Error: line 1 at 32-83: Decimal literals can only be up to 50 characters\n"
)
}

test("Long Double") {
typeDeclaration(
"public class Dummy { Object a = 0.12345678901234567890123456789012345678901234567890123456789d; }"
)
assert(dummyIssues.isEmpty)
}

test("Max Integer") {
typeDeclaration("public class Dummy { Object a = 1234567890; }")
assert(dummyIssues.isEmpty)
}

test("Oversize Integer") {
typeDeclaration("public class Dummy { Object a = 12345678901; }")
assert(
dummyIssues == "Error: line 1 at 32-43: Integer literals can only be up to 10 characters\n"
)
}

test("Max Long") {
typeDeclaration("public class Dummy { Object a = 1234567890123456789l; }")
assert(dummyIssues.isEmpty)
}

test("Oversize Long") {
typeDeclaration("public class Dummy { Object a = 12345678901234567890l; }")
assert(dummyIssues == "Error: line 1 at 32-53: Long literals can only be up to 19 characters\n")
}

test("Bound string literal") {
Expand Down Expand Up @@ -95,4 +143,5 @@ class LiteralTypeTest extends AnyFunSuite with Matchers {
case BoundStringLiteral(bound) if bound == abcSet =>
}
}

}

0 comments on commit fdaaef3

Please sign in to comment.