Skip to content

Commit d3e9720

Browse files
authored
Add literal types (#349)
1 parent c94d41b commit d3e9720

File tree

3 files changed

+169
-10
lines changed

3 files changed

+169
-10
lines changed

jacodb-ets/src/main/kotlin/org/jacodb/ets/dto/Convert.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import org.jacodb.ets.model.EtsBitOrExpr
3232
import org.jacodb.ets.model.EtsBitXorExpr
3333
import org.jacodb.ets.model.EtsBlockCfg
3434
import org.jacodb.ets.model.EtsBooleanConstant
35+
import org.jacodb.ets.model.EtsBooleanLiteralType
3536
import org.jacodb.ets.model.EtsBooleanType
3637
import org.jacodb.ets.model.EtsCallExpr
3738
import org.jacodb.ets.model.EtsCallStmt
@@ -75,7 +76,6 @@ import org.jacodb.ets.model.EtsInstanceOfExpr
7576
import org.jacodb.ets.model.EtsIntersectionType
7677
import org.jacodb.ets.model.EtsLeftShiftExpr
7778
import org.jacodb.ets.model.EtsLexicalEnvType
78-
import org.jacodb.ets.model.EtsLiteralType
7979
import org.jacodb.ets.model.EtsLocal
8080
import org.jacodb.ets.model.EtsLocalSignature
8181
import org.jacodb.ets.model.EtsLtEqExpr
@@ -99,6 +99,7 @@ import org.jacodb.ets.model.EtsNullConstant
9999
import org.jacodb.ets.model.EtsNullType
100100
import org.jacodb.ets.model.EtsNullishCoalescingExpr
101101
import org.jacodb.ets.model.EtsNumberConstant
102+
import org.jacodb.ets.model.EtsNumberLiteralType
102103
import org.jacodb.ets.model.EtsNumberType
103104
import org.jacodb.ets.model.EtsOrExpr
104105
import org.jacodb.ets.model.EtsParameterRef
@@ -118,6 +119,7 @@ import org.jacodb.ets.model.EtsStmtLocation
118119
import org.jacodb.ets.model.EtsStrictEqExpr
119120
import org.jacodb.ets.model.EtsStrictNotEqExpr
120121
import org.jacodb.ets.model.EtsStringConstant
122+
import org.jacodb.ets.model.EtsStringLiteralType
121123
import org.jacodb.ets.model.EtsStringType
122124
import org.jacodb.ets.model.EtsSubExpr
123125
import org.jacodb.ets.model.EtsThis
@@ -551,9 +553,11 @@ fun TypeDto.toEtsType(): EtsType = when (this) {
551553
closures = closures.map { it.toEtsLocal() },
552554
)
553555

554-
is LiteralTypeDto -> EtsLiteralType(
555-
literalTypeName = literal.toString(),
556-
)
556+
is LiteralTypeDto -> when (val literalValue = literal) {
557+
is PrimitiveLiteralDto.StringLiteral -> EtsStringLiteralType(literalValue.value)
558+
is PrimitiveLiteralDto.NumberLiteral -> EtsNumberLiteralType(literalValue.value)
559+
is PrimitiveLiteralDto.BooleanLiteral -> EtsBooleanLiteralType(literalValue.value)
560+
}
557561

558562
NeverTypeDto -> EtsNeverType
559563

jacodb-ets/src/main/kotlin/org/jacodb/ets/model/Type.kt

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,11 @@ interface EtsType : TypeName, CommonType {
4141
fun visit(type: EtsUndefinedType): R
4242
fun visit(type: EtsVoidType): R
4343
fun visit(type: EtsNeverType): R
44-
fun visit(type: EtsLiteralType): R
44+
45+
// Literal
46+
fun visit(type: EtsStringLiteralType): R
47+
fun visit(type: EtsNumberLiteralType): R
48+
fun visit(type: EtsBooleanLiteralType): R
4549

4650
// Ref
4751
fun visit(type: EtsClassType): R
@@ -74,7 +78,10 @@ interface EtsType : TypeName, CommonType {
7478
override fun visit(type: EtsUndefinedType): R = defaultVisit(type)
7579
override fun visit(type: EtsVoidType): R = defaultVisit(type)
7680
override fun visit(type: EtsNeverType): R = defaultVisit(type)
77-
override fun visit(type: EtsLiteralType): R = defaultVisit(type)
81+
82+
override fun visit(type: EtsStringLiteralType): R = defaultVisit(type)
83+
override fun visit(type: EtsNumberLiteralType): R = defaultVisit(type)
84+
override fun visit(type: EtsBooleanLiteralType): R = defaultVisit(type)
7885

7986
override fun visit(type: EtsClassType): R = defaultVisit(type)
8087
override fun visit(type: EtsUnclearRefType): R = defaultVisit(type)
@@ -277,11 +284,39 @@ object EtsNeverType : EtsPrimitiveType {
277284
}
278285
}
279286

280-
data class EtsLiteralType(
281-
val literalTypeName: String,
282-
) : EtsPrimitiveType {
287+
sealed interface EtsLiteralType : EtsPrimitiveType
288+
289+
data class EtsStringLiteralType(
290+
val value: String,
291+
) : EtsLiteralType {
292+
override val typeName: String
293+
get() = "\"$value\""
294+
295+
override fun toString(): String = typeName
296+
297+
override fun <R> accept(visitor: EtsType.Visitor<R>): R {
298+
return visitor.visit(this)
299+
}
300+
}
301+
302+
data class EtsNumberLiteralType(
303+
val value: Double,
304+
) : EtsLiteralType {
305+
override val typeName: String
306+
get() = value.toString()
307+
308+
override fun toString(): String = typeName
309+
310+
override fun <R> accept(visitor: EtsType.Visitor<R>): R {
311+
return visitor.visit(this)
312+
}
313+
}
314+
315+
data class EtsBooleanLiteralType(
316+
val value: Boolean,
317+
) : EtsLiteralType {
283318
override val typeName: String
284-
get() = literalTypeName
319+
get() = value.toString()
285320

286321
override fun toString(): String = typeName
287322

jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsFromJsonTest.kt

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,126 @@ class EtsFromJsonTest {
428428
assertEquals(PrimitiveLiteralDto.StringLiteral("hello"), typeDto.literal)
429429
}
430430

431+
@Test
432+
fun testLoadNumberLiteralTypeFromJson() {
433+
// TS: `let x: 42 = 42;`
434+
val jsonString = """
435+
{
436+
"_": "LiteralType",
437+
"literal": 42
438+
}
439+
""".trimIndent()
440+
val typeDto = Json.decodeFromString<TypeDto>(jsonString)
441+
logger.info { "typeDto = $typeDto" }
442+
assertIs<LiteralTypeDto>(typeDto)
443+
assertEquals(PrimitiveLiteralDto.NumberLiteral(42.0), typeDto.literal)
444+
}
445+
446+
@Test
447+
fun testLoadFloatLiteralTypeFromJson() {
448+
// TS: `let x: 3.14 = 3.14;`
449+
val jsonString = """
450+
{
451+
"_": "LiteralType",
452+
"literal": 3.14
453+
}
454+
""".trimIndent()
455+
val typeDto = Json.decodeFromString<TypeDto>(jsonString)
456+
logger.info { "typeDto = $typeDto" }
457+
assertIs<LiteralTypeDto>(typeDto)
458+
assertEquals(PrimitiveLiteralDto.NumberLiteral(3.14), typeDto.literal)
459+
}
460+
461+
@Test
462+
fun testLoadNegativeNumberLiteralTypeFromJson() {
463+
// TS: `let x: -5 = -5;`
464+
val jsonString = """
465+
{
466+
"_": "LiteralType",
467+
"literal": -5
468+
}
469+
""".trimIndent()
470+
val typeDto = Json.decodeFromString<TypeDto>(jsonString)
471+
logger.info { "typeDto = $typeDto" }
472+
assertIs<LiteralTypeDto>(typeDto)
473+
assertEquals(PrimitiveLiteralDto.NumberLiteral(-5.0), typeDto.literal)
474+
}
475+
476+
@Test
477+
fun testLoadBooleanTrueLiteralTypeFromJson() {
478+
// TS: `let x: true = true;`
479+
val jsonString = """
480+
{
481+
"_": "LiteralType",
482+
"literal": true
483+
}
484+
""".trimIndent()
485+
val typeDto = Json.decodeFromString<TypeDto>(jsonString)
486+
logger.info { "typeDto = $typeDto" }
487+
assertIs<LiteralTypeDto>(typeDto)
488+
assertEquals(PrimitiveLiteralDto.BooleanLiteral(true), typeDto.literal)
489+
}
490+
491+
@Test
492+
fun testLoadBooleanFalseLiteralTypeFromJson() {
493+
// TS: `let x: false = false;`
494+
val jsonString = """
495+
{
496+
"_": "LiteralType",
497+
"literal": false
498+
}
499+
""".trimIndent()
500+
val typeDto = Json.decodeFromString<TypeDto>(jsonString)
501+
logger.info { "typeDto = $typeDto" }
502+
assertIs<LiteralTypeDto>(typeDto)
503+
assertEquals(PrimitiveLiteralDto.BooleanLiteral(false), typeDto.literal)
504+
}
505+
506+
@Test
507+
fun testLoadEmptyStringLiteralTypeFromJson() {
508+
// TS: `let x: "" = "";`
509+
val jsonString = """
510+
{
511+
"_": "LiteralType",
512+
"literal": ""
513+
}
514+
""".trimIndent()
515+
val typeDto = Json.decodeFromString<TypeDto>(jsonString)
516+
logger.info { "typeDto = $typeDto" }
517+
assertIs<LiteralTypeDto>(typeDto)
518+
assertEquals(PrimitiveLiteralDto.StringLiteral(""), typeDto.literal)
519+
}
520+
521+
@Test
522+
fun testLoadStringLiteralWithSpecialCharactersFromJson() {
523+
// TS: `let x: "Hello\nWorld\t!" = "Hello\nWorld\t!";`
524+
val jsonString = """
525+
{
526+
"_": "LiteralType",
527+
"literal": "Hello\nWorld\t!"
528+
}
529+
""".trimIndent()
530+
val typeDto = Json.decodeFromString<TypeDto>(jsonString)
531+
logger.info { "typeDto = $typeDto" }
532+
assertIs<LiteralTypeDto>(typeDto)
533+
assertEquals(PrimitiveLiteralDto.StringLiteral("Hello\nWorld\t!"), typeDto.literal)
534+
}
535+
536+
@Test
537+
fun testLoadZeroLiteralTypeFromJson() {
538+
// TS: `let x: 0 = 0;`
539+
val jsonString = """
540+
{
541+
"_": "LiteralType",
542+
"literal": 0
543+
}
544+
""".trimIndent()
545+
val typeDto = Json.decodeFromString<TypeDto>(jsonString)
546+
logger.info { "typeDto = $typeDto" }
547+
assertIs<LiteralTypeDto>(typeDto)
548+
assertEquals(PrimitiveLiteralDto.NumberLiteral(0.0), typeDto.literal)
549+
}
550+
431551
@Test
432552
fun testLoadRawTypeFromJson() {
433553
val jsonString = """

0 commit comments

Comments
 (0)