Skip to content

Commit

Permalink
Rename EnumByLabel & Co to EnumVariant and document them
Browse files Browse the repository at this point in the history
  • Loading branch information
Mingun committed Jul 19, 2024
1 parent 54524e1 commit d467d6c
Show file tree
Hide file tree
Showing 21 changed files with 65 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,12 @@ class ExpressionsSpec extends AnyFunSpec {

// Enums
it("parses port::http") {
Expressions.parse("port::http") should be (EnumByLabel(identifier("port"), identifier("http")))
Expressions.parse("port::http") should be (EnumVariant(identifier("port"), identifier("http")))
}

it("parses some_type::port::http") {
Expressions.parse("some_type::port::http") should be (
EnumByLabel(
EnumVariant(
identifier("port"),
identifier("http"),
typeId(absolute = false, Seq("some_type"))
Expand All @@ -148,7 +148,7 @@ class ExpressionsSpec extends AnyFunSpec {

it("parses parent_type::child_type::port::http") {
Expressions.parse("parent_type::child_type::port::http") should be (
EnumByLabel(
EnumVariant(
identifier("port"),
identifier("http"),
typeId(absolute = false, Seq("parent_type", "child_type"))
Expand All @@ -158,7 +158,7 @@ class ExpressionsSpec extends AnyFunSpec {

it("parses ::parent_type::child_type::port::http") {
Expressions.parse("::parent_type::child_type::port::http") should be (
EnumByLabel(
EnumVariant(
identifier("port"),
identifier("http"),
typeId(absolute = true, Seq("parent_type", "child_type"))
Expand All @@ -171,7 +171,7 @@ class ExpressionsSpec extends AnyFunSpec {
Compare(
BinOp(
Attribute(
EnumByLabel(identifier("port"),identifier("http")),
EnumVariant(identifier("port"),identifier("http")),
identifier("to_i")
),
Add,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ class GraphvizClassCompiler(classSpecs: ClassSpecs, topClass: ClassSpec) extends
// case expr.Call(func, args) =>
case Ast.expr.IntNum(_) | Ast.expr.FloatNum(_) | Ast.expr.Str(_) | Ast.expr.Bool(_) =>
List()
case _: Ast.expr.EnumByLabel =>
case _: Ast.expr.EnumVariant =>
List()
case Ast.expr.EnumById(_, id, _) =>
affectedVars(id)
Expand Down
9 changes: 8 additions & 1 deletion shared/src/main/scala/io/kaitai/struct/exprlang/Ast.scala
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,14 @@ object Ast {
case class FloatNum(n: BigDecimal) extends expr
case class Str(s: String) extends expr
case class Bool(n: Boolean) extends expr
case class EnumByLabel(enumName: identifier, label: identifier, inType: typeId = EmptyTypeId) extends expr
/**
* Reference to the enum variant `variant` in the enumeration `enumName`,
* defined in the type `inType`. In expression language represented as
* `enumName::variant` or `<type-path>::enumName::variant` where `<type-path>`
* can be an absolute or a relative path to the type, defined in the current
* KSY file.
*/
case class EnumVariant(enumName: identifier, variant: identifier, inType: typeId = EmptyTypeId) extends expr
case class EnumById(enumName: identifier, id: expr, inType: typeId = EmptyTypeId) extends expr

case class Attribute(value: expr, attr: identifier) extends expr
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ object Expressions {
"(" ~ test ~ ")" |
"[" ~ list ~ "]" |
// "{" ~ dictorsetmaker ~ "}" |
enumByName |
enumVariant |
byteSizeOfType |
bitSizeOfType |
fstring |
Expand Down Expand Up @@ -167,17 +167,18 @@ object Expressions {

def testlist1[$: P]: P[Seq[Ast.expr]] = P( test.rep(1, sep = ",") )

def enumByName[$: P]: P[Ast.expr.EnumByLabel] = P("::".!.? ~ NAME.rep(2, "::")).map {
/** Parses reference to an enumeration variant. */
def enumVariant[$: P]: P[Ast.expr.EnumVariant] = P("::".!.? ~ NAME.rep(2, "::")).map {
case (first, names: Seq[Ast.identifier]) =>
val isAbsolute = first.nonEmpty
val (enumName, enumLabel) = names.takeRight(2) match {
val (enumName, variant) = names.takeRight(2) match {
case Seq(a, b) => (a, b)
}
val typePath = names.dropRight(2)
if (typePath.isEmpty) {
Ast.expr.EnumByLabel(enumName, enumLabel, Ast.EmptyTypeId)
Ast.expr.EnumVariant(enumName, variant, Ast.EmptyTypeId)
} else {
Ast.expr.EnumByLabel(enumName, enumLabel, Ast.typeId(isAbsolute, typePath.map(_.name)))
Ast.expr.EnumVariant(enumName, variant, Ast.typeId(isAbsolute, typePath.map(_.name)))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -576,10 +576,10 @@ class JavaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
// Java is very specific about what can be used as "condition" in "case
// condition:".
val condStr = condition match {
case enumByLabel: Ast.expr.EnumByLabel =>
case variant: Ast.expr.EnumVariant =>
// If switch is over a enum, only literal enum values are supported,
// and they must be written as "MEMBER", not "SomeEnum.MEMBER".
value2Const(enumByLabel.label.name)
value2Const(variant.variant.name)
case _ =>
expression(condition)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ abstract class BaseTranslator(val provider: TypeProvider)
case Ast.expr.EnumById(enumType, id, inType) =>
val enumSpec = provider.resolveEnum(inType, enumType.name)
doEnumById(enumSpec, translate(id))
case Ast.expr.EnumByLabel(enumType, label, inType) =>
case Ast.expr.EnumVariant(enumType, variant, inType) =>
val enumSpec = provider.resolveEnum(inType, enumType.name)
doEnumByLabel(enumSpec, label.name)
doEnumVariant(enumSpec, variant.name)
case Ast.expr.Name(name: Ast.identifier) =>
if (name.name == Identifier.SIZEOF) {
byteSizeOfClassSpec(provider.nowClass)
Expand Down Expand Up @@ -186,7 +186,15 @@ abstract class BaseTranslator(val provider: TypeProvider)
def kaitaiStructField(value: Ast.expr, name: String): String =
anyField(value, name)

def doEnumByLabel(enumSpec: EnumSpec, label: String): String
/**
* Translates reference to the enum variant into target language
*
* @param enumSpec An enum definition
* @param variant Enum variant
*
* @return String in the target language with reference to the enum variant
*/
def doEnumVariant(enumSpec: EnumSpec, variant: String): String
def doEnumById(enumSpec: EnumSpec, id: String): String

// Predefined methods of various types
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ class CSharpTranslator(provider: TypeProvider, importList: ImportList) extends B
override def doInternalName(id: Identifier): String =
CSharpCompiler.privateMemberName(id)

override def doEnumByLabel(enumSpec: EnumSpec, label: String): String =
s"${enumClass(enumSpec.name)}.${Utils.upperCamelCase(label)}"
override def doEnumVariant(enumSpec: EnumSpec, variant: String): String =
s"${enumClass(enumSpec.name)}.${Utils.upperCamelCase(variant)}"
override def doEnumById(enumSpec: EnumSpec, id: String): String =
s"((${enumClass(enumSpec.name)}) $id)"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ class ConstructTranslator(provider: TypeProvider, importList: ImportList) extend
}
}

override def doEnumByLabel(enumSpec: EnumSpec, label: String): String =
s"'$label'"
override def doEnumVariant(enumSpec: EnumSpec, variant: String): String =
s"'$variant'"

override def kaitaiStreamSize(value: Ast.expr): String =
s"stream_size(${translate(value)})"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,13 @@ class CppTranslator(provider: TypeProvider, importListSrc: CppImportList, import
override def doInternalName(id: Identifier): String =
CppCompiler.privateMemberName(id)

override def doEnumByLabel(enumSpec: EnumSpec, label: String): String = {
override def doEnumVariant(enumSpec: EnumSpec, variant: String): String = {
val isExternal = enumSpec.isExternal(provider.nowClass)
if (isExternal) {
importListHdr.addLocal(CppCompiler.outFileNameHeader(enumSpec.name.head))
}
CppCompiler.types2class(enumSpec.name.dropRight(1)) + "::" +
Utils.upperUnderscoreCase(enumSpec.name.last + "_" + label)
Utils.upperUnderscoreCase(enumSpec.name.last + "_" + variant)
}
override def doEnumById(enumSpec: EnumSpec, id: String): String =
s"static_cast<${CppCompiler.types2class(enumSpec.name)}>($id)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ class ExpressionValidator(val provider: TypeProvider)
case Ast.expr.EnumById(enumType, id, inType) =>
provider.resolveEnum(inType, enumType.name)
validate(id)
case Ast.expr.EnumByLabel(enumType, label, inType) =>
case Ast.expr.EnumVariant(enumType, variant, inType) =>
val enumSpec = provider.resolveEnum(inType, enumType.name)
if (!enumSpec.map.values.exists(_.name == label.name)) {
throw new EnumMemberNotFoundError(label.name, enumType.name, enumSpec.path.mkString("/"))
if (!enumSpec.map.values.exists(_.name == variant.name)) {
throw new EnumMemberNotFoundError(variant.name, enumType.name, enumSpec.path.mkString("/"))
}
case Ast.expr.Name(name: Ast.identifier) =>
if (name.name == Identifier.SIZEOF) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ class GoTranslator(out: StringLanguageOutputWriter, provider: TypeProvider, impo
case Ast.expr.EnumById(enumType, id, inType) =>
val enumSpec = provider.resolveEnum(inType, enumType.name)
trEnumById(enumSpec.name, translate(id))
case Ast.expr.EnumByLabel(enumType, label, inType) =>
case Ast.expr.EnumVariant(enumType, variant, inType) =>
val enumSpec = provider.resolveEnum(inType, enumType.name)
trEnumByLabel(enumSpec.name, label.name)
trEnumVariant(enumSpec.name, variant.name)
case Ast.expr.Name(name: Ast.identifier) =>
if (name.name == Identifier.SIZEOF) {
byteSizeOfClassSpec(provider.nowClass)
Expand Down Expand Up @@ -253,8 +253,8 @@ class GoTranslator(out: StringLanguageOutputWriter, provider: TypeProvider, impo
ResultLocalVar(v1)
}

def trEnumByLabel(enumTypeAbs: List[String], label: String) =
ResultString(GoCompiler.enumToStr(enumTypeAbs, label))
def trEnumVariant(enumTypeAbs: List[String], variant: String) =
ResultString(GoCompiler.enumToStr(enumTypeAbs, variant))
def trEnumById(enumTypeAbs: List[String], id: String) =
ResultString(s"${types2class(enumTypeAbs)}($id)")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,13 @@ class JavaScriptTranslator(provider: TypeProvider, importList: ImportList) exten
override def doInternalName(id: Identifier): String =
JavaScriptCompiler.privateMemberName(id)

override def doEnumByLabel(enumSpec: EnumSpec, label: String): String = {
override def doEnumVariant(enumSpec: EnumSpec, variant: String): String = {
val isExternal = enumSpec.isExternal(provider.nowClass)
if (isExternal) {
val className = JavaScriptCompiler.type2class(enumSpec.name.head)
importList.add(s"./$className")
}
s"${JavaScriptCompiler.types2class(enumSpec.name, isExternal)}.${Utils.upperUnderscoreCase(label)}"
s"${JavaScriptCompiler.types2class(enumSpec.name, isExternal)}.${Utils.upperUnderscoreCase(variant)}"
}
override def doEnumById(enumSpec: EnumSpec, id: String): String =
// Just an integer, without any casts / resolutions - one would have to look up constants manually
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ class JavaTranslator(provider: TypeProvider, importList: ImportList) extends Bas
override def doInternalName(id: Identifier): String =
JavaCompiler.privateMemberName(id)

override def doEnumByLabel(enumSpec: EnumSpec, label: String): String =
s"${enumClass(enumSpec.name)}.${Utils.upperUnderscoreCase(label)}"
override def doEnumVariant(enumSpec: EnumSpec, variant: String): String =
s"${enumClass(enumSpec.name)}.${Utils.upperUnderscoreCase(variant)}"
override def doEnumById(enumSpec: EnumSpec, id: String): String =
s"${enumClass(enumSpec.name)}.byId($id)"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ class LuaTranslator(provider: TypeProvider, importList: ImportList) extends Base
override def doInternalName(id: Identifier): String =
LuaCompiler.privateMemberName(id)

override def doEnumByLabel(enumSpec: EnumSpec, label: String): String =
s"${LuaCompiler.types2class(enumSpec.name)}.$label"
override def doEnumVariant(enumSpec: EnumSpec, variant: String): String =
s"${LuaCompiler.types2class(enumSpec.name)}.$variant"
override def doEnumById(enumSpec: EnumSpec, id: String): String =
s"${LuaCompiler.types2class(enumSpec.name)}($id)"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ class NimTranslator(provider: TypeProvider, importList: ImportList) extends Base
s"""encode($bytesExpr, ${doStringLiteral(encoding)})"""
}
override def doEnumById(enumSpec: EnumSpec, id: String): String = s"${namespaced(enumSpec.name)}($id)"
// override def doEnumByLabel(enumSpec: EnumSpec, label: String): String = s"${namespaced(enumSpec.name)}($label)"
override def doEnumByLabel(enumSpec: EnumSpec, label: String): String = s"${enumSpec.name.head}.$label"
// override def doEnumVariant(enumSpec: EnumSpec, variant: String): String = s"${namespaced(enumSpec.name)}($variant)"
override def doEnumVariant(enumSpec: EnumSpec, variant: String): String = s"${enumSpec.name.head}.$variant"
override def doName(s: String): String =
s match {
case Identifier.ROOT => "root"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ class PHPTranslator(provider: TypeProvider, config: RuntimeConfig) extends BaseT
override def doInternalName(id: Identifier): String =
PHPCompiler.privateMemberName(id)

override def doEnumByLabel(enumSpec: EnumSpec, label: String): String = {
override def doEnumVariant(enumSpec: EnumSpec, variant: String): String = {
val enumClass = types2classAbs(enumSpec.name)
s"$enumClass::${Utils.upperUnderscoreCase(label)}"
s"$enumClass::${Utils.upperUnderscoreCase(variant)}"
}
override def doEnumById(enumSpec: EnumSpec, id: String): String =
// Just an integer, without any casts / resolutions - one would have to look up constants manually
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,15 @@ class PerlTranslator(provider: TypeProvider, importList: ImportList) extends Bas
override def doInternalName(id: Identifier): String =
PerlCompiler.privateMemberName(id)

override def doEnumByLabel(enumSpec: EnumSpec, label: String): String = {
override def doEnumVariant(enumSpec: EnumSpec, variant: String): String = {
val isExternal = enumSpec.isExternal(provider.nowClass)
if (isExternal) {
importList.add(PerlCompiler.type2class(enumSpec.name.head))
}
val enumClass = PerlCompiler.types2class(enumSpec.name.init)
val enumClassWithScope = if (enumClass.isEmpty) "" else s"$enumClass::"
val enumName = Utils.upperUnderscoreCase(enumSpec.name.last)
s"$$$enumClassWithScope${enumName}_${Utils.upperUnderscoreCase(label)}"
s"$$$enumClassWithScope${enumName}_${Utils.upperUnderscoreCase(variant)}"
}
override def doEnumById(enumSpec: EnumSpec, id: String): String =
// Just an integer, without any casts / resolutions - one would have to look up constants manually
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ class PythonTranslator(provider: TypeProvider, importList: ImportList, config: R
override def doInternalName(id: Identifier): String =
PythonCompiler.privateMemberName(id)

override def doEnumByLabel(enumSpec: EnumSpec, label: String): String = {
override def doEnumVariant(enumSpec: EnumSpec, variant: String): String = {
val isExternal = enumSpec.isExternal(provider.nowClass)
if (isExternal) {
PythonCompiler.externalTypeDeclaration(ExternalEnum(enumSpec), importList, config)
}
s"${PythonCompiler.types2class(enumSpec.name, isExternal)}.$label"
s"${PythonCompiler.types2class(enumSpec.name, isExternal)}.$variant"
}
override def doEnumById(enumSpec: EnumSpec, id: String): String =
s"${PythonCompiler.kstreamName}.resolve_enum(${PythonCompiler.types2class(enumSpec.name, enumSpec.isExternal(provider.nowClass))}, $id)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ class RubyTranslator(provider: TypeProvider) extends BaseTranslator(provider)
override def doInternalName(id: Identifier): String =
RubyCompiler.privateMemberName(id)

override def doEnumByLabel(enumSpec: EnumSpec, label: String): String =
RubyCompiler.enumValue(enumSpec.name.last, label)
override def doEnumVariant(enumSpec: EnumSpec, variant: String): String =
RubyCompiler.enumValue(enumSpec.name.last, variant)
override def doEnumById(enumSpec: EnumSpec, id: String): String =
s"${RubyCompiler.kstreamName}::resolve_enum(${enumDirectMap(enumSpec.name)}, $id)"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ class RustTranslator(provider: TypeProvider, config: RuntimeConfig) extends Base

override def doName(s: String) = s

override def doEnumByLabel(enumSpec: EnumSpec, label: String): String = {
override def doEnumVariant(enumSpec: EnumSpec, variant: String): String = {
val enumClass = types2classAbs(enumSpec.name)
s"$enumClass::${Utils.upperUnderscoreCase(label)}"
s"$enumClass::${Utils.upperUnderscoreCase(variant)}"
}
override def doEnumById(enumSpec: EnumSpec, id: String): String =
// Just an integer, without any casts / resolutions - one would have to look up constants manually
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class TypeDetector(provider: TypeProvider) {
case Ast.expr.Str(_) => CalcStrType
case Ast.expr.InterpolatedStr(_) => CalcStrType
case Ast.expr.Bool(_) => CalcBooleanType
case Ast.expr.EnumByLabel(enumType, _, inType) =>
case Ast.expr.EnumVariant(enumType, _, inType) =>
val t = EnumType(inType.names.toList :+ enumType.name, CalcIntType)
t.enumSpec = Some(provider.resolveEnum(inType, enumType.name))
t
Expand Down

0 comments on commit d467d6c

Please sign in to comment.