in thrifty-schema/src/main/kotlin/com/microsoft/thrifty/schema/Constant.kt [245:316]
override fun validate(symbolTable: SymbolTable, expected: ThriftType, valueElement: ConstValueElement) {
if (expected !is EnumType) {
throw IllegalStateException("bad enum literal")
}
when (valueElement) {
is IntValueElement -> {
val id = valueElement.value
if (expected.members.any { it.value.toLong() == id }) {
return
}
throw IllegalStateException("'$id' is not a valid value for ${expected.name}")
}
is IdentifierValueElement -> {
// An IDENTIFIER enum value could be one of four kinds of entities:
// 1. Another constant, possibly of the correct type
// 2. A fully-qualified imported enum value, e.g. file.Enum.Member
// 3. An imported, partially-qualified enum value, e.g. Enum.Member (where Enum is imported)
// 4. A fully-qualified, non-imported enum value, e.g. Enum.Member
//
// Apache accepts all of these, and so do we.
val id = valueElement.value
// An unusual edge case is when a named constant has the same name as an enum
// member; in this case, constants take precedence over members. Make sure that
// the type is as expected!
val constant = symbolTable.lookupConst(id)
if (constant != null && constant.type.trueType == expected) {
return
}
var ix = id.lastIndexOf('.')
if (ix == -1) {
throw IllegalStateException(
"Unqualified name '$id' is not a valid enum constant value: (${valueElement.location})")
}
val typeName = id.substring(0, ix) // possibly qualified
val memberName = id.substring(ix + 1)
// Does the literal name match the expected type name?
// It could be that typeName is qualified; handle that case.
var typeNameMatches = false
ix = typeName.indexOf('.')
if (ix == -1) {
// unqualified
if (expected.name == typeName) {
typeNameMatches = true
}
} else {
// qualified
val qualifier = typeName.substring(0, ix)
val actualName = typeName.substring(ix + 1)
// Does the qualifier match?
if (expected.location.programName == qualifier && expected.name == actualName) {
typeNameMatches = true
}
}
if (typeNameMatches && expected.members.any { it.name == memberName }) {
return
}
throw IllegalStateException(
"'$id' is not a member of enum type ${expected.name}: members=${expected.members}")
}
else -> throw IllegalStateException("bad enum literal: $valueElement")
}
}