Skip to content

Commit

Permalink
Fix hashCode for TupleType, make error messages/types consistent, use…
Browse files Browse the repository at this point in the history
… compact syntax for single-line functions, start using string templates
  • Loading branch information
JPercival committed Dec 12, 2024
1 parent 02f9aef commit 01a010c
Show file tree
Hide file tree
Showing 16 changed files with 117 additions and 194 deletions.
10 changes: 4 additions & 6 deletions Src/java/model/src/main/java/org/hl7/cql/model/BaseDataType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ package org.hl7.cql.model
abstract class BaseDataType protected constructor(baseType: DataType? = DataType.ANY) : DataType {
override val baseType: DataType = baseType ?: DataType.ANY

override fun toLabel(): String {
return toString()
}
override fun toLabel(): String = toString()

override fun isSubTypeOf(other: DataType): Boolean {
var currentType: DataType = this
Expand Down Expand Up @@ -51,11 +49,11 @@ abstract class BaseDataType protected constructor(baseType: DataType? = DataType
// type compatibility is used to support implicit casting, such as casting a "null"
// literal to any other type, or casting a class to an equivalent tuple.
override fun isCompatibleWith(other: DataType): Boolean {
return when {
return when (other) {
// Any data type is compatible with itself
this == other -> true
this -> true
// A type is compatible with a choice type if it is a subtype of one of the choice types
other is ChoiceType -> other.types.any { this.isSubTypeOf(it) }
is ChoiceType -> other.types.any { this.isSubTypeOf(it) }
else -> false
}
}
Expand Down
15 changes: 5 additions & 10 deletions Src/java/model/src/main/java/org/hl7/cql/model/ChoiceType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,11 @@ data class ChoiceType private constructor(val types: Set<DataType>) : BaseDataTy
}
}

fun isSubSetOf(other: ChoiceType): Boolean {
// every type in this choice is a subtype of some type in the other choice
return types.all { x -> other.types.any { x.isSubTypeOf(it) } }
}
// every type in this choice is a subtype of some type in the other choice
fun isSubSetOf(other: ChoiceType): Boolean =
types.all { x -> other.types.any { x.isSubTypeOf(it) } }

fun isSuperSetOf(other: ChoiceType): Boolean {
return other.isSubSetOf(this)
}
fun isSuperSetOf(other: ChoiceType): Boolean = other.isSubSetOf(this)

override fun isCompatibleWith(other: DataType): Boolean {
// This type is compatible with the other type if
Expand All @@ -38,9 +35,7 @@ data class ChoiceType private constructor(val types: Set<DataType>) : BaseDataTy
}
}

override fun toString(): String {
return types.joinToString(",", "choice<", ">")
}
override fun toString(): String = types.joinToString(",", "choice<", ">")

override val isGeneric: Boolean = types.any { it.isGeneric }

Expand Down
4 changes: 2 additions & 2 deletions Src/java/model/src/main/java/org/hl7/cql/model/ClassType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ constructor(
var genericParameters: MutableList<TypeParameter> = mutableListOf()
) : BaseDataType(baseType), NamedType {
init {
require(name.isNotEmpty()) { "A class type must have a name." }
require(name.isNotEmpty()) { "name can not be empty" }
}

override val namespace: String
Expand Down Expand Up @@ -142,7 +142,7 @@ constructor(
}

val sortedElements: List<ClassTypeElement>
get() = elements.sortedWith { o1, o2 -> o1.name.compareTo(o2.name) }
get() = elements.sortedWith(compareBy { it.name })

private var baseElementMap: LinkedHashMap<String, ClassTypeElement>? = null
get() {
Expand Down
28 changes: 12 additions & 16 deletions Src/java/model/src/main/java/org/hl7/cql/model/ClassTypeElement.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,22 @@ data class ClassTypeElement(
) {

init {
require(name.isNotEmpty()) { "A class type element must have a name." }
require(name.isNotEmpty()) { "name can not be empty" }
}

fun isSubTypeOf(that: ClassTypeElement): Boolean {
return this.name == that.name && type.isSubTypeOf(that.type)
}
fun isSubTypeOf(that: ClassTypeElement): Boolean =
this.name == that.name && type.isSubTypeOf(that.type)

fun isSuperTypeOf(that: ClassTypeElement): Boolean {
return this.name == that.name && type.isSuperTypeOf(that.type)
}
fun isSuperTypeOf(that: ClassTypeElement): Boolean =
this.name == that.name && type.isSuperTypeOf(that.type)

override fun toString(): String {
return String.format(
Locale.US,
"%s:%s%s%s%s",
this.name,
type.toString(),
if (this.prohibited) " (prohibited)" else "",
if (this.oneBased) " (one-based)" else "",
if (this.target != null) " (target: " + this.target + ")" else ""
)
return "$name:$type$%s%s%s"
.format(
Locale.US,
if (this.prohibited) " (prohibited)" else "",
if (this.oneBased) " (one-based)" else "",
if (this.target != null) " (target: " + this.target + ")" else ""
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class GenericClassSignatureParser(
private fun handleParameterDeclaration(parameterString: String): TypeParameter {
val paramComponents = parameterString.split("\\s+".toRegex()).dropLastWhile { it.isEmpty() }
return if (paramComponents.size == 1) {
TypeParameter(parameterString.trim(), TypeParameter.TypeParameterConstraint.NONE, null)
TypeParameter(parameterString.trim(), TypeParameter.TypeParameterConstraint.NONE)
} else if (paramComponents.size == 3) {
if (paramComponents[1].equals(EXTENDS, ignoreCase = true)) {
TypeParameter(
Expand Down Expand Up @@ -138,49 +138,53 @@ class GenericClassSignatureParser(
private fun handleBoundType(boundGenericSignature: String): DataType {
var resolvedType =
resolvedTypes[escapeNestedAngleBrackets(boundGenericSignature)] as? ClassType
if (resolvedType != null) {
return resolvedType
} else {
val genericTypeName =
boundGenericSignature.substring(0, boundGenericSignature.indexOf('<'))
resolvedType = resolveType(genericTypeName) as ClassType
val newType = ClassType(escapeNestedAngleBrackets(boundGenericSignature), resolvedType)
val parameters =
boundGenericSignature.substring(
boundGenericSignature.indexOf('<') + 1,
boundGenericSignature.lastIndexOf('>')
)
val params =
escapeNestedCommas(parameters).split(",".toRegex()).dropLastWhile { it.isEmpty() }
for ((index, param) in params.withIndex()) {
var boundParam: DataType?
val unescaped = unescapeNestedCommas(param)
boundParam =
if (isValidGenericSignature(unescaped)) {
handleBoundType(unescaped)
} else {
resolveType(unescaped)
return when {
resolvedType != null -> resolvedType
else -> {
val genericTypeName =
boundGenericSignature.substring(0, boundGenericSignature.indexOf('<'))
resolvedType = resolveType(genericTypeName) as ClassType
val newType =
ClassType(escapeNestedAngleBrackets(boundGenericSignature), resolvedType)
val parameters =
boundGenericSignature.substring(
boundGenericSignature.indexOf('<') + 1,
boundGenericSignature.lastIndexOf('>')
)
val params =
escapeNestedCommas(parameters).split(",".toRegex()).dropLastWhile {
it.isEmpty()
}
val typeParameter = resolvedType.genericParameters[index]
for ((name, type) in resolvedType.elements) {
if (
type is TypeParameter &&
type.identifier.equals(typeParameter.identifier, ignoreCase = true)
) {
val newElement =
ClassTypeElement(
name,
boundParam,
prohibited = false,
oneBased = false,
target = null
)
newType.addElement(newElement)
for ((index, param) in params.withIndex()) {
var boundParam: DataType?
val unescaped = unescapeNestedCommas(param)
boundParam =
if (isValidGenericSignature(unescaped)) {
handleBoundType(unescaped)
} else {
resolveType(unescaped)
}
val typeParameter = resolvedType.genericParameters[index]
for ((name, type) in resolvedType.elements) {
if (
type is TypeParameter &&
type.identifier.equals(typeParameter.identifier, ignoreCase = true)
) {
val newElement =
ClassTypeElement(
name,
boundParam,
prohibited = false,
oneBased = false,
target = null
)
newType.addElement(newElement)
}
}
}
resolvedTypes[newType.name] = newType
newType
}
resolvedTypes[newType.name] = newType
return newType
}
}

Expand Down Expand Up @@ -260,12 +264,10 @@ class GenericClassSignatureParser(
var openBracketCount = 0
for (index in signatureCharArray.indices) {
val c = signatureCharArray[index]
if (c == '<') {
openBracketCount++
} else if (c == '>') {
openBracketCount--
} else if (c == ',' && openBracketCount > 0) {
signatureCharArray[index] = '|'
when {
c == '<' -> openBracketCount++
c == '>' -> openBracketCount--
c == ',' && openBracketCount > 0 -> signatureCharArray[index] = '|'
}
}
return String(signatureCharArray)
Expand Down
29 changes: 7 additions & 22 deletions Src/java/model/src/main/java/org/hl7/cql/model/IntervalType.kt
Original file line number Diff line number Diff line change
@@ -1,35 +1,25 @@
package org.hl7.cql.model

import java.util.*
import org.hl7.cql.model.DataType.Companion.ANY

data class IntervalType(val pointType: DataType) : BaseDataType() {
override fun isSubTypeOf(other: DataType): Boolean {
return if (other is IntervalType) {
return pointType.isSubTypeOf(other.pointType)
} else {
super.isSubTypeOf(other)
}
} else super.isSubTypeOf(other)
}

override fun isSuperTypeOf(other: DataType): Boolean {
return if (other is IntervalType) {
return pointType.isSuperTypeOf(other.pointType)
} else {
super.isSuperTypeOf(other)
}
} else super.isSuperTypeOf(other)
}

override fun toString(): String {
return String.format(Locale.US, "interval<%s>", pointType.toString())
}
override fun toString(): String = "interval<$pointType>"

override fun toLabel(): String {
return String.format(Locale.US, "Interval of %s", pointType.toLabel())
}
override fun toLabel(): String = "Interval of ${pointType.toLabel()}"

override val isGeneric: Boolean
get() = pointType.isGeneric
override val isGeneric: Boolean = pointType.isGeneric

override fun isInstantiable(callType: DataType, context: InstantiationContext): Boolean {
return when (callType) {
Expand All @@ -40,13 +30,8 @@ data class IntervalType(val pointType: DataType) : BaseDataType() {
context.getIntervalConversionTargets(callType).filter {
pointType.isInstantiable(it.pointType, context)
}
require(instantiableElements.size <= 1) {
String.format(
Locale.US,
"Ambiguous generic instantiation involving %s to %s.",
callType.toString(),
instantiableElements.toString()
)
check(instantiableElements.size <= 1) {
"Ambiguous generic instantiation involving $callType to $instantiableElements"
}

instantiableElements.isNotEmpty()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,12 @@
package org.hl7.cql.model

import java.util.*

class InvalidRedeclarationException : IllegalArgumentException {
constructor() : super()

constructor(s: String?) : super(s)

constructor(
classType: ClassType,
original: ClassTypeElement,
redeclared: ClassTypeElement
) : super(
String.format(
Locale.US,
"%s.%s cannot be redeclared with type %s because it is not a subtype of the original element type %s",
classType.name,
redeclared.name,
redeclared.type,
original.type
)
class InvalidRedeclarationException(
classType: ClassType,
original: ClassTypeElement,
redeclared: ClassTypeElement
) :
IllegalArgumentException(
"""${classType.name}.${redeclared.name} cannot be redeclared
with type ${redeclared.type} because it is not a subtype
of the original element type ${original.type} in class ${classType.name}"""
.trimIndent()
)
}
26 changes: 6 additions & 20 deletions Src/java/model/src/main/java/org/hl7/cql/model/ListType.kt
Original file line number Diff line number Diff line change
@@ -1,32 +1,23 @@
package org.hl7.cql.model

import java.util.*
import org.hl7.cql.model.DataType.Companion.ANY

data class ListType(val elementType: DataType) : BaseDataType() {
override fun isSubTypeOf(other: DataType): Boolean {
return if (other is ListType) {
elementType.isSubTypeOf(other.elementType)
} else {
super.isSubTypeOf(other)
}
} else super.isSubTypeOf(other)
}

override fun isSuperTypeOf(other: DataType): Boolean {
return if (other is ListType) {
elementType.isSuperTypeOf(other.elementType)
} else {
super.isSuperTypeOf(other)
}
} else super.isSuperTypeOf(other)
}

override fun toString(): String {
return String.format(Locale.US, "list<%s>", elementType.toString())
}
override fun toString(): String = "list<${elementType}>"

override fun toLabel(): String {
return String.format(Locale.US, "List of %s", elementType.toLabel())
}
override fun toLabel(): String = "List of ${elementType.toLabel()}"

override val isGeneric: Boolean = elementType.isGeneric

Expand All @@ -39,13 +30,8 @@ data class ListType(val elementType: DataType) : BaseDataType() {
context.getListConversionTargets(callType).filter {
elementType.isInstantiable(it.elementType, context)
}
require(instantiableElements.size <= 1) {
String.format(
Locale.US,
"Ambiguous generic instantiation involving %s to %s.",
callType.toString(),
instantiableElements.toString()
)
check(instantiableElements.size <= 1) {
"Ambiguous generic instantiation involving $callType to $instantiableElements"
}

instantiableElements.isNotEmpty()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ data class ModelIdentifier(
@XmlAttribute(name = "version") var version: String? = null
) {
init {
require(id.isNotEmpty()) { "id is required" }
require(id.isNotEmpty()) { "id can not be empty" }
}
}
Loading

0 comments on commit 01a010c

Please sign in to comment.