Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Trackable as an extension property #1472

Merged
merged 6 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ spotless {
}

dependencies {
implementation("org.slf4j:slf4j-api:1.7.36")
implementation("org.slf4j:slf4j-api:2.0.13")
testImplementation("org.hamcrest:hamcrest-all:1.3")
testImplementation("uk.co.datumedge:hamcrest-json:0.2")
testImplementation(platform("org.junit:junit-bom:5.10.2"))
testImplementation("org.junit.jupiter:junit-jupiter")
testImplementation("org.slf4j:slf4j-simple:1.7.36")
testImplementation("org.slf4j:slf4j-simple:2.0.13")

// These are JAXB dependencies excluded because the libraries need to work
// on Android. But for test purposes we use them pretty much everywhere.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ dependencies {
xjc("org.glassfish.jaxb:jaxb-xjc:3.0.2")
xjc("org.glassfish.jaxb:jaxb-runtime:4.0.3")
xjc("org.eclipse.persistence:org.eclipse.persistence.moxy:4.0.2")
xjc("org.slf4j:slf4j-simple:1.7.36")
xjc("org.slf4j:slf4j-simple:2.0.13")
xjc("org.apache.ant:ant:1.10.14")

api("jakarta.xml.bind:jakarta.xml.bind-api:4.0.1")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import joptsimple.OptionSpec;
import org.cqframework.cql.cql2elm.*;
import org.cqframework.cql.cql2elm.quick.FhirLibrarySourceProvider;
import org.cqframework.cql.elm.tracking.TrackBack;
import org.cqframework.cql.cql2elm.tracking.TrackBack;
import org.hl7.cql.model.ModelIdentifier;
import org.hl7.cql.model.ModelInfoProvider;
import org.hl7.elm_modelinfo.r1.ModelInfo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ import org.cqframework.cql.cql2elm.model.invocation.*
import org.cqframework.cql.cql2elm.preprocessor.CqlPreprocessorElmCommonVisitor
import org.cqframework.cql.cql2elm.preprocessor.ExpressionDefinitionInfo
import org.cqframework.cql.cql2elm.preprocessor.LibraryInfo
import org.cqframework.cql.elm.tracking.TrackBack
import org.cqframework.cql.elm.tracking.Trackable
import org.cqframework.cql.cql2elm.tracking.TrackBack
import org.cqframework.cql.cql2elm.tracking.Trackable.resultType
import org.cqframework.cql.cql2elm.tracking.Trackable.trackbacks
import org.cqframework.cql.cql2elm.tracking.Trackable.withResultType
import org.cqframework.cql.gen.cqlLexer
import org.cqframework.cql.gen.cqlParser
import org.cqframework.cql.gen.cqlParser.*
Expand Down Expand Up @@ -624,7 +626,6 @@ class Cql2ElmVisitor(
of.createTupleElement()
.withName(parseString(ctx.referentialIdentifier()))
.withValue(parseExpression(ctx.expression()))
result.resultType = result.value.resultType
return result
}

Expand All @@ -633,19 +634,17 @@ class Cql2ElmVisitor(
val elements = mutableListOf<TupleTypeElement>()
for (elementContext in ctx.tupleElementSelector()) {
val element = visit(elementContext) as TupleElement
elements.add(TupleTypeElement(element.name, element.resultType!!))
elements.add(TupleTypeElement(element.name, element.value.resultType!!))
tuple.element.add(element)
}
tuple.resultType = TupleType(elements)
return tuple
}

override fun visitInstanceElementSelector(ctx: InstanceElementSelectorContext): Any? {
val result =
of.createInstanceElement()
.withName(parseString(ctx.referentialIdentifier()))
.withValue(parseExpression(ctx.expression()))
result.resultType = result.value.resultType
val name = parseString(ctx.referentialIdentifier())
val exp = parseExpression(ctx.expression())
val result = of.createInstanceElement().withName(name).withValue(exp)
return result
}

Expand Down Expand Up @@ -3533,8 +3532,7 @@ class Cql2ElmVisitor(
else aqs.resultType
element.value.resultType =
sourceType // Doesn't use the fluent API to avoid casting
element.resultType = element.value.resultType
elements.add(TupleTypeElement(element.name, element.resultType!!))
elements.add(TupleTypeElement(element.name, element.value.resultType!!))
returnExpression.element.add(element)
}
val returnType = TupleType(elements)
Expand Down Expand Up @@ -3577,9 +3575,11 @@ class Cql2ElmVisitor(
// result element
// type
// of the query context
libraryBuilder.verifyComparable(queryContext.resultElementType)
libraryBuilder.verifyComparable(
queryContext.resultElementType!!
)
} else {
libraryBuilder.verifyComparable(sortByItem.resultType)
libraryBuilder.verifyComparable(sortByItem.resultType!!)
}
}
} finally {
Expand Down Expand Up @@ -4544,14 +4544,12 @@ class Cql2ElmVisitor(
op.resultType = functionDef.resultType
} else {
functionDef.isExternal = true
if (resultType == null) {
requireNotNull(resultType) {
// ERROR:
throw IllegalArgumentException(
String.format(
Locale.US,
"Function %s is marked external but does not declare a return type.",
functionDef.name
)
String.format(
Locale.US,
"Function %s is marked external but does not declare a return type.",
functionDef.name
)
}
functionDef.resultType = resultType.resultType
Expand Down Expand Up @@ -4654,7 +4652,7 @@ class Cql2ElmVisitor(
}
}

private fun track(trackable: Trackable?, pt: ParseTree): TrackBack? {
private fun track(trackable: Element?, pt: ParseTree): TrackBack? {
val tb = getTrackBack(pt)
if (tb != null) {
trackable!!.trackbacks.add(tb)
Expand All @@ -4665,13 +4663,13 @@ class Cql2ElmVisitor(
return tb
}

private fun track(trackable: Trackable?, from: Element): TrackBack? {
private fun track(element: Element?, from: Element): TrackBack? {
val tb = if (from.trackbacks.isNotEmpty()) from.trackbacks[0] else null
if (tb != null) {
trackable!!.trackbacks.add(tb)
element!!.trackbacks.add(tb)
}
if (trackable is Element) {
decorate(trackable, tb)
if (element is Element) {
decorate(element, tb)
}
return tb
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import org.cqframework.cql.cql2elm.elm.ElmEditor
import org.cqframework.cql.cql2elm.elm.IElmEdit
import org.cqframework.cql.cql2elm.model.CompiledLibrary
import org.cqframework.cql.cql2elm.preprocessor.CqlPreprocessor
import org.cqframework.cql.cql2elm.tracking.TrackBack
import org.cqframework.cql.elm.IdObjectFactory
import org.cqframework.cql.elm.tracking.TrackBack
import org.cqframework.cql.gen.cqlLexer
import org.cqframework.cql.gen.cqlParser
import org.cqframework.cql.gen.cqlParser.LibraryContext
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.cqframework.cql.cql2elm

import org.cqframework.cql.elm.tracking.TrackBack
import org.cqframework.cql.cql2elm.tracking.TrackBack

open class CqlCompilerException
@JvmOverloads
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.cqframework.cql.cql2elm

import org.cqframework.cql.elm.tracking.TrackBack
import org.cqframework.cql.cql2elm.tracking.TrackBack

/** Created by Bryn on 5/20/2017. */
class CqlInternalException : CqlCompilerException {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.cqframework.cql.cql2elm

import org.cqframework.cql.elm.tracking.TrackBack
import org.cqframework.cql.cql2elm.tracking.TrackBack

/** Created by Bryn on 3/27/2017. */
class CqlSemanticException : CqlCompilerException {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.cqframework.cql.cql2elm

import org.cqframework.cql.elm.tracking.TrackBack
import org.cqframework.cql.cql2elm.tracking.TrackBack

/** Created by Bryn on 3/27/2017. */
class CqlSyntaxException : CqlCompilerException {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package org.cqframework.cql.cql2elm

import java.util.*
import org.cqframework.cql.elm.tracking.Trackable
import org.hl7.elm.r1.Element

/**
* Simple POJO using for identifier hider that maintains the identifier and Trackable type of the
* construct being evaluated.
*/
class IdentifierContext(val identifier: String, val trackableSubclass: Class<out Trackable>?) {
class IdentifierContext(val identifier: String, val trackableSubclass: Class<out Element>?) {

override fun equals(other: Any?): Boolean {
if (this === other) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import javax.xml.namespace.QName
import org.cqframework.cql.cql2elm.model.*
import org.cqframework.cql.cql2elm.model.SystemLibraryHelper.load
import org.cqframework.cql.cql2elm.model.invocation.*
import org.cqframework.cql.cql2elm.tracking.Trackable.resultType
import org.cqframework.cql.cql2elm.tracking.Trackable.trackbacks
import org.cqframework.cql.cql2elm.tracking.Trackable.withResultType
import org.cqframework.cql.elm.IdObjectFactory
import org.cqframework.cql.elm.tracking.Trackable
import org.hl7.cql.model.*
import org.hl7.cql_annotations.r1.*
import org.hl7.cql_annotations.r1.ObjectFactory
Expand Down Expand Up @@ -1716,7 +1718,7 @@ class LibraryBuilder(
return invocation
}

fun verifyComparable(dataType: DataType?) {
fun verifyComparable(dataType: DataType) {
val left = objectFactory.createLiteral().withResultType(dataType) as Expression
val right = objectFactory.createLiteral().withResultType(dataType) as Expression
val comparison: BinaryExpression = objectFactory.createLess().withOperand(left, right)
Expand Down Expand Up @@ -1767,14 +1769,9 @@ class LibraryBuilder(
.withResultType(toType) as Query
}

private fun reportWarning(message: String, expression: Trackable?) {
private fun reportWarning(message: String, expression: Element?) {
val trackback =
if (
expression != null &&
expression.trackbacks != null &&
expression.trackbacks.isNotEmpty()
)
expression.trackbacks[0]
if (expression != null && expression.trackbacks.isNotEmpty()) expression.trackbacks[0]
else null
val warning =
CqlSemanticException(message, CqlCompilerException.ErrorSeverity.Warning, trackback)
Expand Down Expand Up @@ -2371,14 +2368,8 @@ class LibraryBuilder(
}

private fun validateUcumUnit(unit: String) {
if (libraryManager.ucumService != null) {
val ucumService = libraryManager.ucumService
val message = ucumService?.validate(unit)
if (message != null) {
// ERROR:
throw IllegalArgumentException(message)
}
}
val message = libraryManager.ucumService?.validate(unit)
require(message == null) { message!! }
}

fun createQuantity(value: BigDecimal?, unit: String): Quantity {
Expand Down Expand Up @@ -3639,12 +3630,12 @@ class LibraryBuilder(
*
* @param identifier The identifier belonging to the parameter, expression, function, alias,
* etc, to be evaluated.
* @param trackable The construct trackable, for example [ExpressionRef].
* @param element The construct trackable, for example [ExpressionRef].
*/
@JvmOverloads
fun pushIdentifier(
identifier: String,
trackable: Trackable?,
element: Element?,
scope: IdentifierScope = IdentifierScope.LOCAL
) {
val localMatch =
Expand All @@ -3656,16 +3647,16 @@ class LibraryBuilder(
val matchedContext = if (globalMatch.isPresent) globalMatch.get() else localMatch.get()
val matchedOnFunctionOverloads =
matchedContext.trackableSubclass == FunctionDef::class.java &&
trackable is FunctionDef
element is FunctionDef
if (!matchedOnFunctionOverloads) {
reportWarning(
resolveWarningMessage(matchedContext.identifier, identifier, trackable),
trackable
resolveWarningMessage(matchedContext.identifier, identifier, element),
element
)
}
}
if (shouldAddIdentifierContext(trackable)) {
val trackableOrNull: Class<out Trackable>? = trackable?.javaClass
if (shouldAddIdentifierContext(element)) {
val trackableOrNull: Class<out Element>? = element?.javaClass
// Sometimes the underlying Trackable doesn't resolve in the calling code
if (scope == IdentifierScope.GLOBAL) {
globalIdentifiers.push(IdentifierContext(identifier, trackableOrNull))
Expand Down Expand Up @@ -3709,17 +3700,17 @@ class LibraryBuilder(

// TODO: consider other structures that should only trigger a readonly check of identifier
// hiding
private fun shouldAddIdentifierContext(trackable: Trackable?): Boolean {
return trackable !is Literal
private fun shouldAddIdentifierContext(element: Element?): Boolean {
return element !is Literal
}

private fun resolveWarningMessage(
matchedIdentifier: String?,
identifierParam: String,
trackable: Trackable?
element: Element?
): String {
val elementString = lookupElementWarning(trackable)
return if (trackable is Literal) {
val elementString = lookupElementWarning(element)
return if (element is Literal) {
String.format(
Locale.US,
"You used a string literal: [%s] here that matches an identifier in scope: [%s]. Did you mean to use the identifier instead?",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.collections.HashSet
import org.cqframework.cql.cql2elm.model.CompiledLibrary
import org.cqframework.cql.cql2elm.tracking.Trackable.resultType
import org.cqframework.cql.cql2elm.ucum.UcumService
import org.cqframework.cql.cql2elm.ucum.UcumServiceFactory
import org.cqframework.cql.elm.serializing.ElmLibraryReaderFactory
Expand Down Expand Up @@ -345,12 +346,10 @@ constructor(
}

private fun isVersionCompatible(library: Library): Boolean {
if (cqlCompilerOptions.compatibilityLevel.isNotBlank()) {
if (library.annotation != null) {
val version: String? = CompilerOptions.getCompilerVersion(library)
if (version != null) {
return (version == cqlCompilerOptions.compatibilityLevel)
}
if (cqlCompilerOptions.compatibilityLevel.isNotBlank() && library.annotation != null) {
val version: String? = CompilerOptions.getCompilerVersion(library)
if (version != null) {
return (version == cqlCompilerOptions.compatibilityLevel)
}
}
return false
Expand All @@ -365,12 +364,13 @@ constructor(
return result
}

override fun equals(obj: Any?): Boolean {
if (this === obj) return true
if (obj == null) return false
if (javaClass != obj.javaClass) return false
val other: FunctionSig = obj as FunctionSig
return (other.name == name) && other.numArguments == numArguments
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null) return false
if (other is FunctionSig) {
return (other.name == name) && other.numArguments == numArguments
}
return false
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import org.cqframework.cql.cql2elm.model.invocation.*
import org.cqframework.cql.cql2elm.model.invocation.DateInvocation.Companion.setDateFieldsFromOperands
import org.cqframework.cql.cql2elm.model.invocation.DateTimeInvocation.Companion.setDateTimeFieldsFromOperands
import org.cqframework.cql.cql2elm.model.invocation.TimeInvocation.Companion.setTimeFieldsFromOperands
import org.cqframework.cql.cql2elm.tracking.Trackable.resultType
import org.cqframework.cql.cql2elm.tracking.Trackable.trackbacks
import org.cqframework.cql.elm.IdObjectFactory
import org.hl7.elm.r1.*

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package org.cqframework.cql.cql2elm

import java.util.*
import org.cqframework.cql.cql2elm.model.QueryContext
import org.cqframework.cql.cql2elm.tracking.Trackable.resultType
import org.cqframework.cql.gen.cqlParser
import org.hl7.cql.model.*
import org.hl7.elm.r1.*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import java.util.*
import javax.xml.namespace.QName
import kotlin.collections.ArrayList
import org.cqframework.cql.cql2elm.model.Model
import org.cqframework.cql.cql2elm.tracking.Trackable.withResultType
import org.cqframework.cql.elm.IdObjectFactory
import org.hl7.cql.model.*
import org.hl7.elm.r1.ParameterTypeSpecifier
Expand Down
Loading
Loading