From 650c1ab2d6356d5876bc0fb61cbb5f76324fa82f Mon Sep 17 00:00:00 2001 From: JP Date: Thu, 12 Dec 2024 09:29:26 -0700 Subject: [PATCH] Clean-up of TupleType (#1467) * Clean-up of TupleType * Fix hashcode * Fix hashCode for TupleType, make error messages/types consistent, use compact syntax for single-line functions, start using string templates * Fix exception message * More cleanup --- .../cqframework/cql/cql2elm/Cql2ElmVisitor.kt | 11 ++- .../cql/cql2elm/model/ModelImporter.kt | 5 +- .../CqlPreprocessorElmCommonVisitor.kt | 6 +- .../cql/cql2elm/operators/QueryTest.java | 2 +- .../cql/elm/requirements/TypeResolver.java | 6 +- .../java/org/hl7/cql/model/BaseDataType.kt | 10 +- .../main/java/org/hl7/cql/model/ChoiceType.kt | 15 +-- .../main/java/org/hl7/cql/model/ClassType.kt | 13 +-- .../org/hl7/cql/model/ClassTypeElement.kt | 28 +++--- .../cql/model/GenericClassSignatureParser.kt | 94 ++++++++++--------- .../java/org/hl7/cql/model/IntervalType.kt | 29 ++---- .../model/InvalidRedeclarationException.kt | 32 ++----- .../main/java/org/hl7/cql/model/ListType.kt | 26 ++--- .../java/org/hl7/cql/model/ModelIdentifier.kt | 2 +- .../java/org/hl7/cql/model/NamespaceInfo.kt | 6 +- .../org/hl7/cql/model/NamespaceManager.kt | 12 +-- .../main/java/org/hl7/cql/model/SearchType.kt | 4 +- .../main/java/org/hl7/cql/model/SimpleType.kt | 15 +-- .../main/java/org/hl7/cql/model/TupleType.kt | 71 ++++++-------- .../org/hl7/cql/model/TupleTypeElement.kt | 22 ++--- .../java/org/hl7/cql/model/TypeParameter.kt | 16 ++-- 21 files changed, 169 insertions(+), 256 deletions(-) diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/Cql2ElmVisitor.kt b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/Cql2ElmVisitor.kt index 7a1c03f15..44dfb22a1 100755 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/Cql2ElmVisitor.kt +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/Cql2ElmVisitor.kt @@ -630,13 +630,13 @@ class Cql2ElmVisitor( override fun visitTupleSelector(ctx: TupleSelectorContext): Any? { val tuple = of.createTuple() - val tupleType = TupleType() + val elements = mutableListOf() for (elementContext in ctx.tupleElementSelector()) { val element = visit(elementContext) as TupleElement - tupleType.addElement(TupleTypeElement(element.name, element.resultType!!)) + elements.add(TupleTypeElement(element.name, element.resultType!!)) tuple.element.add(element) } - tuple.resultType = tupleType + tuple.resultType = TupleType(elements) return tuple } @@ -3522,7 +3522,7 @@ class Cql2ElmVisitor( if (agg == null && ret == null && sources.size > 1) { ret = of.createReturnClause().withDistinct(true) val returnExpression = of.createTuple() - val returnType = TupleType() + val elements = mutableListOf() for (aqs: AliasedQuerySource in sources) { val element = of.createTupleElement() @@ -3534,9 +3534,10 @@ class Cql2ElmVisitor( element.value.resultType = sourceType // Doesn't use the fluent API to avoid casting element.resultType = element.value.resultType - returnType.addElement(TupleTypeElement(element.name, element.resultType!!)) + elements.add(TupleTypeElement(element.name, element.resultType!!)) returnExpression.element.add(element) } + val returnType = TupleType(elements) returnExpression.resultType = if (queryContext.isSingular) returnType else ListType(returnType) ret.expression = returnExpression diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/ModelImporter.kt b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/ModelImporter.kt index a2fb966bc..7d652322a 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/ModelImporter.kt +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/ModelImporter.kt @@ -227,15 +227,16 @@ class ModelImporter(val modelInfo: ModelInfo, val modelManager: ModelManager?) { } if (typeSpecifier is TupleTypeSpecifier) { - val tupleType = TupleType() + val elements = mutableListOf() for (specifierElement in typeSpecifier.element) { val element = TupleTypeElement( specifierElement.name, resolveTypeSpecifier(specifierElement.elementType)!! ) - tupleType.addElement(element) + elements.add(element) } + return TupleType(elements) } if (typeSpecifier is ChoiceTypeSpecifier) { diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/preprocessor/CqlPreprocessorElmCommonVisitor.kt b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/preprocessor/CqlPreprocessorElmCommonVisitor.kt index c9812461c..dda52ac59 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/preprocessor/CqlPreprocessorElmCommonVisitor.kt +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/preprocessor/CqlPreprocessorElmCommonVisitor.kt @@ -151,14 +151,14 @@ abstract class CqlPreprocessorElmCommonVisitor( } override fun visitTupleTypeSpecifier(ctx: TupleTypeSpecifierContext): Any { - val resultType = TupleType() + val elements = mutableListOf() val typeSpecifier = of.createTupleTypeSpecifier() for (definitionContext in ctx.tupleElementDefinition()) { val element = visit(definitionContext) as TupleElementDefinition - resultType.addElement(TupleTypeElement(element.name, element.elementType.resultType!!)) + elements.add(TupleTypeElement(element.name, element.elementType.resultType!!)) typeSpecifier.element.add(element) } - typeSpecifier.resultType = resultType + typeSpecifier.resultType = TupleType(elements) return typeSpecifier } diff --git a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/operators/QueryTest.java b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/operators/QueryTest.java index 348f50841..e71444172 100644 --- a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/operators/QueryTest.java +++ b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/operators/QueryTest.java @@ -76,7 +76,7 @@ void mixedMultipleSourceQuery() { def, hasTypeAndResult( Query.class, - "list")); + "list")); } @Test diff --git a/Src/java/elm-fhir/src/main/java/org/cqframework/cql/elm/requirements/TypeResolver.java b/Src/java/elm-fhir/src/main/java/org/cqframework/cql/elm/requirements/TypeResolver.java index 761ec823d..08f38e5a7 100644 --- a/Src/java/elm-fhir/src/main/java/org/cqframework/cql/elm/requirements/TypeResolver.java +++ b/Src/java/elm-fhir/src/main/java/org/cqframework/cql/elm/requirements/TypeResolver.java @@ -133,13 +133,13 @@ private DataType resolveNamedTypeSpecifier(NamedTypeSpecifier typeSpecifier) { } private DataType resolveTupleTypeSpecifier(TupleTypeSpecifier typeSpecifier) { - TupleType tupleType = new TupleType(); + var elements = new ArrayList(); for (TupleElementDefinition element : typeSpecifier.getElement()) { TupleTypeElement tupleElement = new TupleTypeElement(element.getName(), resolveTypeSpecifier(element.getElementType()), false); - tupleType.addElement(tupleElement); + elements.add(tupleElement); } - return tupleType; + return new TupleType(elements); } private DataType resolveIntervalTypeSpecifier(IntervalTypeSpecifier typeSpecifier) { diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/BaseDataType.kt b/Src/java/model/src/main/java/org/hl7/cql/model/BaseDataType.kt index 754b6cd33..ff1328081 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/BaseDataType.kt +++ b/Src/java/model/src/main/java/org/hl7/cql/model/BaseDataType.kt @@ -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 @@ -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 } } diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/ChoiceType.kt b/Src/java/model/src/main/java/org/hl7/cql/model/ChoiceType.kt index bda8b1bd0..b9d4aefcf 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/ChoiceType.kt +++ b/Src/java/model/src/main/java/org/hl7/cql/model/ChoiceType.kt @@ -16,14 +16,11 @@ data class ChoiceType private constructor(val types: Set) : 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 @@ -38,9 +35,7 @@ data class ChoiceType private constructor(val types: Set) : BaseDataTy } } - override fun toString(): String { - return types.joinToString(",", "choice<", ">") - } + override fun toString(): String = types.joinToString(",", "choice<", ">") override val isGeneric: Boolean = types.any { it.isGeneric } diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/ClassType.kt b/Src/java/model/src/main/java/org/hl7/cql/model/ClassType.kt index 4e818c3d5..e6bb6777c 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/ClassType.kt +++ b/Src/java/model/src/main/java/org/hl7/cql/model/ClassType.kt @@ -19,7 +19,7 @@ constructor( var genericParameters: MutableList = 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 @@ -80,7 +80,7 @@ constructor( } fun findSearch(searchPath: String): SearchType? { - return searches.firstOrNull() { it.name == searchPath } + return searches.firstOrNull { it.name == searchPath } } /** @@ -142,7 +142,7 @@ constructor( } val sortedElements: List - get() = elements.sortedWith { o1, o2 -> o1.name.compareTo(o2.name) } + get() = elements.sortedWith(compareBy { it.name }) private var baseElementMap: LinkedHashMap? = null get() { @@ -230,8 +230,7 @@ constructor( override fun toLabel(): String = label ?: name - val tupleType: TupleType - get() = buildTupleType() + val tupleType: TupleType by lazy { buildTupleType() } private fun addTupleElements( classType: ClassType, @@ -253,10 +252,8 @@ constructor( private fun buildTupleType(): TupleType { val tupleElements = LinkedHashMap() - addTupleElements(this, tupleElements) - - return TupleType(tupleElements.values.toMutableList()) + return TupleType(tupleElements.values) } override fun isCompatibleWith(other: DataType): Boolean { diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/ClassTypeElement.kt b/Src/java/model/src/main/java/org/hl7/cql/model/ClassTypeElement.kt index 08497263e..c0e08c0b2 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/ClassTypeElement.kt +++ b/Src/java/model/src/main/java/org/hl7/cql/model/ClassTypeElement.kt @@ -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 "" + ) } } diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/GenericClassSignatureParser.kt b/Src/java/model/src/main/java/org/hl7/cql/model/GenericClassSignatureParser.kt index f3d83b34c..7d60b42ea 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/GenericClassSignatureParser.kt +++ b/Src/java/model/src/main/java/org/hl7/cql/model/GenericClassSignatureParser.kt @@ -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( @@ -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 } } @@ -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) diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/IntervalType.kt b/Src/java/model/src/main/java/org/hl7/cql/model/IntervalType.kt index 087170299..c7b0861ab 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/IntervalType.kt +++ b/Src/java/model/src/main/java/org/hl7/cql/model/IntervalType.kt @@ -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) { @@ -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() diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/InvalidRedeclarationException.kt b/Src/java/model/src/main/java/org/hl7/cql/model/InvalidRedeclarationException.kt index 08e75d8d9..f6a3ab39b 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/InvalidRedeclarationException.kt +++ b/Src/java/model/src/main/java/org/hl7/cql/model/InvalidRedeclarationException.kt @@ -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}""" + .trimIndent() ) -} diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/ListType.kt b/Src/java/model/src/main/java/org/hl7/cql/model/ListType.kt index 942a01299..7b56adf9b 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/ListType.kt +++ b/Src/java/model/src/main/java/org/hl7/cql/model/ListType.kt @@ -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 @@ -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() diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/ModelIdentifier.kt b/Src/java/model/src/main/java/org/hl7/cql/model/ModelIdentifier.kt index e70d4d3cc..6f39bf512 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/ModelIdentifier.kt +++ b/Src/java/model/src/main/java/org/hl7/cql/model/ModelIdentifier.kt @@ -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" } } } diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/NamespaceInfo.kt b/Src/java/model/src/main/java/org/hl7/cql/model/NamespaceInfo.kt index de5694bbd..2e27504e4 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/NamespaceInfo.kt +++ b/Src/java/model/src/main/java/org/hl7/cql/model/NamespaceInfo.kt @@ -1,13 +1,11 @@ package org.hl7.cql.model -import java.util.* - data class NamespaceInfo(val name: String, val uri: String) { init { - require(name.isNotEmpty() and uri.isNotEmpty()) { "name and uri are required" } + require(name.isNotEmpty() and uri.isNotEmpty()) { "name and uri can not be empty" } } override fun toString(): String { - return String.format(Locale.US, "%s: %s", name, uri) + return "$name: $uri" } } diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/NamespaceManager.kt b/Src/java/model/src/main/java/org/hl7/cql/model/NamespaceManager.kt index 9d3a9faf3..676539a9a 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/NamespaceManager.kt +++ b/Src/java/model/src/main/java/org/hl7/cql/model/NamespaceManager.kt @@ -1,6 +1,5 @@ package org.hl7.cql.model -import java.util.* import kotlin.collections.HashMap class NamespaceManager { @@ -25,15 +24,11 @@ class NamespaceManager { require(namespaceName.isNotEmpty()) { "namespaceName is required" } require(namespaceUri.isNotEmpty()) { "namespaceUri is required" } check(!namespaces.containsKey(namespaceName)) { - String.format(Locale.US, "A namespace named %s is already defined.", namespaceName) + "A namespace named $namespaceName is already defined." } check(!reverseNamespaces.containsKey(namespaceUri)) { - String.format( - Locale.US, - "A namespace name for uri %s is already defined.", - namespaceUri - ) + "A namespace name for uri $namespaceUri is already defined." } namespaces[namespaceName] = namespaceUri @@ -51,8 +46,7 @@ class NamespaceManager { companion object { @JvmStatic fun getPath(namespaceUri: String?, name: String): String { - return namespaceUri?.let { String.format(Locale.US, "%s/%s", namespaceUri, name) } - ?: name + return namespaceUri?.let { "$it/$name" } ?: name } @JvmStatic diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/SearchType.kt b/Src/java/model/src/main/java/org/hl7/cql/model/SearchType.kt index 37bdb0ec7..e99785e0a 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/SearchType.kt +++ b/Src/java/model/src/main/java/org/hl7/cql/model/SearchType.kt @@ -1,8 +1,8 @@ package org.hl7.cql.model -class SearchType(val name: String, val path: String, val type: DataType) { +data class SearchType(val name: String, val path: String, val type: DataType) { init { - require(name.isNotEmpty() && path.isNotEmpty()) { "name and path are required" } + require(name.isNotEmpty() && path.isNotEmpty()) { "name and path can not be empty" } } } diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/SimpleType.kt b/Src/java/model/src/main/java/org/hl7/cql/model/SimpleType.kt index 3c675c4ab..f6c5f559e 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/SimpleType.kt +++ b/Src/java/model/src/main/java/org/hl7/cql/model/SimpleType.kt @@ -1,7 +1,5 @@ package org.hl7.cql.model -import java.util.* - data class SimpleType @JvmOverloads constructor( @@ -44,13 +42,8 @@ constructor( this.isSuperTypeOf(callType) -> true else -> { val instantiableElements = context.getSimpleConversionTargets(callType) - 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() @@ -58,7 +51,5 @@ constructor( } } - override fun instantiate(context: InstantiationContext): DataType { - return this - } + override fun instantiate(context: InstantiationContext): DataType = this } diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/TupleType.kt b/Src/java/model/src/main/java/org/hl7/cql/model/TupleType.kt index 0802205c8..36aa49959 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/TupleType.kt +++ b/Src/java/model/src/main/java/org/hl7/cql/model/TupleType.kt @@ -1,39 +1,21 @@ package org.hl7.cql.model -@Suppress("TooManyFunctions") -data class TupleType -@JvmOverloads -constructor(val elements: MutableList = mutableListOf()) : BaseDataType() { +import java.util.SortedSet - fun addElement(element: TupleTypeElement) { - elements.add(element) - } - - fun addElements(elements: Collection) { - this.elements.addAll(elements) - } +class TupleType private constructor(val elements: SortedSet) : BaseDataType() { - val sortedElements: List - get() = elements.sortedWith { l, r -> l.name.compareTo(r.name) } + constructor(elements: Iterable) : this(elements.sortedByName()) override fun isSubTypeOf(other: DataType): Boolean { - return when { - other is TupleType -> - sortedElements.size == other.sortedElements.size && - sortedElements.zip(other.sortedElements).all { it.first.isSubTypeOf(it.second) } - else -> super.isSubTypeOf(other) - } + return if (other is TupleType) { + elements.zipAll(other.elements) { a, b -> a.isSubTypeOf(b) } + } else super.isSubTypeOf(other) } override fun isSuperTypeOf(other: DataType): Boolean { - return when { - other is TupleType -> - sortedElements.size == other.sortedElements.size && - sortedElements.zip(other.sortedElements).all { - it.first.isSuperTypeOf(it.second) - } - else -> super.isSuperTypeOf(other) - } + return if (other is TupleType) { + elements.zipAll(other.elements) { a, b -> a.isSuperTypeOf(b) } + } else super.isSuperTypeOf(other) } override fun toString(): String = elements.joinToString(",", "tuple{", "}") @@ -46,19 +28,16 @@ constructor(val elements: MutableList = mutableListOf()) : Bas } else super.isCompatibleWith(other) } - override val isGeneric: Boolean - get() = elements.any { it.type.isGeneric } + override val isGeneric: Boolean = elements.any { it.type.isGeneric } override fun isInstantiable(callType: DataType, context: InstantiationContext): Boolean { // Call isInstantiable recursively to make sure that type parameters (if present) are bound return when (callType) { DataType.ANY -> elements.all { it.type.isInstantiable(callType, context) } is TupleType -> { - sortedElements.size == callType.sortedElements.size && - sortedElements.zip(callType.sortedElements).all { - it.first.name == it.second.name && - it.first.type.isInstantiable(it.second.type, context) - } + elements.zipAll(callType.elements) { a, b -> + a.type.isInstantiable(b.type, context) + } } else -> false } @@ -69,24 +48,32 @@ constructor(val elements: MutableList = mutableListOf()) : Bas TupleType( elements .map { TupleTypeElement(it.name, it.type.instantiate(context), false) } - .toMutableList() + .sortedByName() ) } else this } + override fun equals(other: Any?): Boolean { + return if (other is TupleType) { + elements.zipAll(other.elements) { a, b -> a == b } + } else false + } + override fun hashCode(): Int { var result = 13 for (e in elements) { - result += (37 * e.hashCode()) + result = 37 * result + e.hashCode() } - return result } - override fun equals(other: Any?): Boolean { - return if (other is TupleType) { - sortedElements.size == other.sortedElements.size && - sortedElements.zip(other.sortedElements).all { it.first == it.second } - } else false + companion object { + private fun Iterable.sortedByName(): SortedSet = + toSortedSet(compareBy { it.name }) + + private fun Collection.zipAll( + other: Collection, + predicate: (a: TupleTypeElement, b: TupleTypeElement) -> Boolean + ): Boolean = size == other.size && zip(other).all { predicate(it.first, it.second) } } } diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/TupleTypeElement.kt b/Src/java/model/src/main/java/org/hl7/cql/model/TupleTypeElement.kt index db3932d73..aee2da51d 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/TupleTypeElement.kt +++ b/Src/java/model/src/main/java/org/hl7/cql/model/TupleTypeElement.kt @@ -1,29 +1,21 @@ package org.hl7.cql.model -import java.util.* - data class TupleTypeElement( val name: String, val type: DataType, private val oneBased: Boolean = false ) { init { - require(name.isNotEmpty()) { "name is required" } + require(name.isNotEmpty()) { "name can not be empty" } } - fun isSubTypeOf(that: TupleTypeElement): Boolean { - return this.name == that.name && type.isSubTypeOf(that.type) - } + fun isSubTypeOf(that: TupleTypeElement): Boolean = + this.name == that.name && type.isSubTypeOf(that.type) - fun isSuperTypeOf(that: TupleTypeElement): Boolean { - return this.name == that.name && type.isSuperTypeOf(that.type) - } + fun isSuperTypeOf(that: TupleTypeElement): Boolean = + this.name == that.name && type.isSuperTypeOf(that.type) - override fun toString(): String { - return String.format(Locale.US, "%s:%s", this.name, type.toString()) - } + override fun toString(): String = "${name}:${type}" - fun toLabel(): String { - return String.format(Locale.US, "%s: %s", this.name, type.toLabel()) - } + fun toLabel(): String = "${name}: ${type}" } diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/TypeParameter.kt b/Src/java/model/src/main/java/org/hl7/cql/model/TypeParameter.kt index baad6bbd9..35ce32ed2 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/TypeParameter.kt +++ b/Src/java/model/src/main/java/org/hl7/cql/model/TypeParameter.kt @@ -8,7 +8,12 @@ constructor( val constraintType: DataType? = null ) : BaseDataType() { init { - require(identifier.isNotEmpty()) { "identifier is empty" } + require(identifier.isNotEmpty()) { "identifier can not be empty" } + if (constraint == TypeParameterConstraint.TYPE) { + require(constraintType != null) { + "constraintType must be provided when constraint is TYPE" + } + } } enum class TypeParameterConstraint { @@ -58,11 +63,8 @@ constructor( override val isGeneric: Boolean = true - override fun isInstantiable(callType: DataType, context: InstantiationContext): Boolean { - return context.isInstantiable(this, callType) - } + override fun isInstantiable(callType: DataType, context: InstantiationContext): Boolean = + context.isInstantiable(this, callType) - override fun instantiate(context: InstantiationContext): DataType { - return context.instantiate(this) - } + override fun instantiate(context: InstantiationContext): DataType = context.instantiate(this) }