smple enums w/serialization
This commit is contained in:
parent
84e345b04e
commit
b5e89c7e78
@ -475,7 +475,7 @@ Lyng has built-in mutable array class `List` with simple literals:
|
|||||||
[1, "two", 3.33].size
|
[1, "two", 3.33].size
|
||||||
>>> 3
|
>>> 3
|
||||||
|
|
||||||
[List] is an implementation of the type `Array`, and through it `Collection` and [Iterable].
|
[List] is an implementation of the type `Array`, and through it `Collection` and [Iterable]. Please read [Iterable], many collection based methods are implemented there.
|
||||||
|
|
||||||
Lists can contain any type of objects, lists too:
|
Lists can contain any type of objects, lists too:
|
||||||
|
|
||||||
@ -1120,6 +1120,25 @@ These should be imported from [lyng.time](time.md). For example:
|
|||||||
|
|
||||||
See [more docs on time manipulation](time.md)
|
See [more docs on time manipulation](time.md)
|
||||||
|
|
||||||
|
# Enums
|
||||||
|
|
||||||
|
For the moment, only simple enums are implemented. Enum is a list of constants, represented also by their _ordinal_ - [Int] value.
|
||||||
|
|
||||||
|
enum Color {
|
||||||
|
RED, GREEN, BLUE
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( Color.RED is Color )
|
||||||
|
|
||||||
|
assertEquals( 2, Color.BLUE.ordinal )
|
||||||
|
assertEquals( "BLUE", Color.BLUE.name )
|
||||||
|
|
||||||
|
assertEquals( [Color.RED,Color.GREEN,Color.BLUE], Color.entries)
|
||||||
|
assertEquals( Color.valueOf("GREEN"), Color.GREEN )
|
||||||
|
>>> void
|
||||||
|
|
||||||
|
Enums are serialized as ordinals. Please note that due to caching, serialized string arrays could be even more compact than enum arrays, until `Lynon.encodeTyped` will be implemented.
|
||||||
|
|
||||||
# Comments
|
# Comments
|
||||||
|
|
||||||
// single line comment
|
// single line comment
|
||||||
|
@ -4,7 +4,7 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
|
|||||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
|
||||||
group = "net.sergeych"
|
group = "net.sergeych"
|
||||||
version = "0.8.7-SNAPSHOT"
|
version = "0.8.8-SNAPSHOT"
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.sergeych.lyng
|
package net.sergeych.lyng
|
||||||
|
|
||||||
|
import ObjEnumClass
|
||||||
import net.sergeych.lyng.obj.*
|
import net.sergeych.lyng.obj.*
|
||||||
import net.sergeych.lyng.pacman.ImportProvider
|
import net.sergeych.lyng.pacman.ImportProvider
|
||||||
|
|
||||||
@ -858,7 +859,8 @@ class Compiler(
|
|||||||
"break" -> parseBreakStatement(id.pos)
|
"break" -> parseBreakStatement(id.pos)
|
||||||
"continue" -> parseContinueStatement(id.pos)
|
"continue" -> parseContinueStatement(id.pos)
|
||||||
"if" -> parseIfStatement()
|
"if" -> parseIfStatement()
|
||||||
"class" -> parseClassDeclaration(false)
|
"class" -> parseClassDeclaration()
|
||||||
|
"enum" -> parseEnumDeclaration()
|
||||||
"try" -> parseTryStatement()
|
"try" -> parseTryStatement()
|
||||||
"throw" -> parseThrowStatement()
|
"throw" -> parseThrowStatement()
|
||||||
"when" -> parseWhenStatement()
|
"when" -> parseWhenStatement()
|
||||||
@ -1145,7 +1147,40 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun parseClassDeclaration(isStruct: Boolean): Statement {
|
private fun parseEnumDeclaration(): Statement {
|
||||||
|
val nameToken = cc.requireToken(Token.Type.ID)
|
||||||
|
// so far only simplest enums:
|
||||||
|
val names = mutableListOf<String>()
|
||||||
|
// skip '{'
|
||||||
|
cc.skipTokenOfType(Token.Type.LBRACE)
|
||||||
|
|
||||||
|
do {
|
||||||
|
val t = cc.skipWsTokens()
|
||||||
|
when(t.type) {
|
||||||
|
Token.Type.ID -> {
|
||||||
|
names += t.value
|
||||||
|
val t1 = cc.skipWsTokens()
|
||||||
|
when(t1.type) {
|
||||||
|
Token.Type.COMMA ->
|
||||||
|
continue
|
||||||
|
Token.Type.RBRACE -> break
|
||||||
|
else -> {
|
||||||
|
t1.raiseSyntax("unexpected token")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> t.raiseSyntax("expected enum entry name")
|
||||||
|
}
|
||||||
|
} while(true)
|
||||||
|
|
||||||
|
return statement {
|
||||||
|
ObjEnumClass.createSimpleEnum(nameToken.value, names).also {
|
||||||
|
addItem(nameToken.value, false, it, recordType = ObjRecord.Type.Enum)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun parseClassDeclaration(): Statement {
|
||||||
val nameToken = cc.requireToken(Token.Type.ID)
|
val nameToken = cc.requireToken(Token.Type.ID)
|
||||||
val constructorArgsDeclaration =
|
val constructorArgsDeclaration =
|
||||||
if (cc.skipTokenOfType(Token.Type.LPAREN, isOptional = true))
|
if (cc.skipTokenOfType(Token.Type.LPAREN, isOptional = true))
|
||||||
@ -1178,8 +1213,8 @@ class Compiler(
|
|||||||
// create class
|
// create class
|
||||||
val className = nameToken.value
|
val className = nameToken.value
|
||||||
|
|
||||||
@Suppress("UNUSED_VARIABLE") val defaultAccess = if (isStruct) AccessType.Var else AccessType.Initialization
|
// @Suppress("UNUSED_VARIABLE") val defaultAccess = if (isStruct) AccessType.Var else AccessType.Initialization
|
||||||
@Suppress("UNUSED_VARIABLE") val defaultVisibility = Visibility.Public
|
// @Suppress("UNUSED_VARIABLE") val defaultVisibility = Visibility.Public
|
||||||
|
|
||||||
// create instance constructor
|
// create instance constructor
|
||||||
// create custom objClass with all fields and instance constructor
|
// create custom objClass with all fields and instance constructor
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package net.sergeych.lyng
|
package net.sergeych.lyng
|
||||||
|
|
||||||
data class Token(val value: String, val pos: Pos, val type: Type) {
|
data class Token(val value: String, val pos: Pos, val type: Type) {
|
||||||
|
fun raiseSyntax(text: String): Nothing {
|
||||||
|
throw ScriptError(pos, text)
|
||||||
|
}
|
||||||
|
|
||||||
val isComment: Boolean by lazy { type == Type.SINLGE_LINE_COMMENT || type == Type.MULTILINE_COMMENT }
|
val isComment: Boolean by lazy { type == Type.SINLGE_LINE_COMMENT || type == Type.MULTILINE_COMMENT }
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
|
@ -0,0 +1,62 @@
|
|||||||
|
import net.sergeych.lyng.Scope
|
||||||
|
import net.sergeych.lyng.obj.*
|
||||||
|
import net.sergeych.lynon.LynonDecoder
|
||||||
|
import net.sergeych.lynon.LynonEncoder
|
||||||
|
import net.sergeych.lynon.LynonType
|
||||||
|
|
||||||
|
open class ObjEnumEntry(enumClass: ObjEnumClass, val name: ObjString, val ordinal: ObjInt) : Obj() {
|
||||||
|
override val objClass = enumClass
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "$objClass.$name"
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun serialize(scope: Scope, encoder: LynonEncoder, lynonType: LynonType?) {
|
||||||
|
encoder.encodeUnsigned(ordinal.value.toULong())
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun compareTo(scope: Scope, other: Obj): Int {
|
||||||
|
if( other !is ObjEnumEntry) return -2
|
||||||
|
if( other.objClass != objClass ) return -2
|
||||||
|
return ordinal.compareTo(scope, other.ordinal)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object EnumBase : ObjClass("Enum") {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ObjEnumClass(val name: String) : ObjClass(name, EnumBase) {
|
||||||
|
val objEntries = ObjList()
|
||||||
|
val byName by lazy { objEntries.list.associateBy { (it as ObjEnumEntry).name } }
|
||||||
|
|
||||||
|
init {
|
||||||
|
addClassConst("entries", objEntries )
|
||||||
|
addClassFn("valueOf") {
|
||||||
|
val name = requireOnlyArg<ObjString>()
|
||||||
|
byName[name] ?: raiseSymbolNotFound("does not exists: enum ${className}.$name")
|
||||||
|
}
|
||||||
|
addFn("name") { thisAs<ObjEnumEntry>().name }
|
||||||
|
addFn("ordinal") { thisAs<ObjEnumEntry>().ordinal }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj {
|
||||||
|
val index = decoder.unpackUnsigned().toInt()
|
||||||
|
return objEntries.list[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun createSimpleEnum(enumName: String, names: List<String>): ObjEnumClass {
|
||||||
|
val klass = ObjEnumClass(enumName)
|
||||||
|
names.forEachIndexed { index, name ->
|
||||||
|
val entry = ObjEnumEntry(klass, ObjString(name), ObjInt(index.toLong(), isConst = true))
|
||||||
|
klass.objEntries.list += entry
|
||||||
|
klass.addClassConst(name, entry)
|
||||||
|
}
|
||||||
|
return klass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -19,6 +19,9 @@ data class ObjRecord(
|
|||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
Fun,
|
Fun,
|
||||||
ConstructorField(true, true),
|
ConstructorField(true, true),
|
||||||
|
@Suppress("unused")
|
||||||
|
Class,
|
||||||
|
Enum,
|
||||||
Other
|
Other
|
||||||
}
|
}
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
|
@ -2855,4 +2855,45 @@ class ScriptTest {
|
|||||||
""".trimIndent())
|
""".trimIndent())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun enumTest() = runTest {
|
||||||
|
eval(
|
||||||
|
"""
|
||||||
|
enum Color {
|
||||||
|
RED, GREEN, BLUE
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( Color.RED is Color )
|
||||||
|
assertEquals( 2, Color.BLUE.ordinal )
|
||||||
|
assertEquals( "BLUE", Color.BLUE.name )
|
||||||
|
|
||||||
|
assertEquals( [Color.RED,Color.GREEN,Color.BLUE], Color.entries)
|
||||||
|
|
||||||
|
assertEquals( Color.valueOf("GREEN"), Color.GREEN )
|
||||||
|
|
||||||
|
|
||||||
|
""".trimIndent())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun enumSerializationTest() = runTest {
|
||||||
|
eval("""
|
||||||
|
import lyng.serialization
|
||||||
|
|
||||||
|
enum Color {
|
||||||
|
RED, GREEN, BLUE
|
||||||
|
}
|
||||||
|
|
||||||
|
val e = Lynon.encode(Color.BLUE)
|
||||||
|
assertEquals( Color.BLUE, Lynon.decode(e) )
|
||||||
|
println(e.toDump())
|
||||||
|
|
||||||
|
val e1 = Lynon.encode( (1..100).map { Color.GREEN } )
|
||||||
|
println(e1.toDump())
|
||||||
|
println(Lynon.encode( (1..100).map { "RED" } ).toDump() )
|
||||||
|
|
||||||
|
""".trimIndent())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user