diff --git a/Src/java/.vscode/settings.json b/Src/java/.vscode/settings.json index a866b22c3..46c97ea5a 100644 --- a/Src/java/.vscode/settings.json +++ b/Src/java/.vscode/settings.json @@ -10,7 +10,11 @@ "fhirpath", "hamcrest", "Inferencing", + "opdef", + "Instancio", + "Objenesis", "qicore", + "Randomizer", "testng", "tngtech", "trackback" diff --git a/Src/java/buildSrc/src/main/groovy/cql.java-conventions.gradle b/Src/java/buildSrc/src/main/groovy/cql.java-conventions.gradle index 07124b22d..5ae2d3185 100644 --- a/Src/java/buildSrc/src/main/groovy/cql.java-conventions.gradle +++ b/Src/java/buildSrc/src/main/groovy/cql.java-conventions.gradle @@ -29,7 +29,7 @@ dependencies { testImplementation 'org.testng:testng:7.4.0' testImplementation 'org.hamcrest:hamcrest-all:1.3' testImplementation 'uk.co.datumedge:hamcrest-json:0.2' - testImplementation 'junit:junit:4.12' + testImplementation 'junit:junit:4.13.2' testImplementation 'org.slf4j:slf4j-simple:1.7.36' // These are JAXB dependencies excluded because the libraries need to work diff --git a/Src/java/buildSrc/src/main/groovy/cql.xjc-conventions.gradle b/Src/java/buildSrc/src/main/groovy/cql.xjc-conventions.gradle index 0c562d6e8..8f9e15407 100644 --- a/Src/java/buildSrc/src/main/groovy/cql.xjc-conventions.gradle +++ b/Src/java/buildSrc/src/main/groovy/cql.xjc-conventions.gradle @@ -24,7 +24,7 @@ dependencies { ext.xjc = [ destDir: "${buildDir}/generated/sources/$name/main/java", - args: '-disableXmlSecurity -Xfluent-api -Xequals -XhashCode -XtoString' + args: '-disableXmlSecurity -Xfluent-api -Xequals -XhashCode -XtoString -Xsetters -Xsetters-mode=direct' ] diff --git a/Src/java/cql-to-elm/build.gradle b/Src/java/cql-to-elm/build.gradle index f565be824..0458be486 100644 --- a/Src/java/cql-to-elm/build.gradle +++ b/Src/java/cql-to-elm/build.gradle @@ -21,4 +21,5 @@ dependencies { testImplementation project(':qdm') testImplementation 'com.github.reinert:jjschema:1.16' testImplementation 'com.tngtech.archunit:archunit:1.2.1' + testImplementation 'org.skyscreamer:jsonassert:1.5.1' } \ No newline at end of file diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/CqlCompiler.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/CqlCompiler.java index 697e1ffeb..a471881a8 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/CqlCompiler.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/CqlCompiler.java @@ -1,17 +1,26 @@ package org.cqframework.cql.cql2elm; +import static org.cqframework.cql.cql2elm.CqlCompilerOptions.Options.EnableAnnotations; +import static org.cqframework.cql.cql2elm.CqlCompilerOptions.Options.EnableLocators; +import static org.cqframework.cql.cql2elm.CqlCompilerOptions.Options.EnableResultTypes; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import org.antlr.v4.runtime.*; import org.antlr.v4.runtime.tree.ParseTree; +import org.cqframework.cql.cql2elm.elm.ElmEdit; +import org.cqframework.cql.cql2elm.elm.ElmEditor; import org.cqframework.cql.cql2elm.model.CompiledLibrary; -import org.cqframework.cql.cql2elm.preprocessor.CqlPreprocessorVisitor; +import org.cqframework.cql.cql2elm.preprocessor.CqlPreprocessor; +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; @@ -190,34 +199,45 @@ public Library run(CharStream is) { warnings = new ArrayList<>(); messages = new ArrayList<>(); - LibraryBuilder builder = new LibraryBuilder(namespaceInfo, libraryManager); - builder.setCompilerOptions(libraryManager.getCqlCompilerOptions()); - Cql2ElmVisitor visitor = new Cql2ElmVisitor(builder); - builder.setVisitor(visitor); - visitor.setTranslatorOptions(libraryManager.getCqlCompilerOptions()); + var options = libraryManager.getCqlCompilerOptions().getOptions(); - CqlCompiler.CqlErrorListener errorListener = - new CqlCompiler.CqlErrorListener(builder, visitor.isDetailedErrorsEnabled()); + LibraryBuilder builder = new LibraryBuilder(namespaceInfo, libraryManager, new IdObjectFactory()); + CqlCompiler.CqlErrorListener errorListener = new CqlCompiler.CqlErrorListener( + builder, options.contains(CqlCompilerOptions.Options.EnableDetailedErrors)); + // Phase 1: Lexing cqlLexer lexer = new cqlLexer(is); lexer.removeErrorListeners(); lexer.addErrorListener(errorListener); CommonTokenStream tokens = new CommonTokenStream(lexer); + + // Phase 2: Parsing (the lexer is actually streaming, so Phase 1 and 2 happen together) cqlParser parser = new cqlParser(tokens); parser.setBuildParseTree(true); - parser.removeErrorListeners(); // Clear the default console listener parser.addErrorListener(errorListener); ParseTree tree = parser.library(); - CqlPreprocessorVisitor preprocessor = new CqlPreprocessorVisitor(builder, tokens); + // Phase 3: preprocess the parse tree (generates the LibraryInfo with + // header information for definitions) + CqlPreprocessor preprocessor = new CqlPreprocessor(builder, tokens); preprocessor.visit(tree); - visitor.setTokenStream(tokens); - visitor.setLibraryInfo(preprocessor.getLibraryInfo()); - + // Phase 4: generate the ELM (the ELM is generated with full type information that can be used + // for validation, optimization, rewriting, debugging, etc.) + ElmGenerator visitor = new ElmGenerator(builder, tokens, preprocessor.getLibraryInfo()); visitResult = visitor.visit(tree); library = builder.getLibrary(); + + // Phase 5: ELM optimization/reduction (this is where result types, annotations, etc. are removed + // and there will probably be a lot of other optimizations that happen here in the future) + var edits = coalesceAll( + nullIfFalse(options.contains(EnableAnnotations), ElmEdit.REMOVE_ANNOTATION), + nullIfFalse(options.contains(EnableResultTypes), ElmEdit.REMOVE_RESULT_TYPE), + nullIfFalse(options.contains(EnableLocators), ElmEdit.REMOVE_LOCATOR)); + + new ElmEditor(edits).edit(library); + compiledLibrary = builder.getCompiledLibrary(); retrieves = visitor.getRetrieves(); exceptions.addAll(builder.getExceptions()); @@ -227,4 +247,12 @@ public Library run(CharStream is) { return library; } + + private static T nullIfFalse(boolean b, T t) { + return !b ? t : null; + } + + private static List coalesceAll(ElmEdit... ts) { + return Arrays.stream(ts).filter(t -> t != null).collect(Collectors.toList()); + } } diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/Cql2ElmVisitor.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/ElmGenerator.java similarity index 99% rename from Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/Cql2ElmVisitor.java rename to Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/ElmGenerator.java index 8cc6cfb68..108572c1c 100755 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/Cql2ElmVisitor.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/ElmGenerator.java @@ -6,6 +6,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.TokenStream; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; import org.cqframework.cql.cql2elm.model.*; @@ -17,23 +18,14 @@ import org.cqframework.cql.gen.cqlParser; import org.hl7.cql.model.*; import org.hl7.elm.r1.*; -import org.hl7.elm.r1.Element; -import org.hl7.elm.r1.Interval; import org.hl7.elm_modelinfo.r1.ModelInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class Cql2ElmVisitor extends CqlPreprocessorElmCommonVisitor { - private static final Logger logger = LoggerFactory.getLogger(Cql2ElmVisitor.class); +public class ElmGenerator extends CqlPreprocessorElmCommonVisitor { + private static final Logger logger = LoggerFactory.getLogger(ElmGenerator.class); private final SystemMethodResolver systemMethodResolver; - public void setLibraryInfo(LibraryInfo libraryInfo) { - if (libraryInfo == null) { - throw new IllegalArgumentException("libraryInfo is null"); - } - this.libraryInfo = libraryInfo; - } - private final Set definedExpressionDefinitions = new HashSet<>(); private final Stack forwards = new Stack<>(); private final Map functionHeaders = new HashMap<>(); @@ -45,13 +37,9 @@ public void setLibraryInfo(LibraryInfo libraryInfo) { private final List expressions = new ArrayList<>(); private final Map contextDefinitions = new HashMap<>(); - public Cql2ElmVisitor(LibraryBuilder libraryBuilder) { - super(libraryBuilder); - - if (libraryBuilder == null) { - throw new IllegalArgumentException("libraryBuilder is null"); - } - + public ElmGenerator(LibraryBuilder libraryBuilder, TokenStream tokenStream, LibraryInfo libraryInfo) { + super(libraryBuilder, tokenStream); + this.libraryInfo = Objects.requireNonNull(libraryInfo, "libraryInfo required"); this.systemMethodResolver = new SystemMethodResolver(this, libraryBuilder); } @@ -1624,10 +1612,6 @@ public Expression visitEqualityExpression(cqlParser.EqualityExpressionContext ct libraryBuilder.resolveBinaryCall("System", "Equivalent", equivalent); - if (isAnnotationEnabled()) { - equivalent.setLocalId(Integer.toString(getNextLocalId())); - } - if (!"~".equals(parseString(ctx.getChild(1)))) { track(equivalent, ctx); Not not = of.createNot().withOperand(equivalent); diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/LibraryBuilder.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/LibraryBuilder.java index 434645e25..d0a960301 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/LibraryBuilder.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/LibraryBuilder.java @@ -19,7 +19,7 @@ /** * Created by Bryn on 12/29/2016. */ -public class LibraryBuilder implements ModelResolver { +public class LibraryBuilder { public static enum SignatureLevel { /* Indicates signatures will never be included in operator invocations @@ -42,19 +42,17 @@ public static enum SignatureLevel { All } - public LibraryBuilder(LibraryManager libraryManager) { - this(null, libraryManager); + public LibraryBuilder(LibraryManager libraryManager, ObjectFactory objectFactory) { + this(null, libraryManager, objectFactory); } - public LibraryBuilder(NamespaceInfo namespaceInfo, LibraryManager libraryManager) { - if (libraryManager == null) { - throw new IllegalArgumentException("libraryManager is null"); - } + public LibraryBuilder(NamespaceInfo namespaceInfo, LibraryManager libraryManager, ObjectFactory objectFactory) { + this.libraryManager = Objects.requireNonNull(libraryManager); + this.of = Objects.requireNonNull(objectFactory); this.namespaceInfo = namespaceInfo; // Note: allowed to be null, implies global namespace this.modelManager = libraryManager.getModelManager(); - this.libraryManager = libraryManager; - this.typeBuilder = new TypeBuilder(of, this); + this.typeBuilder = new TypeBuilder(of, this.modelManager); this.library = of.createLibrary() .withSchemaIdentifier(of.createVersionedIdentifier() @@ -63,8 +61,13 @@ public LibraryBuilder(NamespaceInfo namespaceInfo, LibraryManager libraryManager this.cqlToElmInfo = af.createCqlToElmInfo(); this.cqlToElmInfo.setTranslatorVersion(LibraryBuilder.class.getPackage().getImplementationVersion()); + this.library.getAnnotation().add(this.cqlToElmInfo); + this.options = Objects.requireNonNull( + libraryManager.getCqlCompilerOptions(), "libraryManager compilerOptions can not be null."); + + this.setCompilerOptions(this.options); compiledLibrary = new CompiledLibrary(); compiledLibrary.setLibrary(library); } @@ -97,6 +100,14 @@ public List getExceptions() { return exceptions; } + public ObjectFactory getObjectFactory() { + return of; + } + + public LibraryManager getLibraryManager() { + return libraryManager; + } + private final Map models = new LinkedHashMap<>(); private final Map> nameTypeSpecifiers = new HashMap<>(); @@ -108,10 +119,10 @@ public List getExceptions() { private final Deque hidingIdentifiersContexts = new ArrayDeque<>(); private int literalContext = 0; private int typeSpecifierContext = 0; - private NamespaceInfo namespaceInfo = null; - private ModelManager modelManager = null; + private final NamespaceInfo namespaceInfo; + private final ModelManager modelManager; private Model defaultModel = null; - private LibraryManager libraryManager = null; + private final LibraryManager libraryManager; private Library library = null; public Library getLibrary() { @@ -130,24 +141,18 @@ public ConversionMap getConversionMap() { return conversionMap; } - private final ObjectFactory of = new ObjectFactory(); + private final ObjectFactory of; private final org.hl7.cql_annotations.r1.ObjectFactory af = new org.hl7.cql_annotations.r1.ObjectFactory(); private boolean listTraversal = true; - private CqlCompilerOptions options; - private CqlToElmInfo cqlToElmInfo = null; - private TypeBuilder typeBuilder = null; - private Cql2ElmVisitor visitor = null; + private final CqlCompilerOptions options; + private final CqlToElmInfo cqlToElmInfo; + private final TypeBuilder typeBuilder; public void enableListTraversal() { listTraversal = true; } - public void setCompilerOptions(CqlCompilerOptions options) { - if (options == null) { - throw new IllegalArgumentException("Options cannot be null"); - } - - this.options = options; + private void setCompilerOptions(CqlCompilerOptions options) { if (options.getOptions().contains(CqlCompilerOptions.Options.DisableListTraversal)) { this.listTraversal = false; } @@ -168,10 +173,6 @@ public void setCompilerOptions(CqlCompilerOptions options) { this.cqlToElmInfo.setSignatureLevel(options.getSignatureLevel().name()); } - public void setVisitor(Cql2ElmVisitor visitor) { - this.visitor = visitor; - } - private String compatibilityLevel = null; public boolean isCompatibilityLevel3() { @@ -964,11 +965,6 @@ public Expression resolveUnion(Expression left, Expression right) { // TODO: Take advantage of nary unions BinaryWrapper wrapper = normalizeListTypes(left, right); Union union = of.createUnion().withOperand(wrapper.left, wrapper.right); - - if (visitor != null && visitor.isAnnotationEnabled()) { - union.setLocalId(Integer.toString(visitor.getNextLocalId())); - } - resolveNaryCall("System", "Union", union); return union; } diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/SystemMethodResolver.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/SystemMethodResolver.java index e9b21b5bd..003566768 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/SystemMethodResolver.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/SystemMethodResolver.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.Set; import org.cqframework.cql.cql2elm.model.QueryContext; import org.cqframework.cql.gen.cqlParser; @@ -13,21 +14,14 @@ * Created by Bryn on 12/27/2016. */ public class SystemMethodResolver { - private final ObjectFactory of = new ObjectFactory(); - private final Cql2ElmVisitor visitor; + private final ObjectFactory of; + private final ElmGenerator visitor; private final LibraryBuilder builder; - public SystemMethodResolver(Cql2ElmVisitor visitor, LibraryBuilder builder) { - if (visitor == null) { - throw new IllegalArgumentException("visitor is null"); - } - - if (builder == null) { - throw new IllegalArgumentException("builder is null"); - } - - this.visitor = visitor; - this.builder = builder; + public SystemMethodResolver(ElmGenerator visitor, LibraryBuilder builder) { + this.visitor = Objects.requireNonNull(visitor, "visitor required"); + this.builder = Objects.requireNonNull(builder, "builder required"); + this.of = Objects.requireNonNull(builder.getObjectFactory(), "builder must have an object factory"); } private List getParams(Expression target, cqlParser.ParamListContext ctx) { diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/TypeBuilder.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/TypeBuilder.java index c1c277166..14d28e05b 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/TypeBuilder.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/TypeBuilder.java @@ -16,7 +16,7 @@ public class TypeBuilder { private ObjectFactory of; private ModelResolver mr; - public class InternalModelResolver implements ModelResolver { + public static class InternalModelResolver implements ModelResolver { private ModelManager modelManager; public InternalModelResolver(ModelManager modelManager) { @@ -33,9 +33,8 @@ public TypeBuilder(ObjectFactory of, ModelResolver mr) { this.mr = mr; } - public TypeBuilder(ModelManager modelManager) { - this.of = new ObjectFactory(); - this.mr = new InternalModelResolver(modelManager); + public TypeBuilder(ObjectFactory of, ModelManager modelManager) { + this(of, new InternalModelResolver(modelManager)); } public QName dataTypeToQName(DataType type) { diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/elm/ElmEdit.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/elm/ElmEdit.java new file mode 100644 index 000000000..912b97f16 --- /dev/null +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/elm/ElmEdit.java @@ -0,0 +1,44 @@ +package org.cqframework.cql.cql2elm.elm; + +import org.hl7.cql_annotations.r1.Annotation; +import org.hl7.elm.r1.Element; + +public enum ElmEdit { + REMOVE_LOCATOR { + @Override + public void edit(Element element) { + element.setLocator(null); + } + }, + REMOVE_ANNOTATION { + @Override + public void edit(Element element) { + element.setLocalId(null); + if (element.getAnnotation() != null) { + for (int i = 0; i < element.getAnnotation().size(); i++) { + var x = element.getAnnotation().get(i); + if (x instanceof Annotation) { + var a = (Annotation) x; + // TODO: Remove narrative but _not_ tags + // Tags are necessary for `allowFluent` compiler resolution + // to work correctly + a.setS(null); + if (a.getT().isEmpty()) { + element.getAnnotation().remove(i); + i--; + } + } + } + } + } + }, + REMOVE_RESULT_TYPE { + @Override + public void edit(Element element) { + element.setResultTypeName(null); + element.setResultTypeSpecifier(null); + } + }; + + public abstract void edit(Element element); +} diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/elm/ElmEditor.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/elm/ElmEditor.java new file mode 100644 index 000000000..28dd8e23d --- /dev/null +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/elm/ElmEditor.java @@ -0,0 +1,36 @@ +package org.cqframework.cql.cql2elm.elm; + +import java.util.List; +import java.util.Objects; +import org.cqframework.cql.elm.tracking.Trackable; +import org.cqframework.cql.elm.utility.Visitors; +import org.cqframework.cql.elm.visiting.FunctionalElmVisitor; +import org.hl7.elm.r1.Element; +import org.hl7.elm.r1.Library; + +public class ElmEditor { + + private final List edits; + private final FunctionalElmVisitor> visitor; + + public ElmEditor(List edits) { + this.edits = Objects.requireNonNull(edits); + this.visitor = Visitors.from(ElmEditor::applyEdits); + } + + public void edit(Library library) { + this.visitor.visitLibrary(library, edits); + } + + protected static Void applyEdits(Trackable trackable, List edits) { + if (!(trackable instanceof Element)) { + return null; + } + + for (ElmEdit edit : edits) { + edit.edit((Element) trackable); + } + + return null; + } +} diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/preprocessor/CqlPreprocessorVisitor.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/preprocessor/CqlPreprocessor.java similarity index 98% rename from Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/preprocessor/CqlPreprocessorVisitor.java rename to Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/preprocessor/CqlPreprocessor.java index 2b89fe0c5..d6dc36b7b 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/preprocessor/CqlPreprocessorVisitor.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/preprocessor/CqlPreprocessor.java @@ -15,11 +15,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class CqlPreprocessorVisitor extends CqlPreprocessorElmCommonVisitor { - static final Logger logger = LoggerFactory.getLogger(CqlPreprocessorVisitor.class); +public class CqlPreprocessor extends CqlPreprocessorElmCommonVisitor { + static final Logger logger = LoggerFactory.getLogger(CqlPreprocessor.class); private int lastSourceIndex = -1; - public CqlPreprocessorVisitor(LibraryBuilder libraryBuilder, TokenStream tokenStream) { + public CqlPreprocessor(LibraryBuilder libraryBuilder, TokenStream tokenStream) { super(libraryBuilder, tokenStream); } diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/preprocessor/CqlPreprocessorElmCommonVisitor.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/preprocessor/CqlPreprocessorElmCommonVisitor.java index 600d43c20..a7fbc0fb0 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/preprocessor/CqlPreprocessorElmCommonVisitor.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/preprocessor/CqlPreprocessorElmCommonVisitor.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.Stack; import javax.xml.namespace.QName; import org.antlr.v4.runtime.ParserRuleContext; @@ -27,16 +28,16 @@ import org.hl7.elm.r1.*; /** - * Common functionality used by {@link CqlPreprocessorVisitor} and {@link Cql2ElmVisitor} + * Common functionality used by {@link CqlPreprocessor} and {@link ElmGenerator} */ public class CqlPreprocessorElmCommonVisitor extends cqlBaseVisitor { - protected final ObjectFactory of = new ObjectFactory(); + protected final ObjectFactory of; protected final org.hl7.cql_annotations.r1.ObjectFactory af = new org.hl7.cql_annotations.r1.ObjectFactory(); private boolean implicitContextCreated = false; private String currentContext = "Unfiltered"; protected Stack chunks = new Stack<>(); protected final LibraryBuilder libraryBuilder; - protected TokenStream tokenStream; + protected final TokenStream tokenStream; protected LibraryInfo libraryInfo = new LibraryInfo(); private boolean annotate = false; private boolean detailedErrors = false; @@ -50,13 +51,20 @@ public class CqlPreprocessorElmCommonVisitor extends cqlBaseVisitor { private final List expressions = new ArrayList<>(); private boolean includeDeprecatedElements = false; - public CqlPreprocessorElmCommonVisitor(LibraryBuilder libraryBuilder) { - this.libraryBuilder = libraryBuilder; + /** + * TODO: refactor away! + */ + public void setLibraryInfo(LibraryInfo libraryInfo) { + this.libraryInfo = libraryInfo; } public CqlPreprocessorElmCommonVisitor(LibraryBuilder libraryBuilder, TokenStream tokenStream) { - this.libraryBuilder = libraryBuilder; - this.tokenStream = tokenStream; + this.libraryBuilder = Objects.requireNonNull(libraryBuilder, "libraryBuilder required"); + this.tokenStream = Objects.requireNonNull(tokenStream, "tokenStream required"); + this.of = Objects.requireNonNull(libraryBuilder.getObjectFactory(), "libraryBuilder.objectFactory required"); + + // Don't talk to strangers. Except when you have to. + this.setCompilerOptions(libraryBuilder.getLibraryManager().getCqlCompilerOptions()); } protected boolean getImplicitContextCreated() { @@ -81,10 +89,6 @@ protected String saveCurrentContext(String currentContext) { return saveContext; } - public void setTokenStream(TokenStream theTokenStream) { - tokenStream = theTokenStream; - } - @Override public Object visit(ParseTree tree) { boolean pushedChunk = pushChunk(tree); @@ -897,7 +901,7 @@ public void setIncludeDeprecatedElements(boolean includeDeprecatedElements) { this.includeDeprecatedElements = includeDeprecatedElements; } - public void setTranslatorOptions(CqlCompilerOptions options) { + private void setCompilerOptions(CqlCompilerOptions options) { if (options.getOptions().contains(CqlCompilerOptions.Options.EnableDateRangeOptimization)) { this.enableDateRangeOptimization(); } diff --git a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/CMS146JsonTest.java b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/CMS146JsonTest.java index c937a891c..e61926a31 100644 --- a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/CMS146JsonTest.java +++ b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/CMS146JsonTest.java @@ -1,8 +1,5 @@ package org.cqframework.cql.cql2elm; -import static org.hamcrest.MatcherAssert.assertThat; -import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs; - import java.io.File; import java.io.IOException; import java.net.URL; @@ -11,6 +8,8 @@ import java.util.Scanner; import org.cqframework.cql.cql2elm.CqlCompilerException.ErrorSeverity; import org.cqframework.cql.cql2elm.LibraryBuilder.SignatureLevel; +import org.json.JSONException; +import org.skyscreamer.jsonassert.JSONAssert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -27,7 +26,8 @@ private static Object[][] sigFileAndSigLevel() { } @Test(dataProvider = "sigFileAndSigLevel") - public void testCms146_SignatureLevels(String fileName, SignatureLevel expectedSignatureLevel) throws IOException { + public void testCms146_SignatureLevels(String fileName, SignatureLevel expectedSignatureLevel) + throws IOException, JSONException { final String expectedJson = getJson(fileName); final File cms146 = getFile("CMS146v2_Test_CQM.cql"); @@ -37,7 +37,7 @@ public void testCms146_SignatureLevels(String fileName, SignatureLevel expectedS new LibraryManager( modelManager, new CqlCompilerOptions(ErrorSeverity.Warning, expectedSignatureLevel))); final String actualJson = translator.toJson(); - assertThat(actualJson, sameJSONAs(expectedJson)); + JSONAssert.assertEquals(expectedJson, actualJson, true); } private static String getJson(String name) throws IOException { diff --git a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/CommentTests.java b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/CommentTests.java index 513949447..0ad7fe313 100644 --- a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/CommentTests.java +++ b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/CommentTests.java @@ -1,5 +1,6 @@ package org.cqframework.cql.cql2elm; +import static org.cqframework.cql.cql2elm.CqlCompilerOptions.Options.EnableAnnotations; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; @@ -19,8 +20,7 @@ public class CommentTests { @Test public void testComments() throws IOException { - CqlTranslator translator = - TestUtils.runSemanticTest("TestComments.cql", 0, CqlCompilerOptions.Options.EnableAnnotations); + CqlTranslator translator = TestUtils.runSemanticTest("TestComments.cql", 0, EnableAnnotations); CompiledLibrary library = translator.getTranslatedLibrary(); assertThat(library.getLibrary().getAnnotation(), notNullValue()); @@ -77,7 +77,7 @@ public void testComments() throws IOException { @Test public void testTags() throws IOException { - CqlTranslator translator = TestUtils.runSemanticTest("TestTags.cql", 0); + CqlTranslator translator = TestUtils.runSemanticTest("TestTags.cql", 0, EnableAnnotations); CompiledLibrary library = translator.getTranslatedLibrary(); assertThat(library.getLibrary().getAnnotation(), notNullValue()); Annotation a = null; @@ -356,6 +356,11 @@ public void testTags() throws IOException { aInvalid = (Annotation) o; } } - assertThat(aInvalid, nullValue()); + + // Narrative still applies in the event of an invalid, it'll just + // be a comment instead of a tag + assertThat(aInvalid, notNullValue()); + assertThat(aInvalid.getS(), notNullValue()); + assertThat(aInvalid.getT().size(), equalTo(0)); } } diff --git a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/LibraryManagerTests.java b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/LibraryManagerTests.java index 12a83bed6..ab3962722 100644 --- a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/LibraryManagerTests.java +++ b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/LibraryManagerTests.java @@ -2,8 +2,8 @@ import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.lessThanOrEqualTo; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; import org.hl7.elm.r1.VersionedIdentifier; import org.testng.annotations.AfterClass; diff --git a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/SemanticTests.java b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/SemanticTests.java index 30abed151..d86ab4ea5 100644 --- a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/SemanticTests.java +++ b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/SemanticTests.java @@ -756,7 +756,7 @@ public void testIfConditionalReturnTypes() throws IOException { @Test public void testIssue863() throws IOException { - final CqlTranslator translator = TestUtils.runSemanticTest("Issue863.cql", 0); + TestUtils.runSemanticTest("Issue863.cql", 0); } private CqlTranslator runSemanticTest(String testFileName) throws IOException { diff --git a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TestUtils.java b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TestUtils.java index f0e0db07c..2007d0605 100644 --- a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TestUtils.java +++ b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TestUtils.java @@ -17,7 +17,8 @@ import org.cqframework.cql.cql2elm.CqlCompilerException.ErrorSeverity; import org.cqframework.cql.cql2elm.LibraryBuilder.SignatureLevel; import org.cqframework.cql.cql2elm.model.CompiledLibrary; -import org.cqframework.cql.cql2elm.preprocessor.CqlPreprocessorVisitor; +import org.cqframework.cql.cql2elm.preprocessor.CqlPreprocessor; +import org.cqframework.cql.elm.IdObjectFactory; import org.cqframework.cql.gen.cqlLexer; import org.cqframework.cql.gen.cqlParser; import org.hl7.cql.model.NamespaceInfo; @@ -29,11 +30,11 @@ private static ModelManager getModelManager() { return new ModelManager(); } - public static Cql2ElmVisitor visitFile(String fileName, boolean inClassPath) throws IOException { + public static ElmGenerator visitFile(String fileName, boolean inClassPath) throws IOException { InputStream is = inClassPath ? TestUtils.class.getResourceAsStream(fileName) : new FileInputStream(fileName); TokenStream tokens = parseCharStream(CharStreams.fromStream(is)); ParseTree tree = parseTokenStream(tokens); - Cql2ElmVisitor visitor = createElmTranslatorVisitor(tokens, tree); + ElmGenerator visitor = createElmTranslatorVisitor(tokens, tree); visitor.visit(tree); return visitor; } @@ -97,14 +98,13 @@ private static void ensureValid(CqlTranslator translator) { } } - private static Cql2ElmVisitor createElmTranslatorVisitor(TokenStream tokens, ParseTree tree) { + private static ElmGenerator createElmTranslatorVisitor(TokenStream tokens, ParseTree tree) { ModelManager modelManager = new ModelManager(); LibraryManager libraryManager = getLibraryManager(modelManager, null); - LibraryBuilder libraryBuilder = new LibraryBuilder(libraryManager); - CqlPreprocessorVisitor preprocessor = new CqlPreprocessorVisitor(libraryBuilder, tokens); + LibraryBuilder libraryBuilder = new LibraryBuilder(libraryManager, new IdObjectFactory()); + CqlPreprocessor preprocessor = new CqlPreprocessor(libraryBuilder, tokens); preprocessor.visit(tree); - Cql2ElmVisitor visitor = new Cql2ElmVisitor(libraryBuilder); - visitor.setLibraryInfo(preprocessor.getLibraryInfo()); + ElmGenerator visitor = new ElmGenerator(libraryBuilder, tokens, preprocessor.getLibraryInfo()); return visitor; } diff --git a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/validation/LocalIdTests.java b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/validation/LocalIdTests.java new file mode 100644 index 000000000..95fa3f1fb --- /dev/null +++ b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/validation/LocalIdTests.java @@ -0,0 +1,89 @@ +package org.cqframework.cql.cql2elm.validation; + +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiFunction; +import org.cqframework.cql.cql2elm.CqlCompilerOptions.Options; +import org.cqframework.cql.cql2elm.TestUtils; +import org.cqframework.cql.elm.tracking.Trackable; +import org.cqframework.cql.elm.utility.Visitors; +import org.hl7.elm.r1.Element; +import org.hl7.elm.r1.Library; + +public class LocalIdTests { + + private static class MissingIdDescription { + private final Element element; + + public MissingIdDescription(Element element) { + this.element = element; + } + + public Element element() { + return element; + } + + public String description() { + var description = + String.format("%s missing localId", element.getClass().getSimpleName()); + if (element.getTrackbacks() != null && !element.getTrackbacks().isEmpty()) { + var tb = element.getTrackbacks().get(0); + description = description + + String.format( + " at %s:[%s:%s-%s:%s]", + tb.getLibrary().getId(), + tb.getStartLine(), + tb.getStartChar(), + tb.getEndLine(), + tb.getEndChar()); + } + + return description; + } + } + + private static BiFunction, List> missingIdChecker = + (elm, context) -> { + if (!(elm instanceof Element)) { + return context; + } + + Element element = (Element) elm; + if (element.getLocalId() == null) { + context.add(new MissingIdDescription(element)); + } + + return context; + }; + + protected Library compile(String cql) { + return TestUtils.createTranslatorFromText(cql, Options.EnableAnnotations, Options.EnableLocators) + .toELM(); + } + + // @Test + public void simpleTest() { + var lib = compile("library Test version '1.0.0'"); + var missingIds = Visitors.from(missingIdChecker).visitElement(lib, new ArrayList<>()); + + for (var missingId : missingIds) { + System.out.println(missingId.description()); + } + + assertTrue(missingIds.isEmpty()); + } + + // @Test + public void equalityTest() { + var lib = compile("library Test version '1.0.0'\n define foo: 1 = 1\n define bar: 1 != 1"); + var missingIds = Visitors.from(missingIdChecker).visitElement(lib, new ArrayList<>()); + + for (var missingId : missingIds) { + System.out.println(missingId.description()); + } + + assertTrue(missingIds.isEmpty()); + } +} diff --git a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_All.json b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_All.json index 86bdcd052..596361251 100644 --- a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_All.json +++ b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_All.json @@ -831,7 +831,6 @@ }, "alias" : "R" } ], - "relationship" : [ ], "where" : { "type" : "And", "signature" : [ { diff --git a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_All.xml b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_All.xml index 99946fcb4..5fcf1c5d6 100644 --- a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_All.xml +++ b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_All.xml @@ -416,7 +416,6 @@ - diff --git a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Differing.json b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Differing.json index 7cf1d030d..3f9cdd3e4 100644 --- a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Differing.json +++ b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Differing.json @@ -581,7 +581,6 @@ }, "alias" : "R" } ], - "relationship" : [ ], "where" : { "type" : "And", "operand" : [ { diff --git a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Differing.xml b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Differing.xml index 91a46365b..062d60db1 100644 --- a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Differing.xml +++ b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Differing.xml @@ -268,7 +268,6 @@ - diff --git a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_None.json b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_None.json index 9f1570f0e..d9375521e 100644 --- a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_None.json +++ b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_None.json @@ -573,7 +573,6 @@ }, "alias" : "R" } ], - "relationship" : [ ], "where" : { "type" : "And", "operand" : [ { diff --git a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_None.xml b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_None.xml index 8e2078e2c..e24aa6200 100644 --- a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_None.xml +++ b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_None.xml @@ -262,7 +262,6 @@ - diff --git a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Overloads.json b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Overloads.json index 947e3c24a..0d7a10925 100644 --- a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Overloads.json +++ b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Overloads.json @@ -639,7 +639,6 @@ }, "alias" : "R" } ], - "relationship" : [ ], "where" : { "type" : "And", "operand" : [ { diff --git a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Overloads.xml b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Overloads.xml index 83af89a4c..4d7d0c31e 100644 --- a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Overloads.xml +++ b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Overloads.xml @@ -302,7 +302,6 @@ - diff --git a/Src/java/elm-fhir/src/main/java/org/cqframework/cql/elm/requirements/ElmRequirementsContext.java b/Src/java/elm-fhir/src/main/java/org/cqframework/cql/elm/requirements/ElmRequirementsContext.java index 54257068a..6cf5e6964 100644 --- a/Src/java/elm-fhir/src/main/java/org/cqframework/cql/elm/requirements/ElmRequirementsContext.java +++ b/Src/java/elm-fhir/src/main/java/org/cqframework/cql/elm/requirements/ElmRequirementsContext.java @@ -7,6 +7,7 @@ import org.cqframework.cql.cql2elm.*; import org.cqframework.cql.cql2elm.model.CompiledLibrary; import org.cqframework.cql.cql2elm.model.LibraryRef; +import org.cqframework.cql.elm.IdObjectFactory; import org.hl7.cql.model.ClassType; import org.hl7.cql.model.DataType; import org.hl7.cql.model.NamespaceManager; @@ -26,7 +27,7 @@ public ElmRequirementsContext( this.libraryManager = libraryManager; this.options = options; this.typeResolver = new TypeResolver(libraryManager); - this.typeBuilder = new TypeBuilder(this.libraryManager.getModelManager()); + this.typeBuilder = new TypeBuilder(new IdObjectFactory(), this.libraryManager.getModelManager()); if (visitor == null) { throw new IllegalArgumentException("visitor required"); diff --git a/Src/java/elm-fhir/src/main/java/org/cqframework/cql/elm/requirements/ElmRequirementsVisitor.java b/Src/java/elm-fhir/src/main/java/org/cqframework/cql/elm/requirements/ElmRequirementsVisitor.java index 1f1c62eda..b0a346861 100644 --- a/Src/java/elm-fhir/src/main/java/org/cqframework/cql/elm/requirements/ElmRequirementsVisitor.java +++ b/Src/java/elm-fhir/src/main/java/org/cqframework/cql/elm/requirements/ElmRequirementsVisitor.java @@ -1,6 +1,6 @@ package org.cqframework.cql.elm.requirements; -import org.cqframework.cql.elm.visiting.ElmBaseLibraryVisitor; +import org.cqframework.cql.elm.visiting.BaseElmLibraryVisitor; import org.hl7.cql.model.ListType; import org.hl7.elm.r1.*; @@ -46,7 +46,7 @@ At an AND, if there are already lists of lists, the condition is too complex for At a logical expression, return ElmConjunctiveRequirement or ElmDisjunctiveRequirement */ -public class ElmRequirementsVisitor extends ElmBaseLibraryVisitor { +public class ElmRequirementsVisitor extends BaseElmLibraryVisitor { public ElmRequirementsVisitor() { super(); @@ -105,7 +105,8 @@ public ElmRequirement visitExpressionRef(ExpressionRef elm, ElmRequirementsConte result = context.reportExpressionRef(elm); } if (result != null) { - // If the expression ref is to a retrieve or a single-source query, surface it as an "inferred" requirement + // If the expression ref is to a retrieve or a single-source query, surface it + // as an "inferred" requirement // in the referencing scope if (result instanceof ElmDataRequirement) { ElmDataRequirement inferredRequirement = ElmDataRequirement.inferFrom((ElmDataRequirement) result); @@ -134,7 +135,8 @@ public ElmRequirement visitFunctionRef(FunctionRef elm, ElmRequirementsContext c if (elm.getOperand().size() != 1 || (elm.getOperand().get(0).getResultType() instanceof ListType && !(elm.getResultType() instanceof ListType))) { - // Note that the assumption here is that the data requirement has already been reported to the context + // Note that the assumption here is that the data requirement has already been + // reported to the context return new ElmOperatorRequirement(context.getCurrentLibraryIdentifier(), elm) .combine((ElmDataRequirement) result); } @@ -169,8 +171,10 @@ public ElmRequirement visitRetrieve(Retrieve elm, ElmRequirementsContext context if (elmPertinenceContext != null) { result.setPertinenceContext(elmPertinenceContext); } - // If not analyzing requirements, or in a query context, report the data requirement - // If in a query context, the requirement will be reported as an inferred requirement at the query boundary + // If not analyzing requirements, or in a query context, report the data + // requirement + // If in a query context, the requirement will be reported as an inferred + // requirement at the query boundary if (!context.getOptions().getAnalyzeDataRequirements() || !context.inQueryContext()) { context.reportRequirements(result, null); } @@ -247,30 +251,18 @@ public ElmRequirement visitConceptDef(ConceptDef elm, ElmRequirementsContext con return super.visitConceptDef(elm, context); } - @Override - public ElmRequirement visitExpression(Expression elm, ElmRequirementsContext context) { - return super.visitExpression(elm, context); - } - - @Override - public ElmRequirement visitOperatorExpression(OperatorExpression elm, ElmRequirementsContext context) { - return super.visitOperatorExpression(elm, context); - } - - @Override - public ElmRequirement visitUnaryExpression(UnaryExpression elm, ElmRequirementsContext context) { - return super.visitUnaryExpression(elm, context); - } - /** - * If both sides are column references that point to the same column in the same alias - * the condition is a tautology - * If both sides are column references that point to different columns in the same alias - * the condition is a constraint + * If both sides are column references that point to the same column in the same + * alias + * the condition is a tautology + * If both sides are column references that point to different columns in the + * same alias + * the condition is a constraint * If both sides are column references that point to different aliases - * the condition is a join + * the condition is a join * If one side or the other is a column reference - * the condition is a potentially sargeable condition + * the condition is a potentially sargeable condition + * * @param elm * @param context * @param left @@ -323,7 +315,8 @@ protected ElmRequirement inferConditionRequirement( @Override public ElmRequirement visitChildren(BinaryExpression elm, ElmRequirementsContext context) { - // Override visit children behavior to determine whether to create an ElmConditionRequirement + // Override visit children behavior to determine whether to create an + // ElmConditionRequirement if (elm.getOperand().size() != 2) { return super.visitChildren(elm, context); } @@ -332,12 +325,15 @@ public ElmRequirement visitChildren(BinaryExpression elm, ElmRequirementsContext /** * Determine whether the condition is sargeable: * - * A op B + * A op B * * Where: - * * A is an order-preserving expression with a single property reference to a property of some source in the current query context - * * op is a positive relative comparison operation (=, >, <, >=, <=) or a membership operator (in, contains) - * * B is a functional, repeatable, and deterministic context literal expression with respect to the current query context + * * A is an order-preserving expression with a single property reference to a + * property of some source in the current query context + * * op is a positive relative comparison operation (=, >, <, >=, <=) or a + * membership operator (in, contains) + * * B is a functional, repeatable, and deterministic context literal expression + * with respect to the current query context */ case "Equal": case "Equivalent": @@ -358,9 +354,11 @@ public ElmRequirement visitChildren(BinaryExpression elm, ElmRequirementsContext } /** - * Gather sargeable conditions as Lists of conditions. At an AND, combine conditions from sub-nodes. + * Gather sargeable conditions as Lists of conditions. At an AND, combine + * conditions from sub-nodes. * At an OR, the result is separate lists of condition lists. - * At an AND, if there are already lists of lists, the condition is too complex for analysis (i.e. it's not in DNF or CNF) + * At an AND, if there are already lists of lists, the condition is too complex + * for analysis (i.e. it's not in DNF or CNF) */ // TODO: Normalize to DNF case "And": { @@ -421,11 +419,6 @@ public ElmRequirement visitChildren(BinaryExpression elm, ElmRequirementsContext } } - @Override - public ElmRequirement visitBinaryExpression(BinaryExpression elm, ElmRequirementsContext context) { - return super.visitBinaryExpression(elm, context); - } - @Override public ElmRequirement visitTernaryExpression(TernaryExpression elm, ElmRequirementsContext context) { ElmRequirement requirements = super.visitTernaryExpression(elm, context); @@ -438,11 +431,6 @@ public ElmRequirement visitNaryExpression(NaryExpression elm, ElmRequirementsCon return new ElmOperatorRequirement(context.getCurrentLibraryIdentifier(), elm).combine(requirements); } - @Override - public ElmRequirement visitOperandDef(OperandDef elm, ElmRequirementsContext context) { - return super.visitOperandDef(elm, context); - } - @Override public ElmRequirement visitOperandRef(OperandRef elm, ElmRequirementsContext context) { return new ElmExpressionRequirement(context.getCurrentLibraryIdentifier(), elm); @@ -458,26 +446,6 @@ public ElmRequirement visitLiteral(Literal elm, ElmRequirementsContext context) return new ElmExpressionRequirement(context.getCurrentLibraryIdentifier(), elm); } - @Override - public ElmRequirement visitTupleElement(TupleElement elm, ElmRequirementsContext context) { - return super.visitTupleElement(elm, context); - } - - @Override - public ElmRequirement visitTuple(Tuple elm, ElmRequirementsContext context) { - return super.visitTuple(elm, context); - } - - @Override - public ElmRequirement visitInstanceElement(InstanceElement elm, ElmRequirementsContext context) { - return super.visitInstanceElement(elm, context); - } - - @Override - public ElmRequirement visitInstance(Instance elm, ElmRequirementsContext context) { - return super.visitInstance(elm, context); - } - @Override public ElmRequirement visitInterval(Interval elm, ElmRequirementsContext context) { ElmRequirement result = super.visitInterval(elm, context); @@ -486,42 +454,12 @@ public ElmRequirement visitInterval(Interval elm, ElmRequirementsContext context return finalResult; } - @Override - public ElmRequirement visitList(List elm, ElmRequirementsContext context) { - return super.visitList(elm, context); - } - - @Override - public ElmRequirement visitAnd(And elm, ElmRequirementsContext context) { - return super.visitAnd(elm, context); - } - - @Override - public ElmRequirement visitOr(Or elm, ElmRequirementsContext context) { - return super.visitOr(elm, context); - } - - @Override - public ElmRequirement visitXor(Xor elm, ElmRequirementsContext context) { - return super.visitXor(elm, context); - } - - @Override - public ElmRequirement visitNot(Not elm, ElmRequirementsContext context) { - return super.visitNot(elm, context); - } - @Override public ElmRequirement visitIf(If elm, ElmRequirementsContext context) { // TODO: Rewrite the if as equivalent logic return new ElmOperatorRequirement(context.getCurrentLibraryIdentifier(), elm); } - @Override - public ElmRequirement visitCaseItem(CaseItem elm, ElmRequirementsContext context) { - return super.visitCaseItem(elm, context); - } - @Override public ElmRequirement visitCase(Case elm, ElmRequirementsContext context) { // TODO: Rewrite the case as equivalent logic @@ -556,295 +494,16 @@ public ElmRequirement visitNull(Null elm, ElmRequirementsContext context) { return new ElmExpressionRequirement(context.getCurrentLibraryIdentifier(), elm); } - @Override - public ElmRequirement visitIsNull(IsNull elm, ElmRequirementsContext context) { - return super.visitIsNull(elm, context); - } - - @Override - public ElmRequirement visitIsTrue(IsTrue elm, ElmRequirementsContext context) { - return super.visitIsTrue(elm, context); - } - - @Override - public ElmRequirement visitIsFalse(IsFalse elm, ElmRequirementsContext context) { - return super.visitIsFalse(elm, context); - } - - @Override - public ElmRequirement visitCoalesce(Coalesce elm, ElmRequirementsContext context) { - return super.visitCoalesce(elm, context); - } - - @Override - public ElmRequirement visitIs(Is elm, ElmRequirementsContext context) { - return super.visitIs(elm, context); - } - - @Override - public ElmRequirement visitAs(As elm, ElmRequirementsContext context) { - return super.visitAs(elm, context); - } - - @Override - public ElmRequirement visitConvert(Convert elm, ElmRequirementsContext context) { - return super.visitConvert(elm, context); - } - - @Override - public ElmRequirement visitToBoolean(ToBoolean elm, ElmRequirementsContext context) { - return super.visitToBoolean(elm, context); - } - - @Override - public ElmRequirement visitToConcept(ToConcept elm, ElmRequirementsContext context) { - return super.visitToConcept(elm, context); - } - - @Override - public ElmRequirement visitToDateTime(ToDateTime elm, ElmRequirementsContext context) { - return super.visitToDateTime(elm, context); - } - - @Override - public ElmRequirement visitToDecimal(ToDecimal elm, ElmRequirementsContext context) { - return super.visitToDecimal(elm, context); - } - - @Override - public ElmRequirement visitToInteger(ToInteger elm, ElmRequirementsContext context) { - return super.visitToInteger(elm, context); - } - - @Override - public ElmRequirement visitToQuantity(ToQuantity elm, ElmRequirementsContext context) { - return super.visitToQuantity(elm, context); - } - - @Override - public ElmRequirement visitToString(ToString elm, ElmRequirementsContext context) { - return super.visitToString(elm, context); - } - - @Override - public ElmRequirement visitToTime(ToTime elm, ElmRequirementsContext context) { - return super.visitToTime(elm, context); - } - - @Override - public ElmRequirement visitEqual(Equal elm, ElmRequirementsContext context) { - return super.visitEqual(elm, context); - } - - @Override - public ElmRequirement visitEquivalent(Equivalent elm, ElmRequirementsContext context) { - return super.visitEquivalent(elm, context); - } - - @Override - public ElmRequirement visitNotEqual(NotEqual elm, ElmRequirementsContext context) { - return super.visitNotEqual(elm, context); - } - - @Override - public ElmRequirement visitLess(Less elm, ElmRequirementsContext context) { - return super.visitLess(elm, context); - } - - @Override - public ElmRequirement visitGreater(Greater elm, ElmRequirementsContext context) { - return super.visitGreater(elm, context); - } - - @Override - public ElmRequirement visitLessOrEqual(LessOrEqual elm, ElmRequirementsContext context) { - return super.visitLessOrEqual(elm, context); - } - - @Override - public ElmRequirement visitGreaterOrEqual(GreaterOrEqual elm, ElmRequirementsContext context) { - return super.visitGreaterOrEqual(elm, context); - } - - @Override - public ElmRequirement visitAdd(Add elm, ElmRequirementsContext context) { - return super.visitAdd(elm, context); - } - - @Override - public ElmRequirement visitSubtract(Subtract elm, ElmRequirementsContext context) { - return super.visitSubtract(elm, context); - } - - @Override - public ElmRequirement visitMultiply(Multiply elm, ElmRequirementsContext context) { - return super.visitMultiply(elm, context); - } - - @Override - public ElmRequirement visitDivide(Divide elm, ElmRequirementsContext context) { - return super.visitDivide(elm, context); - } - - @Override - public ElmRequirement visitTruncatedDivide(TruncatedDivide elm, ElmRequirementsContext context) { - return super.visitTruncatedDivide(elm, context); - } - - @Override - public ElmRequirement visitModulo(Modulo elm, ElmRequirementsContext context) { - return super.visitModulo(elm, context); - } - - @Override - public ElmRequirement visitCeiling(Ceiling elm, ElmRequirementsContext context) { - return super.visitCeiling(elm, context); - } - - @Override - public ElmRequirement visitFloor(Floor elm, ElmRequirementsContext context) { - return super.visitFloor(elm, context); - } - - @Override - public ElmRequirement visitTruncate(Truncate elm, ElmRequirementsContext context) { - return super.visitTruncate(elm, context); - } - - @Override - public ElmRequirement visitAbs(Abs elm, ElmRequirementsContext context) { - return super.visitAbs(elm, context); - } - - @Override - public ElmRequirement visitNegate(Negate elm, ElmRequirementsContext context) { - return super.visitNegate(elm, context); - } - - @Override - public ElmRequirement visitRound(Round elm, ElmRequirementsContext context) { - return super.visitRound(elm, context); - } - - @Override - public ElmRequirement visitLn(Ln elm, ElmRequirementsContext context) { - return super.visitLn(elm, context); - } - - @Override - public ElmRequirement visitExp(Exp elm, ElmRequirementsContext context) { - return super.visitExp(elm, context); - } - - @Override - public ElmRequirement visitLog(Log elm, ElmRequirementsContext context) { - return super.visitLog(elm, context); - } - - @Override - public ElmRequirement visitPower(Power elm, ElmRequirementsContext context) { - return super.visitPower(elm, context); - } - - @Override - public ElmRequirement visitSuccessor(Successor elm, ElmRequirementsContext context) { - return super.visitSuccessor(elm, context); - } - - @Override - public ElmRequirement visitPredecessor(Predecessor elm, ElmRequirementsContext context) { - return super.visitPredecessor(elm, context); - } - - @Override - public ElmRequirement visitMinValue(MinValue elm, ElmRequirementsContext context) { - return super.visitMinValue(elm, context); - } - - @Override - public ElmRequirement visitMaxValue(MaxValue elm, ElmRequirementsContext context) { - return super.visitMaxValue(elm, context); - } - - @Override - public ElmRequirement visitConcatenate(Concatenate elm, ElmRequirementsContext context) { - return super.visitConcatenate(elm, context); - } - - @Override - public ElmRequirement visitCombine(Combine elm, ElmRequirementsContext context) { - return super.visitCombine(elm, context); - } - @Override public ElmRequirement visitSplit(Split elm, ElmRequirementsContext context) { - // If the separator is a literal, infer based only on the string to split argument + // If the separator is a literal, infer based only on the string to split + // argument if (elm.getSeparator() instanceof Literal) { return visitElement(elm.getStringToSplit(), context); } return super.visitSplit(elm, context); } - @Override - public ElmRequirement visitLength(Length elm, ElmRequirementsContext context) { - return super.visitLength(elm, context); - } - - @Override - public ElmRequirement visitUpper(Upper elm, ElmRequirementsContext context) { - return super.visitUpper(elm, context); - } - - @Override - public ElmRequirement visitLower(Lower elm, ElmRequirementsContext context) { - return super.visitLower(elm, context); - } - - @Override - public ElmRequirement visitIndexer(Indexer elm, ElmRequirementsContext context) { - return super.visitIndexer(elm, context); - } - - @Override - public ElmRequirement visitPositionOf(PositionOf elm, ElmRequirementsContext context) { - return super.visitPositionOf(elm, context); - } - - @Override - public ElmRequirement visitSubstring(Substring elm, ElmRequirementsContext context) { - return super.visitSubstring(elm, context); - } - - @Override - public ElmRequirement visitDurationBetween(DurationBetween elm, ElmRequirementsContext context) { - return super.visitDurationBetween(elm, context); - } - - @Override - public ElmRequirement visitDifferenceBetween(DifferenceBetween elm, ElmRequirementsContext context) { - return super.visitDifferenceBetween(elm, context); - } - - @Override - public ElmRequirement visitDateFrom(DateFrom elm, ElmRequirementsContext context) { - return super.visitDateFrom(elm, context); - } - - @Override - public ElmRequirement visitTimeFrom(TimeFrom elm, ElmRequirementsContext context) { - return super.visitTimeFrom(elm, context); - } - - @Override - public ElmRequirement visitTimezoneOffsetFrom(TimezoneOffsetFrom elm, ElmRequirementsContext context) { - return super.visitTimezoneOffsetFrom(elm, context); - } - - @Override - public ElmRequirement visitDateTimeComponentFrom(DateTimeComponentFrom elm, ElmRequirementsContext context) { - return super.visitDateTimeComponentFrom(elm, context); - } - @Override public ElmRequirement visitTimeOfDay(TimeOfDay elm, ElmRequirementsContext context) { return new ElmOperatorRequirement(context.getCurrentLibraryIdentifier(), elm); @@ -968,276 +627,6 @@ public ElmRequirement visitTime(Time elm, ElmRequirementsContext context) { return result; } - @Override - public ElmRequirement visitSameAs(SameAs elm, ElmRequirementsContext context) { - return super.visitSameAs(elm, context); - } - - @Override - public ElmRequirement visitSameOrBefore(SameOrBefore elm, ElmRequirementsContext context) { - return super.visitSameOrBefore(elm, context); - } - - @Override - public ElmRequirement visitSameOrAfter(SameOrAfter elm, ElmRequirementsContext context) { - return super.visitSameOrAfter(elm, context); - } - - @Override - public ElmRequirement visitWidth(Width elm, ElmRequirementsContext context) { - return super.visitWidth(elm, context); - } - - @Override - public ElmRequirement visitStart(Start elm, ElmRequirementsContext context) { - return super.visitStart(elm, context); - } - - @Override - public ElmRequirement visitEnd(End elm, ElmRequirementsContext context) { - return super.visitEnd(elm, context); - } - - @Override - public ElmRequirement visitContains(Contains elm, ElmRequirementsContext context) { - return super.visitContains(elm, context); - } - - @Override - public ElmRequirement visitProperContains(ProperContains elm, ElmRequirementsContext context) { - return super.visitProperContains(elm, context); - } - - @Override - public ElmRequirement visitIn(In elm, ElmRequirementsContext context) { - return super.visitIn(elm, context); - } - - @Override - public ElmRequirement visitProperIn(ProperIn elm, ElmRequirementsContext context) { - return super.visitProperIn(elm, context); - } - - @Override - public ElmRequirement visitIncludes(Includes elm, ElmRequirementsContext context) { - return super.visitIncludes(elm, context); - } - - @Override - public ElmRequirement visitIncludedIn(IncludedIn elm, ElmRequirementsContext context) { - return super.visitIncludedIn(elm, context); - } - - @Override - public ElmRequirement visitProperIncludes(ProperIncludes elm, ElmRequirementsContext context) { - return super.visitProperIncludes(elm, context); - } - - @Override - public ElmRequirement visitProperIncludedIn(ProperIncludedIn elm, ElmRequirementsContext context) { - return super.visitProperIncludedIn(elm, context); - } - - @Override - public ElmRequirement visitBefore(Before elm, ElmRequirementsContext context) { - return super.visitBefore(elm, context); - } - - @Override - public ElmRequirement visitAfter(After elm, ElmRequirementsContext context) { - return super.visitAfter(elm, context); - } - - @Override - public ElmRequirement visitMeets(Meets elm, ElmRequirementsContext context) { - return super.visitMeets(elm, context); - } - - @Override - public ElmRequirement visitMeetsBefore(MeetsBefore elm, ElmRequirementsContext context) { - return super.visitMeetsBefore(elm, context); - } - - @Override - public ElmRequirement visitMeetsAfter(MeetsAfter elm, ElmRequirementsContext context) { - return super.visitMeetsAfter(elm, context); - } - - @Override - public ElmRequirement visitOverlaps(Overlaps elm, ElmRequirementsContext context) { - return super.visitOverlaps(elm, context); - } - - @Override - public ElmRequirement visitOverlapsBefore(OverlapsBefore elm, ElmRequirementsContext context) { - return super.visitOverlapsBefore(elm, context); - } - - @Override - public ElmRequirement visitOverlapsAfter(OverlapsAfter elm, ElmRequirementsContext context) { - return super.visitOverlapsAfter(elm, context); - } - - @Override - public ElmRequirement visitStarts(Starts elm, ElmRequirementsContext context) { - return super.visitStarts(elm, context); - } - - @Override - public ElmRequirement visitEnds(Ends elm, ElmRequirementsContext context) { - return super.visitEnds(elm, context); - } - - @Override - public ElmRequirement visitCollapse(Collapse elm, ElmRequirementsContext context) { - return super.visitCollapse(elm, context); - } - - @Override - public ElmRequirement visitUnion(Union elm, ElmRequirementsContext context) { - return super.visitUnion(elm, context); - } - - @Override - public ElmRequirement visitIntersect(Intersect elm, ElmRequirementsContext context) { - return super.visitIntersect(elm, context); - } - - @Override - public ElmRequirement visitExcept(Except elm, ElmRequirementsContext context) { - return super.visitExcept(elm, context); - } - - @Override - public ElmRequirement visitExists(Exists elm, ElmRequirementsContext context) { - return super.visitExists(elm, context); - } - - @Override - public ElmRequirement visitTimes(Times elm, ElmRequirementsContext context) { - return super.visitTimes(elm, context); - } - - @Override - public ElmRequirement visitFilter(Filter elm, ElmRequirementsContext context) { - return super.visitFilter(elm, context); - } - - @Override - public ElmRequirement visitFirst(First elm, ElmRequirementsContext context) { - return super.visitFirst(elm, context); - } - - @Override - public ElmRequirement visitLast(Last elm, ElmRequirementsContext context) { - return super.visitLast(elm, context); - } - - @Override - public ElmRequirement visitIndexOf(IndexOf elm, ElmRequirementsContext context) { - return super.visitIndexOf(elm, context); - } - - @Override - public ElmRequirement visitFlatten(Flatten elm, ElmRequirementsContext context) { - return super.visitFlatten(elm, context); - } - - @Override - public ElmRequirement visitSort(Sort elm, ElmRequirementsContext context) { - return super.visitSort(elm, context); - } - - @Override - public ElmRequirement visitForEach(ForEach elm, ElmRequirementsContext context) { - return super.visitForEach(elm, context); - } - - @Override - public ElmRequirement visitDistinct(Distinct elm, ElmRequirementsContext context) { - return super.visitDistinct(elm, context); - } - - @Override - public ElmRequirement visitCurrent(Current elm, ElmRequirementsContext context) { - return super.visitCurrent(elm, context); - } - - @Override - public ElmRequirement visitSingletonFrom(SingletonFrom elm, ElmRequirementsContext context) { - return super.visitSingletonFrom(elm, context); - } - - @Override - public ElmRequirement visitAggregateExpression(AggregateExpression elm, ElmRequirementsContext context) { - return super.visitAggregateExpression(elm, context); - } - - @Override - public ElmRequirement visitCount(Count elm, ElmRequirementsContext context) { - return super.visitCount(elm, context); - } - - @Override - public ElmRequirement visitSum(Sum elm, ElmRequirementsContext context) { - return super.visitSum(elm, context); - } - - @Override - public ElmRequirement visitMin(Min elm, ElmRequirementsContext context) { - return super.visitMin(elm, context); - } - - @Override - public ElmRequirement visitMax(Max elm, ElmRequirementsContext context) { - return super.visitMax(elm, context); - } - - @Override - public ElmRequirement visitAvg(Avg elm, ElmRequirementsContext context) { - return super.visitAvg(elm, context); - } - - @Override - public ElmRequirement visitMedian(Median elm, ElmRequirementsContext context) { - return super.visitMedian(elm, context); - } - - @Override - public ElmRequirement visitMode(Mode elm, ElmRequirementsContext context) { - return super.visitMode(elm, context); - } - - @Override - public ElmRequirement visitVariance(Variance elm, ElmRequirementsContext context) { - return super.visitVariance(elm, context); - } - - @Override - public ElmRequirement visitPopulationVariance(PopulationVariance elm, ElmRequirementsContext context) { - return super.visitPopulationVariance(elm, context); - } - - @Override - public ElmRequirement visitStdDev(StdDev elm, ElmRequirementsContext context) { - return super.visitStdDev(elm, context); - } - - @Override - public ElmRequirement visitPopulationStdDev(PopulationStdDev elm, ElmRequirementsContext context) { - return super.visitPopulationStdDev(elm, context); - } - - @Override - public ElmRequirement visitAllTrue(AllTrue elm, ElmRequirementsContext context) { - return super.visitAllTrue(elm, context); - } - - @Override - public ElmRequirement visitAnyTrue(AnyTrue elm, ElmRequirementsContext context) { - return super.visitAnyTrue(elm, context); - } - @Override public ElmRequirement visitProperty(Property elm, ElmRequirementsContext context) { ElmRequirement visitResult = super.visitProperty(elm, context); @@ -1264,9 +653,9 @@ public ElmRequirement visitProperty(Property elm, ElmRequirementsContext context return result; } - @Override - public ElmRequirement visitChildren(AliasedQuerySource elm, ElmRequirementsContext context) { - // Override visit behavior because we need to exit the definition context prior to traversing the such that + public ElmRequirement commonAliasedQuerySource(AliasedQuerySource elm, ElmRequirementsContext context) { + // Override visit behavior because we need to exit the definition context prior + // to traversing the such that // condition // Such that traversal happens in the visitChildren relationship ElmRequirement result = defaultResult(elm, context); @@ -1280,7 +669,8 @@ public ElmRequirement visitChildren(AliasedQuerySource elm, ElmRequirementsConte } finally { aliasContext = context.getCurrentQueryContext().exitAliasDefinitionContext(result); } - // If this is an operator requirement, report it directly to the context, otherwise the context it contains will + // If this is an operator requirement, report it directly to the context, + // otherwise the context it contains will // not be reported // since query requirements are abstracted to an ElmDataRequirement if (result instanceof ElmOperatorRequirement) { @@ -1290,32 +680,26 @@ public ElmRequirement visitChildren(AliasedQuerySource elm, ElmRequirementsConte } @Override - public ElmRequirement visitAliasedQuerySource(AliasedQuerySource elm, ElmRequirementsContext context) { - return super.visitAliasedQuerySource(elm, context); - } + public ElmRequirement visitWith(With elm, ElmRequirementsContext context) { + ElmRequirement result = commonAliasedQuerySource((AliasedQuerySource) elm, context); - @Override - public ElmRequirement visitLetClause(LetClause elm, ElmRequirementsContext context) { - ElmRequirement result = defaultResult(elm, context); - ElmQueryLetContext letContext = null; - context.getCurrentQueryContext().enterLetDefinitionContext(elm); - try { - if (elm.getExpression() != null) { - ElmRequirement childResult = super.visitLetClause(elm, context); - result = aggregateResult(result, childResult); - } - } finally { - letContext = context.getCurrentQueryContext().exitLetDefinitionContext(result); + if (elm.getSuchThat() != null) { + ElmRequirement childResult = visitExpression(elm.getSuchThat(), context); + context.getCurrentQueryContext().reportQueryRequirements(childResult); + result = aggregateResult(result, childResult); } - return letContext.getRequirements(); + + context.getCurrentQueryContext().descopeAlias(elm); + + return result; } @Override - public ElmRequirement visitChildren(RelationshipClause elm, ElmRequirementsContext context) { - ElmRequirement result = visitChildren((AliasedQuerySource) elm, context); + public ElmRequirement visitWithout(Without elm, ElmRequirementsContext context) { + ElmRequirement result = commonAliasedQuerySource((AliasedQuerySource) elm, context); if (elm.getSuchThat() != null) { - ElmRequirement childResult = visitSuchThatClause(elm.getSuchThat(), elm instanceof With, context); + ElmRequirement childResult = visitExpression(elm.getSuchThat(), context); result = aggregateResult(result, childResult); } @@ -1325,65 +709,76 @@ public ElmRequirement visitChildren(RelationshipClause elm, ElmRequirementsConte } @Override - public ElmRequirement visitRelationshipClause(RelationshipClause elm, ElmRequirementsContext context) { - return super.visitRelationshipClause(elm, context); - } - - @Override - public ElmRequirement visitWith(With elm, ElmRequirementsContext context) { - return super.visitWith(elm, context); - } - - @Override - public ElmRequirement visitWithout(Without elm, ElmRequirementsContext context) { - return super.visitWithout(elm, context); - } + public ElmRequirement visitAliasedQuerySource(AliasedQuerySource elm, ElmRequirementsContext context) { + if (elm instanceof RelationshipClause) { + return visitRelationshipClause((RelationshipClause) elm, context); + } - @Override - public ElmRequirement visitSortByItem(SortByItem elm, ElmRequirementsContext context) { - return super.visitSortByItem(elm, context); + return commonAliasedQuerySource(elm, context); } @Override - public ElmRequirement visitByDirection(ByDirection elm, ElmRequirementsContext context) { - return super.visitByDirection(elm, context); + public ElmRequirement visitLetClause(LetClause elm, ElmRequirementsContext context) { + ElmRequirement result = defaultResult(elm, context); + ElmQueryLetContext letContext = null; + context.getCurrentQueryContext().enterLetDefinitionContext(elm); + try { + if (elm.getExpression() != null) { + ElmRequirement childResult = super.visitLetClause(elm, context); + result = aggregateResult(result, childResult); + } + } finally { + letContext = context.getCurrentQueryContext().exitLetDefinitionContext(result); + } + return letContext.getRequirements(); } - @Override - public ElmRequirement visitByColumn(ByColumn elm, ElmRequirementsContext context) { - return super.visitByColumn(elm, context); - } + // This is most a copy of the super-class visitQuery + // But it reports the requirements of the where clause to the requirements + // context + public ElmRequirement innerVisitQuery(Query elm, ElmRequirementsContext context) { + ElmRequirement result = defaultResult(elm, context); + for (var source : elm.getSource()) { + ElmRequirement childResult = visitAliasedQuerySource(source, context); + result = aggregateResult(result, childResult); + } + for (var let : elm.getLet()) { + ElmRequirement childResult = visitLetClause(let, context); + result = aggregateResult(result, childResult); + } - @Override - public ElmRequirement visitByExpression(ByExpression elm, ElmRequirementsContext context) { - return super.visitByExpression(elm, context); - } + for (var r : elm.getRelationship()) { + ElmRequirement childResult = visitRelationshipClause(r, context); + result = aggregateResult(result, childResult); + } - @Override - public ElmRequirement visitSortClause(SortClause elm, ElmRequirementsContext context) { - return super.visitSortClause(elm, context); - } + if (elm.getWhere() != null) { + ElmRequirement childResult = visitExpression(elm.getWhere(), context); + // This is the one line that's different between this implementation + // and the super implementation + context.getCurrentQueryContext().reportQueryRequirements(childResult); + result = aggregateResult(result, childResult); + } + if (elm.getReturn() != null) { + ElmRequirement childResult = visitReturnClause(elm.getReturn(), context); + result = aggregateResult(result, childResult); + } - @Override - public ElmRequirement visitReturnClause(ReturnClause elm, ElmRequirementsContext context) { - return super.visitReturnClause(elm, context); - } + if (elm.getAggregate() != null) { + ElmRequirement childResult = visitAggregateClause(elm.getAggregate(), context); + result = aggregateResult(result, childResult); + } - @Override - public ElmRequirement visitWhereClause(Expression elm, ElmRequirementsContext context) { - ElmRequirement childResult = super.visitWhereClause(elm, context); - context.getCurrentQueryContext().reportQueryRequirements(childResult); - return childResult; - } + if (elm.getSort() != null) { + ElmRequirement childResult = visitSortClause(elm.getSort(), context); + result = aggregateResult(result, childResult); + } - @Override - public ElmRequirement visitSuchThatClause(Expression elm, boolean isWith, ElmRequirementsContext context) { - ElmRequirement childResult = super.visitSuchThatClause(elm, isWith, context); - if (isWith) { - context.getCurrentQueryContext().reportQueryRequirements(childResult); + if (elm.getResultTypeSpecifier() != null) { + ElmRequirement childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); } - // TODO: Determine how to incorporate requirements from a without clause - return childResult; + return result; } @Override @@ -1392,7 +787,7 @@ public ElmRequirement visitQuery(Query elm, ElmRequirementsContext context) { ElmQueryContext queryContext = null; context.enterQueryContext(elm); try { - childResult = super.visitQuery(elm, context); + childResult = innerVisitQuery(elm, context); } finally { queryContext = context.exitQueryContext(); } @@ -1402,26 +797,6 @@ public ElmRequirement visitQuery(Query elm, ElmRequirementsContext context) { return result; } - @Override - public ElmRequirement visitAliasRef(AliasRef elm, ElmRequirementsContext context) { - return super.visitAliasRef(elm, context); - } - - @Override - public ElmRequirement visitQueryLetRef(QueryLetRef elm, ElmRequirementsContext context) { - return super.visitQueryLetRef(elm, context); - } - - @Override - public ElmRequirement visitCode(Code elm, ElmRequirementsContext context) { - return super.visitCode(elm, context); - } - - @Override - public ElmRequirement visitConcept(Concept elm, ElmRequirementsContext context) { - return super.visitConcept(elm, context); - } - @Override public ElmRequirement visitInCodeSystem(InCodeSystem elm, ElmRequirementsContext context) { if (elm.getCode() != null && (elm.getCodesystem() != null || elm.getCodesystemExpression() != null)) { @@ -1474,56 +849,6 @@ public ElmRequirement visitAnyInValueSet(AnyInValueSet elm, ElmRequirementsConte return super.visitAnyInValueSet(elm, context); } - @Override - public ElmRequirement visitQuantity(Quantity elm, ElmRequirementsContext context) { - return super.visitQuantity(elm, context); - } - - @Override - public ElmRequirement visitCalculateAge(CalculateAge elm, ElmRequirementsContext context) { - return super.visitCalculateAge(elm, context); - } - - @Override - public ElmRequirement visitCalculateAgeAt(CalculateAgeAt elm, ElmRequirementsContext context) { - return super.visitCalculateAgeAt(elm, context); - } - - @Override - public ElmRequirement visitElement(Element elm, ElmRequirementsContext context) { - return super.visitElement(elm, context); - } - - @Override - public ElmRequirement visitTypeSpecifier(TypeSpecifier elm, ElmRequirementsContext context) { - return super.visitTypeSpecifier(elm, context); - } - - @Override - public ElmRequirement visitNamedTypeSpecifier(NamedTypeSpecifier elm, ElmRequirementsContext context) { - return super.visitNamedTypeSpecifier(elm, context); - } - - @Override - public ElmRequirement visitIntervalTypeSpecifier(IntervalTypeSpecifier elm, ElmRequirementsContext context) { - return super.visitIntervalTypeSpecifier(elm, context); - } - - @Override - public ElmRequirement visitListTypeSpecifier(ListTypeSpecifier elm, ElmRequirementsContext context) { - return super.visitListTypeSpecifier(elm, context); - } - - @Override - public ElmRequirement visitTupleElementDefinition(TupleElementDefinition elm, ElmRequirementsContext context) { - return super.visitTupleElementDefinition(elm, context); - } - - @Override - public ElmRequirement visitTupleTypeSpecifier(TupleTypeSpecifier elm, ElmRequirementsContext context) { - return super.visitTupleTypeSpecifier(elm, context); - } - @Override public ElmRequirement visitUsingDef(UsingDef elm, ElmRequirementsContext context) { context.reportUsingDef(elm); diff --git a/Src/java/elm-jackson/src/main/java/org/cqframework/cql/elm/serializing/jackson/ElmJsonMapper.java b/Src/java/elm-jackson/src/main/java/org/cqframework/cql/elm/serializing/jackson/ElmJsonMapper.java index 352dc3491..3a7eb1cb9 100644 --- a/Src/java/elm-jackson/src/main/java/org/cqframework/cql/elm/serializing/jackson/ElmJsonMapper.java +++ b/Src/java/elm-jackson/src/main/java/org/cqframework/cql/elm/serializing/jackson/ElmJsonMapper.java @@ -19,8 +19,8 @@ public class ElmJsonMapper { .enable(SerializationFeature.INDENT_OUTPUT) .enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY) .enable(MapperFeature.USE_BASE_TYPE_AS_DEFAULT_IMPL) - .defaultPropertyInclusion( - JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, JsonInclude.Include.NON_NULL)) + .defaultPropertyInclusion(JsonInclude.Value.construct( + JsonInclude.Include.CUSTOM, JsonInclude.Include.NON_EMPTY, NoEmptyListsFilter.class, Void.class)) .addModule(new JakartaXmlBindAnnotationModule()) .addMixIn(Trackable.class, TrackableMixIn.class) .addMixIn(TypeSpecifier.class, TypeSpecifierMixIn.class) diff --git a/Src/java/elm-jackson/src/main/java/org/cqframework/cql/elm/serializing/jackson/ElmXmlMapper.java b/Src/java/elm-jackson/src/main/java/org/cqframework/cql/elm/serializing/jackson/ElmXmlMapper.java index 7f08af91e..c107afc94 100644 --- a/Src/java/elm-jackson/src/main/java/org/cqframework/cql/elm/serializing/jackson/ElmXmlMapper.java +++ b/Src/java/elm-jackson/src/main/java/org/cqframework/cql/elm/serializing/jackson/ElmXmlMapper.java @@ -30,8 +30,8 @@ public class ElmXmlMapper { .enable(SerializationFeature.INDENT_OUTPUT) .enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY) .enable(MapperFeature.USE_BASE_TYPE_AS_DEFAULT_IMPL) - .defaultPropertyInclusion( - JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, JsonInclude.Include.NON_NULL)) + .defaultPropertyInclusion(JsonInclude.Value.construct( + JsonInclude.Include.CUSTOM, JsonInclude.Include.NON_EMPTY, NoEmptyListsFilter.class, Void.class)) .addModule(new JakartaXmlBindAnnotationModule()) .addMixIn(Trackable.class, TrackableMixIn.class) .addMixIn(TypeSpecifier.class, TypeSpecifierMixIn.class) diff --git a/Src/java/elm-jackson/src/main/java/org/cqframework/cql/elm/serializing/jackson/NoEmptyListsFilter.java b/Src/java/elm-jackson/src/main/java/org/cqframework/cql/elm/serializing/jackson/NoEmptyListsFilter.java new file mode 100644 index 000000000..cb7240607 --- /dev/null +++ b/Src/java/elm-jackson/src/main/java/org/cqframework/cql/elm/serializing/jackson/NoEmptyListsFilter.java @@ -0,0 +1,20 @@ +package org.cqframework.cql.elm.serializing.jackson; + +import java.util.Collection; + +class NoEmptyListsFilter { + + // True if values should be filtered, false otherwise. + @Override + public boolean equals(Object obj) { + if (obj == null) { + return true; + } + + if (obj instanceof Collection) { + return ((Collection) obj).isEmpty(); + } + + return false; + } +} diff --git a/Src/java/elm/build.gradle b/Src/java/elm/build.gradle index 2b9842213..9791c0612 100644 --- a/Src/java/elm/build.gradle +++ b/Src/java/elm/build.gradle @@ -5,6 +5,8 @@ plugins { dependencies { api project(':model') + testImplementation 'org.jeasy:easy-random-core:5.0.0' + testImplementation 'com.tngtech.archunit:archunit:1.2.1' } generateSources { diff --git a/Src/java/elm/src/main/java/org/cqframework/cql/elm/IdObjectFactory.java b/Src/java/elm/src/main/java/org/cqframework/cql/elm/IdObjectFactory.java new file mode 100644 index 000000000..582cb919c --- /dev/null +++ b/Src/java/elm/src/main/java/org/cqframework/cql/elm/IdObjectFactory.java @@ -0,0 +1,1246 @@ +package org.cqframework.cql.elm; + +import jakarta.xml.bind.JAXBElement; +import org.hl7.elm.r1.*; + +/* + * Extends the ObjectFactory to allow for decorating the elements created by the factory. If no decorator is provided, nodes are + * given monotonically increasing ids. + * + */ +public class IdObjectFactory extends ObjectFactory { + + private int nextId = 0; + + /** + * returns the next id and increments the counter + */ + public String nextId() { + return Integer.toString(nextId++); + } + + @Override + public Abs createAbs() { + return super.createAbs().withLocalId(nextId()); + } + + @Override + public Add createAdd() { + return super.createAdd().withLocalId(nextId()); + } + + @Override + public After createAfter() { + return super.createAfter().withLocalId(nextId()); + } + + @Override + public Aggregate createAggregate() { + return super.createAggregate().withLocalId(nextId()); + } + + @Override + public AggregateClause createAggregateClause() { + return super.createAggregateClause().withLocalId(nextId()); + } + + @Override + public AliasRef createAliasRef() { + return super.createAliasRef().withLocalId(nextId()); + } + + @Override + public AliasedQuerySource createAliasedQuerySource() { + return super.createAliasedQuerySource().withLocalId(nextId()); + } + + @Override + public AllTrue createAllTrue() { + return super.createAllTrue().withLocalId(nextId()); + } + + @Override + public And createAnd() { + return super.createAnd().withLocalId(nextId()); + } + + @Override + public AnyInCodeSystem createAnyInCodeSystem() { + return super.createAnyInCodeSystem().withLocalId(nextId()); + } + + @Override + public AnyInValueSet createAnyInValueSet() { + return super.createAnyInValueSet().withLocalId(nextId()); + } + + @Override + public AnyTrue createAnyTrue() { + return super.createAnyTrue().withLocalId(nextId()); + } + + @Override + public As createAs() { + return super.createAs().withLocalId(nextId()); + } + + @Override + public Avg createAvg() { + return super.createAvg().withLocalId(nextId()); + } + + @Override + public Before createBefore() { + return super.createBefore().withLocalId(nextId()); + } + + @Override + public ByColumn createByColumn() { + return super.createByColumn().withLocalId(nextId()); + } + + @Override + public ByDirection createByDirection() { + return super.createByDirection().withLocalId(nextId()); + } + + @Override + public ByExpression createByExpression() { + return super.createByExpression().withLocalId(nextId()); + } + + @Override + public CalculateAge createCalculateAge() { + return super.createCalculateAge().withLocalId(nextId()); + } + + @Override + public CalculateAgeAt createCalculateAgeAt() { + return super.createCalculateAgeAt().withLocalId(nextId()); + } + + @Override + public CanConvert createCanConvert() { + return super.createCanConvert().withLocalId(nextId()); + } + + @Override + public CanConvertQuantity createCanConvertQuantity() { + return super.createCanConvertQuantity().withLocalId(nextId()); + } + + @Override + public Case createCase() { + return super.createCase().withLocalId(nextId()); + } + + @Override + public CaseItem createCaseItem() { + return super.createCaseItem().withLocalId(nextId()); + } + + @Override + public Ceiling createCeiling() { + return super.createCeiling().withLocalId(nextId()); + } + + @Override + public Children createChildren() { + return super.createChildren().withLocalId(nextId()); + } + + @Override + public ChoiceTypeSpecifier createChoiceTypeSpecifier() { + return super.createChoiceTypeSpecifier().withLocalId(nextId()); + } + + @Override + public Coalesce createCoalesce() { + return super.createCoalesce().withLocalId(nextId()); + } + + @Override + public Code createCode() { + return super.createCode().withLocalId(nextId()); + } + + @Override + public CodeDef createCodeDef() { + return super.createCodeDef().withLocalId(nextId()); + } + + @Override + public CodeFilterElement createCodeFilterElement() { + return super.createCodeFilterElement().withLocalId(nextId()); + } + + @Override + public CodeRef createCodeRef() { + return super.createCodeRef().withLocalId(nextId()); + } + + @Override + public CodeSystemDef createCodeSystemDef() { + return super.createCodeSystemDef().withLocalId(nextId()); + } + + @Override + public CodeSystemRef createCodeSystemRef() { + return super.createCodeSystemRef().withLocalId(nextId()); + } + + @Override + public Collapse createCollapse() { + return super.createCollapse().withLocalId(nextId()); + } + + @Override + public Combine createCombine() { + return super.createCombine().withLocalId(nextId()); + } + + @Override + public Concatenate createConcatenate() { + return super.createConcatenate().withLocalId(nextId()); + } + + @Override + public Concept createConcept() { + return super.createConcept().withLocalId(nextId()); + } + + @Override + public ConceptDef createConceptDef() { + return super.createConceptDef().withLocalId(nextId()); + } + + @Override + public ConceptRef createConceptRef() { + return super.createConceptRef().withLocalId(nextId()); + } + + @Override + public Contains createContains() { + return super.createContains().withLocalId(nextId()); + } + + @Override + public ContextDef createContextDef() { + return super.createContextDef().withLocalId(nextId()); + } + + @Override + public Convert createConvert() { + return super.createConvert().withLocalId(nextId()); + } + + @Override + public ConvertQuantity createConvertQuantity() { + return super.createConvertQuantity().withLocalId(nextId()); + } + + @Override + public ConvertsToBoolean createConvertsToBoolean() { + return super.createConvertsToBoolean().withLocalId(nextId()); + } + + @Override + public ConvertsToDate createConvertsToDate() { + return super.createConvertsToDate().withLocalId(nextId()); + } + + @Override + public ConvertsToDateTime createConvertsToDateTime() { + return super.createConvertsToDateTime().withLocalId(nextId()); + } + + @Override + public ConvertsToDecimal createConvertsToDecimal() { + return super.createConvertsToDecimal().withLocalId(nextId()); + } + + @Override + public ConvertsToInteger createConvertsToInteger() { + return super.createConvertsToInteger().withLocalId(nextId()); + } + + @Override + public ConvertsToLong createConvertsToLong() { + return super.createConvertsToLong().withLocalId(nextId()); + } + + @Override + public ConvertsToQuantity createConvertsToQuantity() { + return super.createConvertsToQuantity().withLocalId(nextId()); + } + + @Override + public ConvertsToRatio createConvertsToRatio() { + return super.createConvertsToRatio().withLocalId(nextId()); + } + + @Override + public ConvertsToString createConvertsToString() { + return super.createConvertsToString().withLocalId(nextId()); + } + + @Override + public ConvertsToTime createConvertsToTime() { + return super.createConvertsToTime().withLocalId(nextId()); + } + + @Override + public Count createCount() { + return super.createCount().withLocalId(nextId()); + } + + @Override + public Current createCurrent() { + return super.createCurrent().withLocalId(nextId()); + } + + @Override + public Date createDate() { + return super.createDate().withLocalId(nextId()); + } + + @Override + public DateFilterElement createDateFilterElement() { + return super.createDateFilterElement().withLocalId(nextId()); + } + + @Override + public DateFrom createDateFrom() { + return super.createDateFrom().withLocalId(nextId()); + } + + @Override + public DateTime createDateTime() { + return super.createDateTime().withLocalId(nextId()); + } + + @Override + public DateTimeComponentFrom createDateTimeComponentFrom() { + return super.createDateTimeComponentFrom().withLocalId(nextId()); + } + + @Override + public Descendents createDescendents() { + return super.createDescendents().withLocalId(nextId()); + } + + @Override + public DifferenceBetween createDifferenceBetween() { + return super.createDifferenceBetween().withLocalId(nextId()); + } + + @Override + public Distinct createDistinct() { + return super.createDistinct().withLocalId(nextId()); + } + + @Override + public Divide createDivide() { + return super.createDivide().withLocalId(nextId()); + } + + @Override + public DurationBetween createDurationBetween() { + return super.createDurationBetween().withLocalId(nextId()); + } + + @Override + public End createEnd() { + return super.createEnd().withLocalId(nextId()); + } + + @Override + public Ends createEnds() { + return super.createEnds().withLocalId(nextId()); + } + + @Override + public EndsWith createEndsWith() { + return super.createEndsWith().withLocalId(nextId()); + } + + @Override + public Equal createEqual() { + return super.createEqual().withLocalId(nextId()); + } + + @Override + public Equivalent createEquivalent() { + return super.createEquivalent().withLocalId(nextId()); + } + + @Override + public Except createExcept() { + return super.createExcept().withLocalId(nextId()); + } + + @Override + public Exists createExists() { + return super.createExists().withLocalId(nextId()); + } + + @Override + public Exp createExp() { + return super.createExp().withLocalId(nextId()); + } + + @Override + public Expand createExpand() { + return super.createExpand().withLocalId(nextId()); + } + + @Override + public ExpandValueSet createExpandValueSet() { + return super.createExpandValueSet().withLocalId(nextId()); + } + + @Override + public ExpressionDef createExpressionDef() { + return super.createExpressionDef().withLocalId(nextId()); + } + + @Override + public ExpressionRef createExpressionRef() { + return super.createExpressionRef().withLocalId(nextId()); + } + + @Override + public Filter createFilter() { + return super.createFilter().withLocalId(nextId()); + } + + @Override + public First createFirst() { + return super.createFirst().withLocalId(nextId()); + } + + @Override + public Flatten createFlatten() { + return super.createFlatten().withLocalId(nextId()); + } + + @Override + public Floor createFloor() { + return super.createFloor().withLocalId(nextId()); + } + + @Override + public ForEach createForEach() { + return super.createForEach().withLocalId(nextId()); + } + + @Override + public FunctionDef createFunctionDef() { + return super.createFunctionDef().withLocalId(nextId()); + } + + @Override + public FunctionRef createFunctionRef() { + return super.createFunctionRef().withLocalId(nextId()); + } + + @Override + public GeometricMean createGeometricMean() { + return super.createGeometricMean().withLocalId(nextId()); + } + + @Override + public Greater createGreater() { + return super.createGreater().withLocalId(nextId()); + } + + @Override + public GreaterOrEqual createGreaterOrEqual() { + return super.createGreaterOrEqual().withLocalId(nextId()); + } + + @Override + public HighBoundary createHighBoundary() { + return super.createHighBoundary().withLocalId(nextId()); + } + + @Override + public IdentifierRef createIdentifierRef() { + return super.createIdentifierRef().withLocalId(nextId()); + } + + @Override + public If createIf() { + return super.createIf().withLocalId(nextId()); + } + + @Override + public Implies createImplies() { + return super.createImplies().withLocalId(nextId()); + } + + @Override + public In createIn() { + return super.createIn().withLocalId(nextId()); + } + + @Override + public InCodeSystem createInCodeSystem() { + return super.createInCodeSystem().withLocalId(nextId()); + } + + @Override + public InValueSet createInValueSet() { + return super.createInValueSet().withLocalId(nextId()); + } + + @Override + public IncludeDef createIncludeDef() { + return super.createIncludeDef().withLocalId(nextId()); + } + + @Override + public IncludeElement createIncludeElement() { + return super.createIncludeElement().withLocalId(nextId()); + } + + @Override + public IncludedIn createIncludedIn() { + return super.createIncludedIn().withLocalId(nextId()); + } + + @Override + public Includes createIncludes() { + return super.createIncludes().withLocalId(nextId()); + } + + @Override + public IndexOf createIndexOf() { + return super.createIndexOf().withLocalId(nextId()); + } + + @Override + public Indexer createIndexer() { + return super.createIndexer().withLocalId(nextId()); + } + + @Override + public Instance createInstance() { + return super.createInstance().withLocalId(nextId()); + } + + // @Override + // public InstanceElement createInstanceElement() { + // return super.createInstanceElement().withLocalId(nextId()); + // } + + @Override + public Intersect createIntersect() { + return super.createIntersect().withLocalId(nextId()); + } + + @Override + public Interval createInterval() { + return super.createInterval().withLocalId(nextId()); + } + + @Override + public IntervalTypeSpecifier createIntervalTypeSpecifier() { + return super.createIntervalTypeSpecifier().withLocalId(nextId()); + } + + @Override + public Is createIs() { + return super.createIs().withLocalId(nextId()); + } + + @Override + public IsFalse createIsFalse() { + return super.createIsFalse().withLocalId(nextId()); + } + + @Override + public IsNull createIsNull() { + return super.createIsNull().withLocalId(nextId()); + } + + @Override + public IsTrue createIsTrue() { + return super.createIsTrue().withLocalId(nextId()); + } + + @Override + public Iteration createIteration() { + return super.createIteration().withLocalId(nextId()); + } + + @Override + public Last createLast() { + return super.createLast().withLocalId(nextId()); + } + + @Override + public LastPositionOf createLastPositionOf() { + return super.createLastPositionOf().withLocalId(nextId()); + } + + @Override + public Length createLength() { + return super.createLength().withLocalId(nextId()); + } + + @Override + public Less createLess() { + return super.createLess().withLocalId(nextId()); + } + + @Override + public LessOrEqual createLessOrEqual() { + return super.createLessOrEqual().withLocalId(nextId()); + } + + @Override + public LetClause createLetClause() { + return super.createLetClause().withLocalId(nextId()); + } + + @Override + public Library createLibrary() { + return super.createLibrary().withLocalId(nextId()); + } + + @Override + public JAXBElement createLibrary(Library value) { + return super.createLibrary(value); + } + + // @Override + // public CodeSystems createLibraryCodeSystems() { + // return super.createLibraryCodeSystems().withLocalId(nextId()); + // } + + // @Override + // public Codes createLibraryCodes() { + // return super.createLibraryCodes().withLocalId(nextId()); + // } + + // @Override + // public Concepts createLibraryConcepts() { + // return super.createLibraryConcepts().withLocalId(nextId()); + // } + + // @Override + // public Contexts createLibraryContexts() { + // return super.createLibraryContexts().withLocalId(nextId()); + // } + + // @Override + // public Includes createLibraryIncludes() { + // return super.createLibraryIncludes().withLocalId(nextId()); + // } + + // @Override + // public Parameters createLibraryParameters() { + // return super.createLibraryParameters().withLocalId(nextId()); + // } + + // @Override + // public Statements createLibraryStatements() { + // return super.createLibraryStatements().withLocalId(nextId()); + // } + + // @Override + // public Usings createLibraryUsings() { + // return super.createLibraryUsings().withLocalId(nextId()); + // } + + // @Override + // public ValueSets createLibraryValueSets() { + // return super.createLibraryValueSets().withLocalId(nextId()); + // } + + @Override + public List createList() { + return super.createList().withLocalId(nextId()); + } + + @Override + public ListTypeSpecifier createListTypeSpecifier() { + return super.createListTypeSpecifier().withLocalId(nextId()); + } + + @Override + public Literal createLiteral() { + return super.createLiteral().withLocalId(nextId()); + } + + @Override + public Ln createLn() { + return super.createLn().withLocalId(nextId()); + } + + @Override + public Log createLog() { + return super.createLog().withLocalId(nextId()); + } + + @Override + public LowBoundary createLowBoundary() { + return super.createLowBoundary().withLocalId(nextId()); + } + + @Override + public Lower createLower() { + return super.createLower().withLocalId(nextId()); + } + + @Override + public Matches createMatches() { + return super.createMatches().withLocalId(nextId()); + } + + @Override + public Max createMax() { + return super.createMax().withLocalId(nextId()); + } + + @Override + public MaxValue createMaxValue() { + return super.createMaxValue().withLocalId(nextId()); + } + + @Override + public Median createMedian() { + return super.createMedian().withLocalId(nextId()); + } + + @Override + public Meets createMeets() { + return super.createMeets().withLocalId(nextId()); + } + + @Override + public MeetsAfter createMeetsAfter() { + return super.createMeetsAfter().withLocalId(nextId()); + } + + @Override + public MeetsBefore createMeetsBefore() { + return super.createMeetsBefore().withLocalId(nextId()); + } + + @Override + public Message createMessage() { + return super.createMessage().withLocalId(nextId()); + } + + @Override + public Min createMin() { + return super.createMin().withLocalId(nextId()); + } + + @Override + public MinValue createMinValue() { + return super.createMinValue().withLocalId(nextId()); + } + + @Override + public Mode createMode() { + return super.createMode().withLocalId(nextId()); + } + + @Override + public Modulo createModulo() { + return super.createModulo().withLocalId(nextId()); + } + + @Override + public Multiply createMultiply() { + return super.createMultiply().withLocalId(nextId()); + } + + @Override + public NamedTypeSpecifier createNamedTypeSpecifier() { + return super.createNamedTypeSpecifier().withLocalId(nextId()); + } + + @Override + public Negate createNegate() { + return super.createNegate().withLocalId(nextId()); + } + + @Override + public Not createNot() { + return super.createNot().withLocalId(nextId()); + } + + @Override + public NotEqual createNotEqual() { + return super.createNotEqual().withLocalId(nextId()); + } + + @Override + public Now createNow() { + return super.createNow().withLocalId(nextId()); + } + + @Override + public Null createNull() { + return super.createNull().withLocalId(nextId()); + } + + @Override + public OperandDef createOperandDef() { + return super.createOperandDef().withLocalId(nextId()); + } + + @Override + public OperandRef createOperandRef() { + return super.createOperandRef().withLocalId(nextId()); + } + + @Override + public Or createOr() { + return super.createOr().withLocalId(nextId()); + } + + @Override + public OtherFilterElement createOtherFilterElement() { + return super.createOtherFilterElement().withLocalId(nextId()); + } + + @Override + public Overlaps createOverlaps() { + return super.createOverlaps().withLocalId(nextId()); + } + + @Override + public OverlapsAfter createOverlapsAfter() { + return super.createOverlapsAfter().withLocalId(nextId()); + } + + @Override + public OverlapsBefore createOverlapsBefore() { + return super.createOverlapsBefore().withLocalId(nextId()); + } + + @Override + public ParameterDef createParameterDef() { + return super.createParameterDef().withLocalId(nextId()); + } + + @Override + public ParameterRef createParameterRef() { + return super.createParameterRef().withLocalId(nextId()); + } + + @Override + public ParameterTypeSpecifier createParameterTypeSpecifier() { + return super.createParameterTypeSpecifier().withLocalId(nextId()); + } + + @Override + public PointFrom createPointFrom() { + return super.createPointFrom().withLocalId(nextId()); + } + + @Override + public PopulationStdDev createPopulationStdDev() { + return super.createPopulationStdDev().withLocalId(nextId()); + } + + @Override + public PopulationVariance createPopulationVariance() { + return super.createPopulationVariance().withLocalId(nextId()); + } + + @Override + public PositionOf createPositionOf() { + return super.createPositionOf().withLocalId(nextId()); + } + + @Override + public Power createPower() { + return super.createPower().withLocalId(nextId()); + } + + @Override + public Precision createPrecision() { + return super.createPrecision().withLocalId(nextId()); + } + + @Override + public Predecessor createPredecessor() { + return super.createPredecessor().withLocalId(nextId()); + } + + @Override + public Product createProduct() { + return super.createProduct().withLocalId(nextId()); + } + + @Override + public ProperContains createProperContains() { + return super.createProperContains().withLocalId(nextId()); + } + + @Override + public ProperIn createProperIn() { + return super.createProperIn().withLocalId(nextId()); + } + + @Override + public ProperIncludedIn createProperIncludedIn() { + return super.createProperIncludedIn().withLocalId(nextId()); + } + + @Override + public ProperIncludes createProperIncludes() { + return super.createProperIncludes().withLocalId(nextId()); + } + + @Override + public Property createProperty() { + return super.createProperty().withLocalId(nextId()); + } + + @Override + public Quantity createQuantity() { + return super.createQuantity().withLocalId(nextId()); + } + + @Override + public Query createQuery() { + return super.createQuery().withLocalId(nextId()); + } + + @Override + public QueryLetRef createQueryLetRef() { + return super.createQueryLetRef().withLocalId(nextId()); + } + + @Override + public Ratio createRatio() { + return super.createRatio().withLocalId(nextId()); + } + + @Override + public Repeat createRepeat() { + return super.createRepeat().withLocalId(nextId()); + } + + @Override + public ReplaceMatches createReplaceMatches() { + return super.createReplaceMatches().withLocalId(nextId()); + } + + @Override + public Retrieve createRetrieve() { + return super.createRetrieve().withLocalId(nextId()); + } + + @Override + public ReturnClause createReturnClause() { + return super.createReturnClause().withLocalId(nextId()); + } + + @Override + public Round createRound() { + return super.createRound().withLocalId(nextId()); + } + + @Override + public SameAs createSameAs() { + return super.createSameAs().withLocalId(nextId()); + } + + @Override + public SameOrAfter createSameOrAfter() { + return super.createSameOrAfter().withLocalId(nextId()); + } + + @Override + public SameOrBefore createSameOrBefore() { + return super.createSameOrBefore().withLocalId(nextId()); + } + + @Override + public Search createSearch() { + return super.createSearch().withLocalId(nextId()); + } + + @Override + public SingletonFrom createSingletonFrom() { + return super.createSingletonFrom().withLocalId(nextId()); + } + + @Override + public Size createSize() { + return super.createSize().withLocalId(nextId()); + } + + @Override + public Slice createSlice() { + return super.createSlice().withLocalId(nextId()); + } + + @Override + public Sort createSort() { + return super.createSort().withLocalId(nextId()); + } + + @Override + public SortClause createSortClause() { + return super.createSortClause().withLocalId(nextId()); + } + + @Override + public Split createSplit() { + return super.createSplit().withLocalId(nextId()); + } + + @Override + public SplitOnMatches createSplitOnMatches() { + return super.createSplitOnMatches().withLocalId(nextId()); + } + + @Override + public Start createStart() { + return super.createStart().withLocalId(nextId()); + } + + @Override + public Starts createStarts() { + return super.createStarts().withLocalId(nextId()); + } + + @Override + public StartsWith createStartsWith() { + return super.createStartsWith().withLocalId(nextId()); + } + + @Override + public StdDev createStdDev() { + return super.createStdDev().withLocalId(nextId()); + } + + @Override + public Substring createSubstring() { + return super.createSubstring().withLocalId(nextId()); + } + + @Override + public SubsumedBy createSubsumedBy() { + return super.createSubsumedBy().withLocalId(nextId()); + } + + @Override + public Subsumes createSubsumes() { + return super.createSubsumes().withLocalId(nextId()); + } + + @Override + public Subtract createSubtract() { + return super.createSubtract().withLocalId(nextId()); + } + + @Override + public Successor createSuccessor() { + return super.createSuccessor().withLocalId(nextId()); + } + + @Override + public Sum createSum() { + return super.createSum().withLocalId(nextId()); + } + + @Override + public Time createTime() { + return super.createTime().withLocalId(nextId()); + } + + @Override + public TimeFrom createTimeFrom() { + return super.createTimeFrom().withLocalId(nextId()); + } + + @Override + public TimeOfDay createTimeOfDay() { + return super.createTimeOfDay().withLocalId(nextId()); + } + + @Override + public Times createTimes() { + return super.createTimes().withLocalId(nextId()); + } + + @Override + public TimezoneFrom createTimezoneFrom() { + return super.createTimezoneFrom().withLocalId(nextId()); + } + + @Override + public TimezoneOffsetFrom createTimezoneOffsetFrom() { + return super.createTimezoneOffsetFrom().withLocalId(nextId()); + } + + @Override + public ToBoolean createToBoolean() { + return super.createToBoolean().withLocalId(nextId()); + } + + @Override + public ToChars createToChars() { + return super.createToChars().withLocalId(nextId()); + } + + @Override + public ToConcept createToConcept() { + return super.createToConcept().withLocalId(nextId()); + } + + @Override + public ToDate createToDate() { + return super.createToDate().withLocalId(nextId()); + } + + @Override + public ToDateTime createToDateTime() { + return super.createToDateTime().withLocalId(nextId()); + } + + @Override + public ToDecimal createToDecimal() { + return super.createToDecimal().withLocalId(nextId()); + } + + @Override + public ToInteger createToInteger() { + return super.createToInteger().withLocalId(nextId()); + } + + @Override + public ToList createToList() { + return super.createToList().withLocalId(nextId()); + } + + @Override + public ToLong createToLong() { + return super.createToLong().withLocalId(nextId()); + } + + @Override + public ToQuantity createToQuantity() { + return super.createToQuantity().withLocalId(nextId()); + } + + @Override + public ToRatio createToRatio() { + return super.createToRatio().withLocalId(nextId()); + } + + @Override + public ToString createToString() { + return super.createToString().withLocalId(nextId()); + } + + @Override + public ToTime createToTime() { + return super.createToTime().withLocalId(nextId()); + } + + @Override + public Today createToday() { + return super.createToday().withLocalId(nextId()); + } + + @Override + public Total createTotal() { + return super.createTotal().withLocalId(nextId()); + } + + @Override + public Truncate createTruncate() { + return super.createTruncate().withLocalId(nextId()); + } + + @Override + public TruncatedDivide createTruncatedDivide() { + return super.createTruncatedDivide().withLocalId(nextId()); + } + + @Override + public Tuple createTuple() { + return super.createTuple().withLocalId(nextId()); + } + + // @Override + // public TupleElement createTupleElement() { + // return super.createTupleElement().withLocalId(nextId()); + // } + + @Override + public TupleElementDefinition createTupleElementDefinition() { + return super.createTupleElementDefinition().withLocalId(nextId()); + } + + @Override + public TupleTypeSpecifier createTupleTypeSpecifier() { + return super.createTupleTypeSpecifier().withLocalId(nextId()); + } + + @Override + public Union createUnion() { + return super.createUnion().withLocalId(nextId()); + } + + @Override + public Upper createUpper() { + return super.createUpper().withLocalId(nextId()); + } + + @Override + public UsingDef createUsingDef() { + return super.createUsingDef().withLocalId(nextId()); + } + + @Override + public ValueSetDef createValueSetDef() { + return super.createValueSetDef().withLocalId(nextId()); + } + + @Override + public ValueSetRef createValueSetRef() { + return super.createValueSetRef().withLocalId(nextId()); + } + + @Override + public Variance createVariance() { + return super.createVariance().withLocalId(nextId()); + } + + // @Override + // public VersionedIdentifier createVersionedIdentifier() { + // return super.createVersionedIdentifier().withLocalId(nextId()); + // } + + @Override + public Width createWidth() { + return super.createWidth().withLocalId(nextId()); + } + + @Override + public With createWith() { + return super.createWith().withLocalId(nextId()); + } + + @Override + public Without createWithout() { + return super.createWithout().withLocalId(nextId()); + } + + @Override + public Xor createXor() { + return super.createXor().withLocalId(nextId()); + } +} diff --git a/Src/java/elm/src/main/java/org/cqframework/cql/elm/utility/Visitors.java b/Src/java/elm/src/main/java/org/cqframework/cql/elm/utility/Visitors.java new file mode 100644 index 000000000..b03f3d74d --- /dev/null +++ b/Src/java/elm/src/main/java/org/cqframework/cql/elm/utility/Visitors.java @@ -0,0 +1,23 @@ +package org.cqframework.cql.elm.utility; + +import java.util.Objects; +import java.util.function.BiFunction; +import org.cqframework.cql.elm.tracking.Trackable; +import org.cqframework.cql.elm.visiting.FunctionalElmVisitor; + +public class Visitors { + + private Visitors() {} + + public static FunctionalElmVisitor from( + BiFunction defaultResult, BiFunction aggregateResult) { + Objects.requireNonNull(defaultResult, "defaultResult required"); + Objects.requireNonNull(aggregateResult, "aggregateResult required"); + return new FunctionalElmVisitor<>(defaultResult, aggregateResult); + } + + public static FunctionalElmVisitor from(BiFunction defaultResult) { + Objects.requireNonNull(defaultResult, "defaultResult required"); + return from(defaultResult, (a, b) -> b); + } +} diff --git a/Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/ElmBaseClinicalVisitor.java b/Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/BaseElmClinicalVisitor.java similarity index 73% rename from Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/ElmBaseClinicalVisitor.java rename to Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/BaseElmClinicalVisitor.java index 64510b3f9..2a9d56318 100644 --- a/Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/ElmBaseClinicalVisitor.java +++ b/Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/BaseElmClinicalVisitor.java @@ -7,9 +7,9 @@ * * @param The return type of the visit operation. Use {@link Void} for * @param The type of context passed to each visit method - * operations with no return type. + * operations with no return type. */ -public class ElmBaseClinicalVisitor extends ElmBaseVisitor implements ElmClinicalVisitor { +public abstract class BaseElmClinicalVisitor extends BaseElmVisitor implements ElmClinicalVisitor { @Override public T visitElement(Element elm, C context) { @@ -106,7 +106,7 @@ public T visitBinaryExpression(BinaryExpression elm, C context) { * @return the visitor result */ public T visitExpandValueSet(ExpandValueSet elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -120,9 +120,15 @@ public T visitExpandValueSet(ExpandValueSet elm, C context) { public T visitCodeFilterElement(CodeFilterElement elm, C context) { T result = defaultResult(elm, context); if (elm.getValue() != null) { - T childResult = visitElement(elm.getValue(), context); + T childResult = visitExpression(elm.getValue(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } + return result; } @@ -137,9 +143,15 @@ public T visitCodeFilterElement(CodeFilterElement elm, C context) { public T visitDateFilterElement(DateFilterElement elm, C context) { T result = defaultResult(elm, context); if (elm.getValue() != null) { - T childResult = visitElement(elm.getValue(), context); + T childResult = visitExpression(elm.getValue(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } + return result; } @@ -154,9 +166,15 @@ public T visitDateFilterElement(DateFilterElement elm, C context) { public T visitOtherFilterElement(OtherFilterElement elm, C context) { T result = defaultResult(elm, context); if (elm.getValue() != null) { - T childResult = visitElement(elm.getValue(), context); + T childResult = visitExpression(elm.getValue(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } + return result; } @@ -169,7 +187,7 @@ public T visitOtherFilterElement(OtherFilterElement elm, C context) { * @return the visitor result */ public T visitIncludeElement(IncludeElement elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -182,34 +200,49 @@ public T visitIncludeElement(IncludeElement elm, C context) { */ public T visitRetrieve(Retrieve elm, C context) { T result = defaultResult(elm, context); - if (elm.getCodes() != null) { - T childResult = visitElement(elm.getCodes(), context); + + for (var cfe : elm.getCodeFilter()) { + T childResult = visitCodeFilterElement(cfe, context); result = aggregateResult(result, childResult); } - if (elm.getDateRange() != null) { - T childResult = visitElement(elm.getDateRange(), context); + + if (elm.getCodes() != null) { + T childResult = visitExpression(elm.getCodes(), context); result = aggregateResult(result, childResult); } if (elm.getContext() != null) { - T childResult = visitElement(elm.getContext(), context); + T childResult = visitExpression(elm.getContext(), context); result = aggregateResult(result, childResult); } - for (IncludeElement ie : elm.getInclude()) { - T childResult = visitElement(ie, context); + for (var dfe : elm.getDateFilter()) { + T childResult = visitDateFilterElement(dfe, context); result = aggregateResult(result, childResult); } - for (CodeFilterElement cfe : elm.getCodeFilter()) { - T childResult = visitElement(cfe, context); + if (elm.getDateRange() != null) { + T childResult = visitExpression(elm.getDateRange(), context); result = aggregateResult(result, childResult); } - for (DateFilterElement dfe : elm.getDateFilter()) { - T childResult = visitElement(dfe, context); + + if (elm.getId() != null) { + T childResult = visitExpression(elm.getId(), context); result = aggregateResult(result, childResult); } - for (OtherFilterElement ofe : elm.getOtherFilter()) { - T childResult = visitElement(ofe, context); + + for (var ie : elm.getInclude()) { + T childResult = visitIncludeElement(ie, context); result = aggregateResult(result, childResult); } + + for (var ofe : elm.getOtherFilter()) { + T childResult = visitOtherFilterElement(ofe, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + return result; } @@ -238,7 +271,18 @@ public T visitProperty(Property elm, C context) { * @return the visitor result */ public T visitSearch(Search elm, C context) { - return visitChildren(elm, context); + T result = defaultResult(elm, context); + if (elm.getSource() != null) { + T childResult = visitExpression(elm.getSource(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + + return result; } /** @@ -255,6 +299,12 @@ public T visitCodeSystemDef(CodeSystemDef elm, C context) { T childResult = visitAccessModifier(elm.getAccessLevel(), context); result = aggregateResult(result, childResult); } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + return result; } @@ -273,9 +323,15 @@ public T visitValueSetDef(ValueSetDef elm, C context) { result = aggregateResult(result, childResult); } for (CodeSystemRef codeSystemRef : elm.getCodeSystem()) { - T childResult = visitElement(codeSystemRef, context); + T childResult = visitCodeSystemRef(codeSystemRef, context); result = aggregateResult(result, childResult); } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + return result; } @@ -297,6 +353,12 @@ public T visitCodeDef(CodeDef elm, C context) { T childResult = visitCodeSystemRef(elm.getCodeSystem(), context); result = aggregateResult(result, childResult); } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + return result; } @@ -315,9 +377,15 @@ public T visitConceptDef(ConceptDef elm, C context) { result = aggregateResult(result, childResult); } for (CodeRef cr : elm.getCode()) { - T childResult = visitElement(cr, context); + T childResult = visitCodeRef(cr, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } + return result; } @@ -330,7 +398,7 @@ public T visitConceptDef(ConceptDef elm, C context) { * @return the visitor result */ public T visitCodeSystemRef(CodeSystemRef elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -342,7 +410,7 @@ public T visitCodeSystemRef(CodeSystemRef elm, C context) { * @return the visitor result */ public T visitValueSetRef(ValueSetRef elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -354,7 +422,7 @@ public T visitValueSetRef(ValueSetRef elm, C context) { * @return the visitor result */ public T visitCodeRef(CodeRef elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -366,7 +434,7 @@ public T visitCodeRef(CodeRef elm, C context) { * @return the visitor result */ public T visitConceptRef(ConceptRef elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -380,9 +448,15 @@ public T visitConceptRef(ConceptRef elm, C context) { public T visitCode(Code elm, C context) { T result = defaultResult(elm, context); if (elm.getSystem() != null) { - T childResult = visitElement(elm.getSystem(), context); + T childResult = visitCodeSystemRef(elm.getSystem(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } + return result; } @@ -397,9 +471,15 @@ public T visitCode(Code elm, C context) { public T visitConcept(Concept elm, C context) { T result = defaultResult(elm, context); for (Code c : elm.getCode()) { - T childResult = visitElement(c, context); + T childResult = visitCode(c, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } + return result; } @@ -414,15 +494,25 @@ public T visitConcept(Concept elm, C context) { public T visitInCodeSystem(InCodeSystem elm, C context) { T result = defaultResult(elm, context); if (elm.getCode() != null) { - T childResult = visitElement(elm.getCode(), context); + T childResult = visitExpression(elm.getCode(), context); result = aggregateResult(result, childResult); } if (elm.getCodesystem() != null) { - T childResult = visitElement(elm.getCodesystem(), context); + T childResult = visitCodeSystemRef(elm.getCodesystem(), context); result = aggregateResult(result, childResult); } if (elm.getCodesystemExpression() != null) { - T childResult = visitElement(elm.getCodesystemExpression(), context); + T childResult = visitExpression(elm.getCodesystemExpression(), context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -439,15 +529,25 @@ public T visitInCodeSystem(InCodeSystem elm, C context) { public T visitAnyInCodeSystem(AnyInCodeSystem elm, C context) { T result = defaultResult(elm, context); if (elm.getCodes() != null) { - T childResult = visitElement(elm.getCodes(), context); + T childResult = visitExpression(elm.getCodes(), context); result = aggregateResult(result, childResult); } if (elm.getCodesystem() != null) { - T childResult = visitElement(elm.getCodesystem(), context); + T childResult = visitCodeSystemRef(elm.getCodesystem(), context); result = aggregateResult(result, childResult); } if (elm.getCodesystemExpression() != null) { - T childResult = visitElement(elm.getCodesystemExpression(), context); + T childResult = visitExpression(elm.getCodesystemExpression(), context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -464,15 +564,25 @@ public T visitAnyInCodeSystem(AnyInCodeSystem elm, C context) { public T visitInValueSet(InValueSet elm, C context) { T result = defaultResult(elm, context); if (elm.getCode() != null) { - T childResult = visitElement(elm.getCode(), context); + T childResult = visitExpression(elm.getCode(), context); result = aggregateResult(result, childResult); } if (elm.getValueset() != null) { - T childResult = visitElement(elm.getValueset(), context); + T childResult = visitValueSetRef(elm.getValueset(), context); result = aggregateResult(result, childResult); } if (elm.getValuesetExpression() != null) { - T childResult = visitElement(elm.getValuesetExpression(), context); + T childResult = visitExpression(elm.getValuesetExpression(), context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -489,15 +599,25 @@ public T visitInValueSet(InValueSet elm, C context) { public T visitAnyInValueSet(AnyInValueSet elm, C context) { T result = defaultResult(elm, context); if (elm.getCodes() != null) { - T childResult = visitElement(elm.getCodes(), context); + T childResult = visitExpression(elm.getCodes(), context); result = aggregateResult(result, childResult); } if (elm.getValueset() != null) { - T childResult = visitElement(elm.getValueset(), context); + T childResult = visitValueSetRef(elm.getValueset(), context); result = aggregateResult(result, childResult); } if (elm.getValuesetExpression() != null) { - T childResult = visitElement(elm.getValuesetExpression(), context); + T childResult = visitExpression(elm.getValuesetExpression(), context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -536,7 +656,7 @@ public T visitSubsumedBy(SubsumedBy elm, C context) { * @return the visitor result */ public T visitQuantity(Quantity elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -550,11 +670,16 @@ public T visitQuantity(Quantity elm, C context) { public T visitRatio(Ratio elm, C context) { T result = defaultResult(elm, context); if (elm.getDenominator() != null) { - T childResult = visitElement(elm.getDenominator(), context); + T childResult = visitQuantity(elm.getDenominator(), context); result = aggregateResult(result, childResult); } if (elm.getNumerator() != null) { - T childResult = visitElement(elm.getNumerator(), context); + T childResult = visitQuantity(elm.getNumerator(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; diff --git a/Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/ElmBaseLibraryVisitor.java b/Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/BaseElmLibraryVisitor.java similarity index 83% rename from Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/ElmBaseLibraryVisitor.java rename to Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/BaseElmLibraryVisitor.java index d0d57a419..521719ce2 100644 --- a/Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/ElmBaseLibraryVisitor.java +++ b/Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/BaseElmLibraryVisitor.java @@ -5,7 +5,8 @@ /** * Created by Bryn on 4/14/2016. */ -public class ElmBaseLibraryVisitor extends ElmBaseClinicalVisitor implements ElmLibraryVisitor { +public abstract class BaseElmLibraryVisitor extends BaseElmClinicalVisitor + implements ElmLibraryVisitor { /** * Visit an Element in an ELM tree. This method will be called for @@ -38,7 +39,7 @@ public T visitLibrary(Library elm, C context) { && elm.getUsings().getDef() != null && !elm.getUsings().getDef().isEmpty()) { for (UsingDef def : elm.getUsings().getDef()) { - T childResult = visitElement(def, context); + T childResult = visitUsingDef(def, context); result = aggregateResult(result, childResult); } } @@ -46,7 +47,7 @@ public T visitLibrary(Library elm, C context) { && elm.getIncludes().getDef() != null && !elm.getIncludes().getDef().isEmpty()) { for (IncludeDef def : elm.getIncludes().getDef()) { - T childResult = visitElement(def, context); + T childResult = visitIncludeDef(def, context); result = aggregateResult(result, childResult); } } @@ -54,7 +55,7 @@ public T visitLibrary(Library elm, C context) { && elm.getCodeSystems().getDef() != null && !elm.getCodeSystems().getDef().isEmpty()) { for (CodeSystemDef def : elm.getCodeSystems().getDef()) { - T childResult = visitElement(def, context); + T childResult = visitCodeSystemDef(def, context); result = aggregateResult(result, childResult); } } @@ -62,7 +63,7 @@ public T visitLibrary(Library elm, C context) { && elm.getValueSets().getDef() != null && !elm.getValueSets().getDef().isEmpty()) { for (ValueSetDef def : elm.getValueSets().getDef()) { - T childResult = visitElement(def, context); + T childResult = visitValueSetDef(def, context); result = aggregateResult(result, childResult); } } @@ -78,7 +79,7 @@ public T visitLibrary(Library elm, C context) { && elm.getConcepts().getDef() != null && !elm.getConcepts().getDef().isEmpty()) { for (ConceptDef def : elm.getConcepts().getDef()) { - T childResult = visitElement(def, context); + T childResult = visitConceptDef(def, context); result = aggregateResult(result, childResult); } } @@ -86,7 +87,7 @@ public T visitLibrary(Library elm, C context) { && elm.getParameters().getDef() != null && !elm.getParameters().getDef().isEmpty()) { for (ParameterDef def : elm.getParameters().getDef()) { - T childResult = visitElement(def, context); + T childResult = visitParameterDef(def, context); result = aggregateResult(result, childResult); } } @@ -94,7 +95,7 @@ public T visitLibrary(Library elm, C context) { && elm.getContexts().getDef() != null && !elm.getContexts().getDef().isEmpty()) { for (ContextDef def : elm.getContexts().getDef()) { - T childResult = visitElement(def, context); + T childResult = visitContextDef(def, context); result = aggregateResult(result, childResult); } } @@ -102,10 +103,16 @@ public T visitLibrary(Library elm, C context) { && elm.getStatements().getDef() != null && !elm.getStatements().getDef().isEmpty()) { for (ExpressionDef def : elm.getStatements().getDef()) { - T childResult = visitElement(def, context); + T childResult = visitExpressionDef(def, context); result = aggregateResult(result, childResult); } } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + return result; } @@ -118,7 +125,7 @@ public T visitLibrary(Library elm, C context) { * @return the visitor result */ public T visitUsingDef(UsingDef elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -130,7 +137,7 @@ public T visitUsingDef(UsingDef elm, C context) { * @return the visitor result */ public T visitIncludeDef(IncludeDef elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -142,6 +149,6 @@ public T visitIncludeDef(IncludeDef elm, C context) { * @return the visitor result */ public T visitContextDef(ContextDef elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } } diff --git a/Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/ElmBaseVisitor.java b/Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/BaseElmVisitor.java similarity index 80% rename from Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/ElmBaseVisitor.java rename to Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/BaseElmVisitor.java index f9cf349da..d0e8a9782 100644 --- a/Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/ElmBaseVisitor.java +++ b/Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/BaseElmVisitor.java @@ -8,12 +8,13 @@ * * @param The return type of the visit operation. Use {@link Void} for * @param The type of context passed to each visit method - * operations with no return type. + * operations with no return type. */ -public class ElmBaseVisitor implements ElmVisitor { +public abstract class BaseElmVisitor implements ElmVisitor { /** * Provides the default result of a visit + * * @return */ protected T defaultResult(Trackable elm, C context) { @@ -25,7 +26,7 @@ protected T defaultResult(Trackable elm, C context) { * Default behavior returns the next result, ignoring the current * aggregate. * - * @param aggregate Current aggregate result + * @param aggregate Current aggregate result * @param nextResult Next result to be aggregated * @return The result of aggregating the nextResult into aggregate */ @@ -42,20 +43,19 @@ protected T aggregateResult(T aggregate, T nextResult) { * @return the visitor result */ public T visitElement(Element elm, C context) { - if (elm instanceof AliasedQuerySource) return visitAliasedQuerySource((AliasedQuerySource) elm, context); + if (elm instanceof Expression) return visitExpression((Expression) elm, context); else if (elm instanceof CaseItem) return visitCaseItem((CaseItem) elm, context); - else if (elm instanceof Expression) return visitExpression((Expression) elm, context); else if (elm instanceof LetClause) return visitLetClause((LetClause) elm, context); else if (elm instanceof OperandDef) return visitOperandDef((OperandDef) elm, context); else if (elm instanceof ParameterDef) return visitParameterDef((ParameterDef) elm, context); - else if (elm instanceof ReturnClause) return visitReturnClause((ReturnClause) elm, context); - else if (elm instanceof AggregateClause) return visitAggregateClause((AggregateClause) elm, context); else if (elm instanceof SortByItem) return visitSortByItem((SortByItem) elm, context); else if (elm instanceof SortClause) return visitSortClause((SortClause) elm, context); else if (elm instanceof TupleElementDefinition) return visitTupleElementDefinition((TupleElementDefinition) elm, context); else if (elm instanceof TypeSpecifier) return visitTypeSpecifier((TypeSpecifier) elm, context); - else return defaultResult(elm, context); + else + throw new IllegalArgumentException( + "Unknown Element type: " + elm.getClass().getName()); } /** @@ -74,7 +74,23 @@ else if (elm instanceof IntervalTypeSpecifier) else if (elm instanceof TupleTypeSpecifier) return visitTupleTypeSpecifier((TupleTypeSpecifier) elm, context); else if (elm instanceof ChoiceTypeSpecifier) return visitChoiceTypeSpecifier((ChoiceTypeSpecifier) elm, context); - else return defaultResult(elm, context); + else if (elm instanceof ParameterTypeSpecifier) + return visitParameterTypeSpecifier((ParameterTypeSpecifier) elm, context); + else + throw new IllegalArgumentException( + "Unknown TypeSpecifier type: " + elm.getClass().getName()); + } + + /** + * Visit a ParameterTypeSpecifier. This method will be called for + * every node in the tree that is a ParameterTypeSpecifier. + * + * @param elm the ELM tree + * @param context the context passed to the visitor + * @return the visitor result + */ + public T visitParameterTypeSpecifier(ParameterTypeSpecifier elm, C context) { + return defaultResult(elm, context); } /** @@ -99,8 +115,13 @@ public T visitNamedTypeSpecifier(NamedTypeSpecifier elm, C context) { */ public T visitIntervalTypeSpecifier(IntervalTypeSpecifier elm, C context) { T result = defaultResult(elm, context); - T childResult = visitTypeSpecifier(elm.getPointType(), context); - return aggregateResult(result, childResult); + + if (elm.getPointType() != null) { + T childResult = visitTypeSpecifier(elm.getPointType(), context); + result = aggregateResult(result, childResult); + } + + return result; } /** @@ -113,8 +134,12 @@ public T visitIntervalTypeSpecifier(IntervalTypeSpecifier elm, C context) { */ public T visitListTypeSpecifier(ListTypeSpecifier elm, C context) { T result = defaultResult(elm, context); - T childResult = visitTypeSpecifier(elm.getElementType(), context); - return aggregateResult(result, childResult); + if (elm.getElementType() != null) { + T childResult = visitTypeSpecifier(elm.getElementType(), context); + result = aggregateResult(result, childResult); + } + + return result; } /** @@ -127,8 +152,23 @@ public T visitListTypeSpecifier(ListTypeSpecifier elm, C context) { */ public T visitTupleElementDefinition(TupleElementDefinition elm, C context) { T result = defaultResult(elm, context); - T childResult = visitTypeSpecifier(elm.getElementType(), context); - return aggregateResult(result, childResult); + + if (elm.getElementType() != null) { + T childResult = visitTypeSpecifier(elm.getElementType(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getType() != null) { + T childResult = visitTypeSpecifier(elm.getType(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + + return result; } /** @@ -158,10 +198,16 @@ public T visitTupleTypeSpecifier(TupleTypeSpecifier elm, C context) { */ public T visitChoiceTypeSpecifier(ChoiceTypeSpecifier elm, C context) { T result = defaultResult(elm, context); - for (TypeSpecifier choice : elm.getChoice()) { - T childResult = visitElement(choice, context); + for (var choice : elm.getChoice()) { + T childResult = visitTypeSpecifier(choice, context); + result = aggregateResult(result, childResult); + } + + for (var type : elm.getType()) { + T childResult = visitTypeSpecifier(type, context); result = aggregateResult(result, childResult); } + return result; } @@ -174,9 +220,7 @@ public T visitChoiceTypeSpecifier(ChoiceTypeSpecifier elm, C context) { * @return the visitor result */ public T visitExpression(Expression elm, C context) { - if (elm instanceof AggregateExpression) return visitAggregateExpression((AggregateExpression) elm, context); - else if (elm instanceof OperatorExpression) return visitOperatorExpression((OperatorExpression) elm, context); - else if (elm instanceof AliasRef) return visitAliasRef((AliasRef) elm, context); + if (elm instanceof AliasRef) return visitAliasRef((AliasRef) elm, context); else if (elm instanceof Case) return visitCase((Case) elm, context); else if (elm instanceof Current) return visitCurrent((Current) elm, context); else if (elm instanceof ExpressionRef) return visitExpressionRef((ExpressionRef) elm, context); @@ -201,7 +245,12 @@ public T visitExpression(Expression elm, C context) { else if (elm instanceof Sort) return visitSort((Sort) elm, context); else if (elm instanceof Total) return visitTotal((Total) elm, context); else if (elm instanceof Tuple) return visitTuple((Tuple) elm, context); - else return defaultResult(elm, context); + else if (elm instanceof AggregateExpression) + return visitAggregateExpression((AggregateExpression) elm, context); + else if (elm instanceof OperatorExpression) return visitOperatorExpression((OperatorExpression) elm, context); + else + throw new IllegalArgumentException( + "Unknown Expression type: " + elm.getClass().getName()); } /** @@ -213,11 +262,7 @@ public T visitExpression(Expression elm, C context) { * @return the visitor result */ public T visitOperatorExpression(OperatorExpression elm, C context) { - if (elm instanceof UnaryExpression) return visitUnaryExpression((UnaryExpression) elm, context); - else if (elm instanceof BinaryExpression) return visitBinaryExpression((BinaryExpression) elm, context); - else if (elm instanceof TernaryExpression) return visitTernaryExpression((TernaryExpression) elm, context); - else if (elm instanceof NaryExpression) return visitNaryExpression((NaryExpression) elm, context); - else if (elm instanceof Round) return visitRound((Round) elm, context); + if (elm instanceof Round) return visitRound((Round) elm, context); else if (elm instanceof Combine) return visitCombine((Combine) elm, context); else if (elm instanceof Split) return visitSplit((Split) elm, context); else if (elm instanceof SplitOnMatches) return visitSplitOnMatches((SplitOnMatches) elm, context); @@ -237,11 +282,18 @@ public T visitOperatorExpression(OperatorExpression elm, C context) { else if (elm instanceof Children) return visitChildren((Children) elm, context); else if (elm instanceof Descendents) return visitDescendents((Descendents) elm, context); else if (elm instanceof Message) return visitMessage((Message) elm, context); - return defaultResult(elm, context); + else if (elm instanceof UnaryExpression) return visitUnaryExpression((UnaryExpression) elm, context); + else if (elm instanceof BinaryExpression) return visitBinaryExpression((BinaryExpression) elm, context); + else if (elm instanceof TernaryExpression) return visitTernaryExpression((TernaryExpression) elm, context); + else if (elm instanceof NaryExpression) return visitNaryExpression((NaryExpression) elm, context); + else + throw new IllegalArgumentException( + "Unknown OperatorExpression type: " + elm.getClass().getName()); } /** * Visits the children of a UnaryExpression + * * @param elm * @param context * @return @@ -249,7 +301,17 @@ public T visitOperatorExpression(OperatorExpression elm, C context) { public T visitChildren(UnaryExpression elm, C context) { T result = defaultResult(elm, context); if (elm.getOperand() != null) { - T childResult = visitElement(elm.getOperand(), context); + T childResult = visitExpression(elm.getOperand(), context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -323,11 +385,14 @@ else if (elm instanceof DateTimeComponentFrom) else if (elm instanceof Truncate) return visitTruncate((Truncate) elm, context); else if (elm instanceof Upper) return visitUpper((Upper) elm, context); else if (elm instanceof Width) return visitWidth((Width) elm, context); - else return visitChildren(elm, context); + else + throw new IllegalArgumentException( + "Unknown UnaryExpression type: " + elm.getClass().getName()); } /** * Visits the children of a BinaryExpression + * * @param elm * @param context * @return @@ -335,9 +400,20 @@ else if (elm instanceof DateTimeComponentFrom) public T visitChildren(BinaryExpression elm, C context) { T result = defaultResult(elm, context); for (Expression e : elm.getOperand()) { - T childResult = visitElement(e, context); + T childResult = visitExpression(e, context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); result = aggregateResult(result, childResult); } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + return result; } @@ -403,11 +479,14 @@ public T visitBinaryExpression(BinaryExpression elm, C context) { else if (elm instanceof Times) return visitTimes((Times) elm, context); else if (elm instanceof TruncatedDivide) return visitTruncatedDivide((TruncatedDivide) elm, context); else if (elm instanceof Xor) return visitXor((Xor) elm, context); - else return visitChildren(elm, context); + else + throw new IllegalArgumentException( + "Unknown BinaryExpression type: " + elm.getClass().getName()); } /** * Visits the children of a TernaryExpression + * * @param elm * @param context * @return @@ -415,9 +494,20 @@ public T visitBinaryExpression(BinaryExpression elm, C context) { public T visitChildren(TernaryExpression elm, C context) { T result = defaultResult(elm, context); for (Expression e : elm.getOperand()) { - T childResult = visitElement(e, context); + T childResult = visitExpression(e, context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } + return result; } @@ -430,15 +520,15 @@ public T visitChildren(TernaryExpression elm, C context) { * @return the visitor result */ public T visitTernaryExpression(TernaryExpression elm, C context) { - for (Expression element : elm.getOperand()) { - visitElement(element, context); - } if (elm instanceof ReplaceMatches) return visitReplaceMatches((ReplaceMatches) elm, context); - return visitChildren(elm, context); + else + throw new IllegalArgumentException( + "Unknown TernaryExpression type: " + elm.getClass().getName()); } /** * Visits the children of an NaryExpression + * * @param elm * @param context * @return @@ -446,9 +536,20 @@ public T visitTernaryExpression(TernaryExpression elm, C context) { public T visitChildren(NaryExpression elm, C context) { T result = defaultResult(elm, context); for (Expression e : elm.getOperand()) { - T childResult = visitElement(e, context); + T childResult = visitExpression(e, context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } + return result; } @@ -466,26 +567,9 @@ public T visitNaryExpression(NaryExpression elm, C context) { else if (elm instanceof Except) return visitExcept((Except) elm, context); else if (elm instanceof Intersect) return visitIntersect((Intersect) elm, context); else if (elm instanceof Union) return visitUnion((Union) elm, context); - else return visitChildren(elm, context); - } - - /** - * Visits the children of an ExpressionDef - * @param elm - * @param context - * @return - */ - public T visitChildren(ExpressionDef elm, C context) { - T result = defaultResult(elm, context); - if (elm.getAccessLevel() != null) { - T childResult = visitAccessModifier(elm.getAccessLevel(), context); - result = aggregateResult(result, childResult); - } - if (elm.getExpression() != null) { - T childResult = visitElement(elm.getExpression(), context); - result = aggregateResult(result, childResult); - } - return result; + else + throw new IllegalArgumentException( + "Unknown NaryExpression type: " + elm.getClass().getName()); } /** @@ -500,7 +584,23 @@ public T visitExpressionDef(ExpressionDef elm, C context) { if (elm instanceof FunctionDef) { return visitFunctionDef((FunctionDef) elm, context); } - return visitChildren(elm, context); + + T result = defaultResult(elm, context); + if (elm.getAccessLevel() != null) { + T childResult = visitAccessModifier(elm.getAccessLevel(), context); + result = aggregateResult(result, childResult); + } + if (elm.getExpression() != null) { + T childResult = visitExpression(elm.getExpression(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + + return result; } /** @@ -512,15 +612,26 @@ public T visitExpressionDef(ExpressionDef elm, C context) { * @return the visitor result */ public T visitFunctionDef(FunctionDef elm, C context) { - T result = visitChildren(elm, context); - for (Element operand : elm.getOperand()) { - T childResult = visitElement(operand, context); + T result = defaultResult(elm, context); + if (elm.getAccessLevel() != null) { + T childResult = visitAccessModifier(elm.getAccessLevel(), context); + result = aggregateResult(result, childResult); + } + if (elm.getExpression() != null) { + T childResult = visitElement(elm.getExpression(), context); + result = aggregateResult(result, childResult); + } + + for (var operand : elm.getOperand()) { + T childResult = visitOperandDef(operand, context); result = aggregateResult(result, childResult); } + if (elm.getResultTypeSpecifier() != null) { - T childResult = visitElement(elm.getResultTypeSpecifier(), context); + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } + return result; } @@ -549,7 +660,7 @@ public T visitExpressionRef(ExpressionRef elm, C context) { if (elm instanceof FunctionRef) { return visitFunctionRef((FunctionRef) elm, context); } - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -562,10 +673,21 @@ public T visitExpressionRef(ExpressionRef elm, C context) { */ public T visitFunctionRef(FunctionRef elm, C context) { T result = defaultResult(elm, context); - for (Expression element : elm.getOperand()) { - T childResult = visitElement(element, context); + for (var element : elm.getOperand()) { + T childResult = visitExpression(element, context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } + return result; } @@ -580,12 +702,17 @@ public T visitFunctionRef(FunctionRef elm, C context) { public T visitParameterDef(ParameterDef elm, C context) { T result = defaultResult(elm, context); if (elm.getParameterTypeSpecifier() != null) { - T childResult = visitElement(elm.getParameterTypeSpecifier(), context); + T childResult = visitTypeSpecifier(elm.getParameterTypeSpecifier(), context); result = aggregateResult(result, childResult); } if (elm.getDefault() != null) { - T childResult = visitElement(elm.getDefault(), context); + T childResult = visitExpression(elm.getDefault(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } @@ -601,7 +728,7 @@ public T visitParameterDef(ParameterDef elm, C context) { * @return the visitor result */ public T visitParameterRef(ParameterRef elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -615,9 +742,15 @@ public T visitParameterRef(ParameterRef elm, C context) { public T visitOperandDef(OperandDef elm, C context) { T result = defaultResult(elm, context); if (elm.getOperandTypeSpecifier() != null) { - T childResult = visitElement(elm.getOperandTypeSpecifier(), context); + T childResult = visitTypeSpecifier(elm.getOperandTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } + return result; } @@ -630,7 +763,7 @@ public T visitOperandDef(OperandDef elm, C context) { * @return the visitor result */ public T visitOperandRef(OperandRef elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -642,7 +775,7 @@ public T visitOperandRef(OperandRef elm, C context) { * @return the visitor result */ public T visitIdentifierRef(IdentifierRef elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -654,7 +787,7 @@ public T visitIdentifierRef(IdentifierRef elm, C context) { * @return the visitor result */ public T visitLiteral(Literal elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -671,6 +804,7 @@ public T visitTupleElement(TupleElement elm, C context) { T childResult = visitExpression(elm.getValue(), context); result = aggregateResult(result, childResult); } + return result; } @@ -688,6 +822,11 @@ public T visitTuple(Tuple elm, C context) { T childResult = visitTupleElement(element, context); result = aggregateResult(result, childResult); } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } return result; } @@ -705,6 +844,7 @@ public T visitInstanceElement(InstanceElement elm, C context) { T childResult = visitExpression(elm.getValue(), context); result = aggregateResult(result, childResult); } + return result; } @@ -722,6 +862,12 @@ public T visitInstance(Instance elm, C context) { T childResult = visitInstanceElement(element, context); result = aggregateResult(result, childResult); } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + return result; } @@ -736,19 +882,24 @@ public T visitInstance(Instance elm, C context) { public T visitInterval(Interval elm, C context) { T result = defaultResult(elm, context); if (elm.getLow() != null) { - T childResult = visitElement(elm.getLow(), context); + T childResult = visitExpression(elm.getLow(), context); result = aggregateResult(result, childResult); } if (elm.getLowClosedExpression() != null) { - T childResult = visitElement(elm.getLowClosedExpression(), context); + T childResult = visitExpression(elm.getLowClosedExpression(), context); result = aggregateResult(result, childResult); } if (elm.getHigh() != null) { - T childResult = visitElement(elm.getHigh(), context); + T childResult = visitExpression(elm.getHigh(), context); result = aggregateResult(result, childResult); } if (elm.getHighClosedExpression() != null) { - T childResult = visitElement(elm.getHighClosedExpression(), context); + T childResult = visitExpression(elm.getHighClosedExpression(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -765,11 +916,16 @@ public T visitInterval(Interval elm, C context) { public T visitList(List elm, C context) { T result = defaultResult(elm, context); if (elm.getTypeSpecifier() != null) { - T childResult = visitElement(elm.getTypeSpecifier(), context); + T childResult = visitTypeSpecifier(elm.getTypeSpecifier(), context); result = aggregateResult(result, childResult); } for (Expression element : elm.getElement()) { - T childResult = visitElement(element, context); + T childResult = visitExpression(element, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -846,15 +1002,20 @@ public T visitNot(Not elm, C context) { public T visitIf(If elm, C context) { T result = defaultResult(elm, context); if (elm.getCondition() != null) { - T childResult = visitElement(elm.getCondition(), context); + T childResult = visitExpression(elm.getCondition(), context); result = aggregateResult(result, childResult); } if (elm.getThen() != null) { - T childResult = visitElement(elm.getThen(), context); + T childResult = visitExpression(elm.getThen(), context); result = aggregateResult(result, childResult); } if (elm.getElse() != null) { - T childResult = visitElement(elm.getElse(), context); + T childResult = visitExpression(elm.getElse(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -871,11 +1032,16 @@ public T visitIf(If elm, C context) { public T visitCaseItem(CaseItem elm, C context) { T result = defaultResult(elm, context); if (elm.getWhen() != null) { - T childResult = visitElement(elm.getWhen(), context); + T childResult = visitExpression(elm.getWhen(), context); result = aggregateResult(result, childResult); } if (elm.getThen() != null) { - T childResult = visitElement(elm.getThen(), context); + T childResult = visitExpression(elm.getThen(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -892,15 +1058,20 @@ public T visitCaseItem(CaseItem elm, C context) { public T visitCase(Case elm, C context) { T result = defaultResult(elm, context); if (elm.getComparand() != null) { - T childResult = visitElement(elm.getComparand(), context); + T childResult = visitExpression(elm.getComparand(), context); result = aggregateResult(result, childResult); } for (CaseItem ci : elm.getCaseItem()) { - T childResult = visitElement(ci, context); + T childResult = visitCaseItem(ci, context); result = aggregateResult(result, childResult); } if (elm.getElse() != null) { - T childResult = visitElement(elm.getElse(), context); + T childResult = visitExpression(elm.getElse(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -915,7 +1086,7 @@ public T visitCase(Case elm, C context) { * @return the visitor result */ public T visitNull(Null elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -975,9 +1146,24 @@ public T visitCoalesce(Coalesce elm, C context) { * @return the visitor result */ public T visitIs(Is elm, C context) { - T result = visitChildren(elm, context); + T result = defaultResult(elm, context); if (elm.getIsTypeSpecifier() != null) { - T childResult = visitElement(elm.getIsTypeSpecifier(), context); + T childResult = visitTypeSpecifier(elm.getIsTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getOperand() != null) { + T childResult = visitExpression(elm.getOperand(), context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -992,11 +1178,27 @@ public T visitIs(Is elm, C context) { * @return the visitor result */ public T visitAs(As elm, C context) { - T result = visitChildren(elm, context); + T result = defaultResult(elm, context); if (elm.getAsTypeSpecifier() != null) { - T childResult = visitElement(elm.getAsTypeSpecifier(), context); + T childResult = visitTypeSpecifier(elm.getAsTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getOperand() != null) { + T childResult = visitExpression(elm.getOperand(), context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } + return result; } @@ -1009,9 +1211,24 @@ public T visitAs(As elm, C context) { * @return the visitor result */ public T visitConvert(Convert elm, C context) { - T result = visitChildren(elm, context); + T result = defaultResult(elm, context); if (elm.getToTypeSpecifier() != null) { - T childResult = visitElement(elm.getToTypeSpecifier(), context); + T childResult = visitTypeSpecifier(elm.getToTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getOperand() != null) { + T childResult = visitExpression(elm.getOperand(), context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -1026,9 +1243,24 @@ public T visitConvert(Convert elm, C context) { * @return the visitor result */ public T visitCanConvert(CanConvert elm, C context) { - T result = visitChildren(elm, context); + T result = defaultResult(elm, context); if (elm.getToTypeSpecifier() != null) { - T childResult = visitElement(elm.getToTypeSpecifier(), context); + T childResult = visitTypeSpecifier(elm.getToTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getOperand() != null) { + T childResult = visitExpression(elm.getOperand(), context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -1561,11 +1793,22 @@ public T visitNegate(Negate elm, C context) { public T visitRound(Round elm, C context) { T result = defaultResult(elm, context); if (elm.getOperand() != null) { - T childResult = visitElement(elm.getOperand(), context); + T childResult = visitExpression(elm.getOperand(), context); result = aggregateResult(result, childResult); } + if (elm.getPrecision() != null) { - T childResult = visitElement(elm.getPrecision(), context); + T childResult = visitExpression(elm.getPrecision(), context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -1652,7 +1895,7 @@ public T visitPredecessor(Predecessor elm, C context) { * @return the visitor result */ public T visitMinValue(MinValue elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -1664,7 +1907,7 @@ public T visitMinValue(MinValue elm, C context) { * @return the visitor result */ public T visitMaxValue(MaxValue elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -1726,20 +1969,30 @@ public T visitConcatenate(Concatenate elm, C context) { public T visitCombine(Combine elm, C context) { T result = defaultResult(elm, context); if (elm.getSource() != null) { - T childResult = visitElement(elm.getSource(), context); + T childResult = visitExpression(elm.getSource(), context); result = aggregateResult(result, childResult); } if (elm.getSeparator() != null) { - T childResult = visitElement(elm.getSeparator(), context); + T childResult = visitExpression(elm.getSeparator(), context); result = aggregateResult(result, childResult); } - return result; - } - /** - * Visit a Split. This method will be called for - * every node in the tree that is a Split. - * + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + return result; + } + + /** + * Visit a Split. This method will be called for + * every node in the tree that is a Split. + * * @param elm the ELM tree * @param context the context passed to the visitor * @return the visitor result @@ -1754,6 +2007,16 @@ public T visitSplit(Split elm, C context) { T childResult = visitExpression(elm.getSeparator(), context); result = aggregateResult(result, childResult); } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } return result; } @@ -1775,6 +2038,16 @@ public T visitSplitOnMatches(SplitOnMatches elm, C context) { T childResult = visitExpression(elm.getSeparatorPattern(), context); result = aggregateResult(result, childResult); } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } return result; } @@ -1844,6 +2117,16 @@ public T visitPositionOf(PositionOf elm, C context) { T childResult = visitExpression(elm.getString(), context); result = aggregateResult(result, childResult); } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } return result; } @@ -1865,6 +2148,16 @@ public T visitLastPositionOf(LastPositionOf elm, C context) { T childResult = visitExpression(elm.getString(), context); result = aggregateResult(result, childResult); } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } return result; } @@ -1890,6 +2183,16 @@ public T visitSubstring(Substring elm, C context) { T childResult = visitExpression(elm.getLength(), context); result = aggregateResult(result, childResult); } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } return result; } @@ -2034,7 +2337,7 @@ public T visitDateTimeComponentFrom(DateTimeComponentFrom elm, C context) { * @return the visitor result */ public T visitTimeOfDay(TimeOfDay elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -2046,7 +2349,7 @@ public T visitTimeOfDay(TimeOfDay elm, C context) { * @return the visitor result */ public T visitToday(Today elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -2058,7 +2361,7 @@ public T visitToday(Today elm, C context) { * @return the visitor result */ public T visitNow(Now elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -2103,6 +2406,16 @@ public T visitDateTime(DateTime elm, C context) { T childResult = visitExpression(elm.getTimezoneOffset(), context); result = aggregateResult(result, childResult); } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } return result; } @@ -2128,6 +2441,16 @@ public T visitDate(Date elm, C context) { T childResult = visitExpression(elm.getDay(), context); result = aggregateResult(result, childResult); } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } return result; } @@ -2157,6 +2480,16 @@ public T visitTime(Time elm, C context) { T childResult = visitExpression(elm.getMillisecond(), context); result = aggregateResult(result, childResult); } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } return result; } @@ -2567,11 +2900,16 @@ public T visitTimes(Times elm, C context) { public T visitFilter(Filter elm, C context) { T result = defaultResult(elm, context); if (elm.getSource() != null) { - T childResult = visitElement(elm.getSource(), context); + T childResult = visitExpression(elm.getSource(), context); result = aggregateResult(result, childResult); } if (elm.getCondition() != null) { - T childResult = visitElement(elm.getCondition(), context); + T childResult = visitExpression(elm.getCondition(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -2588,7 +2926,17 @@ public T visitFilter(Filter elm, C context) { public T visitFirst(First elm, C context) { T result = defaultResult(elm, context); if (elm.getSource() != null) { - T childResult = visitElement(elm.getSource(), context); + T childResult = visitExpression(elm.getSource(), context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -2605,7 +2953,17 @@ public T visitFirst(First elm, C context) { public T visitLast(Last elm, C context) { T result = defaultResult(elm, context); if (elm.getSource() != null) { - T childResult = visitElement(elm.getSource(), context); + T childResult = visitExpression(elm.getSource(), context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -2622,15 +2980,25 @@ public T visitLast(Last elm, C context) { public T visitSlice(Slice elm, C context) { T result = defaultResult(elm, context); if (elm.getSource() != null) { - T childResult = visitElement(elm.getSource(), context); + T childResult = visitExpression(elm.getSource(), context); result = aggregateResult(result, childResult); } if (elm.getStartIndex() != null) { - T childResult = visitElement(elm.getStartIndex(), context); + T childResult = visitExpression(elm.getStartIndex(), context); result = aggregateResult(result, childResult); } if (elm.getEndIndex() != null) { - T childResult = visitElement(elm.getEndIndex(), context); + T childResult = visitExpression(elm.getEndIndex(), context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -2647,7 +3015,12 @@ public T visitSlice(Slice elm, C context) { public T visitChildren(Children elm, C context) { T result = defaultResult(elm, context); if (elm.getSource() != null) { - T childResult = visitElement(elm.getSource(), context); + T childResult = visitExpression(elm.getSource(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -2664,7 +3037,17 @@ public T visitChildren(Children elm, C context) { public T visitDescendents(Descendents elm, C context) { T result = defaultResult(elm, context); if (elm.getSource() != null) { - T childResult = visitElement(elm.getSource(), context); + T childResult = visitExpression(elm.getSource(), context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -2681,23 +3064,33 @@ public T visitDescendents(Descendents elm, C context) { public T visitMessage(Message elm, C context) { T result = defaultResult(elm, context); if (elm.getSource() != null) { - T childResult = visitElement(elm.getSource(), context); + T childResult = visitExpression(elm.getSource(), context); result = aggregateResult(result, childResult); } if (elm.getCondition() != null) { - T childResult = visitElement(elm.getCondition(), context); + T childResult = visitExpression(elm.getCondition(), context); result = aggregateResult(result, childResult); } if (elm.getCode() != null) { - T childResult = visitElement(elm.getCode(), context); + T childResult = visitExpression(elm.getCode(), context); result = aggregateResult(result, childResult); } if (elm.getSeverity() != null) { - T childResult = visitElement(elm.getSeverity(), context); + T childResult = visitExpression(elm.getSeverity(), context); result = aggregateResult(result, childResult); } if (elm.getMessage() != null) { - T childResult = visitElement(elm.getMessage(), context); + T childResult = visitExpression(elm.getMessage(), context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -2714,11 +3107,21 @@ public T visitMessage(Message elm, C context) { public T visitIndexOf(IndexOf elm, C context) { T result = defaultResult(elm, context); if (elm.getSource() != null) { - T childResult = visitElement(elm.getSource(), context); + T childResult = visitExpression(elm.getSource(), context); result = aggregateResult(result, childResult); } if (elm.getElement() != null) { - T childResult = visitElement(elm.getElement(), context); + T childResult = visitExpression(elm.getElement(), context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -2747,11 +3150,16 @@ public T visitFlatten(Flatten elm, C context) { public T visitSort(Sort elm, C context) { T result = defaultResult(elm, context); if (elm.getSource() != null) { - T childResult = visitElement(elm.getSource(), context); + T childResult = visitExpression(elm.getSource(), context); result = aggregateResult(result, childResult); } for (SortByItem sbi : elm.getBy()) { - T childResult = visitElement(sbi, context); + T childResult = visitSortByItem(sbi, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -2768,11 +3176,16 @@ public T visitSort(Sort elm, C context) { public T visitForEach(ForEach elm, C context) { T result = defaultResult(elm, context); if (elm.getSource() != null) { - T childResult = visitElement(elm.getSource(), context); + T childResult = visitExpression(elm.getSource(), context); result = aggregateResult(result, childResult); } if (elm.getElement() != null) { - T childResult = visitElement(elm.getElement(), context); + T childResult = visitExpression(elm.getElement(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -2789,11 +3202,16 @@ public T visitForEach(ForEach elm, C context) { public T visitRepeat(Repeat elm, C context) { T result = defaultResult(elm, context); if (elm.getSource() != null) { - T childResult = visitElement(elm.getSource(), context); + T childResult = visitExpression(elm.getSource(), context); result = aggregateResult(result, childResult); } if (elm.getElement() != null) { - T childResult = visitElement(elm.getElement(), context); + T childResult = visitExpression(elm.getElement(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -2820,7 +3238,7 @@ public T visitDistinct(Distinct elm, C context) { * @return the visitor result */ public T visitCurrent(Current elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -2832,7 +3250,7 @@ public T visitCurrent(Current elm, C context) { * @return the visitor result */ public T visitIteration(Iteration elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -2844,7 +3262,7 @@ public T visitIteration(Iteration elm, C context) { * @return the visitor result */ public T visitTotal(Total elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -2861,6 +3279,7 @@ public T visitSingletonFrom(SingletonFrom elm, C context) { /** * Visits the children of an AggregateExpression + * * @param elm * @param context * @return @@ -2868,9 +3287,20 @@ public T visitSingletonFrom(SingletonFrom elm, C context) { public T visitChildren(AggregateExpression elm, C context) { T result = defaultResult(elm, context); if (elm.getSource() != null) { - T childResult = visitElement(elm.getSource(), context); + T childResult = visitExpression(elm.getSource(), context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } + return result; } @@ -2899,7 +3329,9 @@ public T visitAggregateExpression(AggregateExpression elm, C context) { else if (elm instanceof PopulationStdDev) return visitPopulationStdDev((PopulationStdDev) elm, context); else if (elm instanceof AllTrue) return visitAllTrue((AllTrue) elm, context); else if (elm instanceof AnyTrue) return visitAnyTrue((AnyTrue) elm, context); - return visitChildren(elm, context); + else + throw new IllegalArgumentException( + "Unsupported AggregateExpression type: " + elm.getClass().getName()); } /** @@ -2920,6 +3352,21 @@ public T visitAggregate(Aggregate elm, C context) { T childResult = visitExpression(elm.getIteration(), context); result = aggregateResult(result, childResult); } + + if (elm.getSource() != null) { + T childResult = visitExpression(elm.getSource(), context); + result = aggregateResult(result, childResult); + } + + for (var s : elm.getSignature()) { + T childResult = visitTypeSpecifier(s, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } return result; } @@ -3103,21 +3550,6 @@ public T visitAnyTrue(AnyTrue elm, C context) { return visitChildren(elm, context); } - /** - * Visits the children of a Property - * @param elm - * @param context - * @return - */ - public T visitChildren(Property elm, C context) { - T result = defaultResult(elm, context); - if (elm.getSource() != null) { - T childResult = visitExpression(elm.getSource(), context); - result = aggregateResult(result, childResult); - } - return result; - } - /** * Visit a Property. This method will be called for * every node in the tree that is a Property. @@ -3127,19 +3559,14 @@ public T visitChildren(Property elm, C context) { * @return the visitor result */ public T visitProperty(Property elm, C context) { - return visitChildren(elm, context); - } - - /** - * Visits the children of an AliasedQuerySource - * @param elm - * @param context - * @return - */ - public T visitChildren(AliasedQuerySource elm, C context) { T result = defaultResult(elm, context); - if (elm.getExpression() != null) { - T childResult = visitExpression(elm.getExpression(), context); + if (elm.getSource() != null) { + T childResult = visitExpression(elm.getSource(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -3157,7 +3584,18 @@ public T visitAliasedQuerySource(AliasedQuerySource elm, C context) { if (elm instanceof RelationshipClause) { return visitRelationshipClause((RelationshipClause) elm, context); } - return visitChildren(elm, context); + + T result = defaultResult(elm, context); + if (elm.getExpression() != null) { + T childResult = visitExpression(elm.getExpression(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + return result; } /** @@ -3169,27 +3607,22 @@ public T visitAliasedQuerySource(AliasedQuerySource elm, C context) { * @return the visitor result */ public T visitLetClause(LetClause elm, C context) { + T result = defaultResult(elm, context); if (elm.getExpression() != null) { - return visitElement(elm.getExpression(), context); + T childResult = visitExpression(elm.getExpression(), context); + result = aggregateResult(result, childResult); } - return null; - } - /** - * Visits an expression that is the condition of a such that clause in a - * with or without clause. The isWith parameter indicates whether the clause - * is a with or a without. - * @param elm - * @param isWith - * @param context - * @return - */ - public T visitSuchThatClause(Expression elm, boolean isWith, C context) { - return visitElement(elm, context); + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + return result; } /** * Visits the children of a RelationshipClause + * * @param elm * @param context * @return @@ -3197,11 +3630,16 @@ public T visitSuchThatClause(Expression elm, boolean isWith, C context) { public T visitChildren(RelationshipClause elm, C context) { T result = defaultResult(elm, context); if (elm.getExpression() != null) { - T childResult = visitElement(elm.getExpression(), context); + T childResult = visitExpression(elm.getExpression(), context); result = aggregateResult(result, childResult); } if (elm.getSuchThat() != null) { - T childResult = visitSuchThatClause(elm.getSuchThat(), elm instanceof With, context); + T childResult = visitExpression(elm.getSuchThat(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -3220,8 +3658,10 @@ public T visitRelationshipClause(RelationshipClause elm, C context) { return visitWith((With) elm, context); } else if (elm instanceof Without) { return visitWithout((Without) elm, context); + } else { + throw new IllegalArgumentException( + "Unknown RelationshipClause type: " + elm.getClass().getName()); } - return visitChildren(elm, context); } /** @@ -3257,18 +3697,15 @@ public T visitWithout(Without elm, C context) { * @return the visitor result */ public T visitSortByItem(SortByItem elm, C context) { - T result = defaultResult(elm, context); if (elm instanceof ByDirection) { - T childResult = visitByDirection((ByDirection) elm, context); - result = aggregateResult(result, childResult); + return visitByDirection((ByDirection) elm, context); } else if (elm instanceof ByColumn) { - T childResult = visitByColumn((ByColumn) elm, context); - result = aggregateResult(result, childResult); + return visitByColumn((ByColumn) elm, context); } else if (elm instanceof ByExpression) { - T childResult = visitByExpression((ByExpression) elm, context); - result = aggregateResult(result, childResult); - } - return result; + return visitByExpression((ByExpression) elm, context); + } else + throw new IllegalArgumentException( + "Unknown SortByItem type: " + elm.getClass().getName()); } /** @@ -3280,7 +3717,7 @@ public T visitSortByItem(SortByItem elm, C context) { * @return the visitor result */ public T visitByDirection(ByDirection elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -3292,7 +3729,7 @@ public T visitByDirection(ByDirection elm, C context) { * @return the visitor result */ public T visitByColumn(ByColumn elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -3306,9 +3743,15 @@ public T visitByColumn(ByColumn elm, C context) { public T visitByExpression(ByExpression elm, C context) { T result = defaultResult(elm, context); if (elm.getExpression() != null) { - T childResult = visitElement(elm.getExpression(), context); + T childResult = visitExpression(elm.getExpression(), context); result = aggregateResult(result, childResult); } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + return result; } @@ -3323,9 +3766,15 @@ public T visitByExpression(ByExpression elm, C context) { public T visitSortClause(SortClause elm, C context) { T result = defaultResult(elm, context); for (SortByItem sbi : elm.getBy()) { - T childResult = visitElement(sbi, context); + T childResult = visitSortByItem(sbi, context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } + return result; } @@ -3340,11 +3789,16 @@ public T visitSortClause(SortClause elm, C context) { public T visitAggregateClause(AggregateClause elm, C context) { T result = defaultResult(elm, context); if (elm.getExpression() != null) { - T childResult = visitElement(elm.getExpression(), context); + T childResult = visitExpression(elm.getExpression(), context); result = aggregateResult(result, childResult); } if (elm.getStarting() != null) { - T childResult = visitElement(elm.getStarting(), context); + T childResult = visitExpression(elm.getStarting(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -3364,18 +3818,12 @@ public T visitReturnClause(ReturnClause elm, C context) { T childResult = visitExpression(elm.getExpression(), context); result = aggregateResult(result, childResult); } - return result; - } - /** - * Visits an Expression that is the condition for a where clause - * in a Query. - * @param elm - * @param context - * @return - */ - public T visitWhereClause(Expression elm, C context) { - return visitElement(elm, context); + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + return result; } /** @@ -3388,36 +3836,41 @@ public T visitWhereClause(Expression elm, C context) { */ public T visitQuery(Query elm, C context) { T result = defaultResult(elm, context); - for (AliasedQuerySource source : elm.getSource()) { - T childResult = visitElement(source, context); + for (var source : elm.getSource()) { + T childResult = visitAliasedQuerySource(source, context); result = aggregateResult(result, childResult); } - if (elm.getLet() != null && !elm.getLet().isEmpty()) { - for (Element let : elm.getLet()) { - T childResult = visitElement(let, context); - result = aggregateResult(result, childResult); - } + for (var let : elm.getLet()) { + T childResult = visitLetClause(let, context); + result = aggregateResult(result, childResult); } - if (elm.getRelationship() != null && !elm.getRelationship().isEmpty()) { - for (Element relationship : elm.getRelationship()) { - T childResult = visitElement(relationship, context); - result = aggregateResult(result, childResult); - } + + for (var r : elm.getRelationship()) { + T childResult = visitRelationshipClause(r, context); + result = aggregateResult(result, childResult); } + if (elm.getWhere() != null) { - T childResult = visitWhereClause(elm.getWhere(), context); + T childResult = visitExpression(elm.getWhere(), context); result = aggregateResult(result, childResult); } if (elm.getReturn() != null) { - T childResult = visitElement(elm.getReturn(), context); + T childResult = visitReturnClause(elm.getReturn(), context); result = aggregateResult(result, childResult); } + if (elm.getAggregate() != null) { - T childResult = visitElement(elm.getAggregate(), context); + T childResult = visitAggregateClause(elm.getAggregate(), context); result = aggregateResult(result, childResult); } + if (elm.getSort() != null) { - T childResult = visitElement(elm.getSort(), context); + T childResult = visitSortClause(elm.getSort(), context); + result = aggregateResult(result, childResult); + } + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); result = aggregateResult(result, childResult); } return result; @@ -3432,7 +3885,7 @@ public T visitQuery(Query elm, C context) { * @return the visitor result */ public T visitAliasRef(AliasRef elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); } /** @@ -3444,6 +3897,28 @@ public T visitAliasRef(AliasRef elm, C context) { * @return the visitor result */ public T visitQueryLetRef(QueryLetRef elm, C context) { - return defaultResult(elm, context); + return visitChildren(elm, context); + } + + public T visitChildren(Expression elm, C context) { + T result = defaultResult(elm, context); + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + + return result; + } + + public T visitChildren(Element elm, C context) { + T result = defaultResult(elm, context); + + if (elm.getResultTypeSpecifier() != null) { + T childResult = visitTypeSpecifier(elm.getResultTypeSpecifier(), context); + result = aggregateResult(result, childResult); + } + + return result; } } diff --git a/Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/ElmFunctionalVisitor.java b/Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/FunctionalElmVisitor.java similarity index 77% rename from Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/ElmFunctionalVisitor.java rename to Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/FunctionalElmVisitor.java index c3b753490..c4fdc72bf 100644 --- a/Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/ElmFunctionalVisitor.java +++ b/Src/java/elm/src/main/java/org/cqframework/cql/elm/visiting/FunctionalElmVisitor.java @@ -9,7 +9,7 @@ * Useful for quick visitor implementations, such as counting all nodes, or finding a specific element * type. */ -public class ElmFunctionalVisitor extends ElmBaseLibraryVisitor { +public class FunctionalElmVisitor extends BaseElmLibraryVisitor { private final BiFunction defaultResult; private final BiFunction aggregateResult; @@ -19,7 +19,7 @@ public class ElmFunctionalVisitor extends ElmBaseLibraryVisitor { * @param defaultResult the function for processing a visited element * @param aggregateResult the function for aggregating results */ - public ElmFunctionalVisitor(BiFunction defaultResult, BiFunction aggregateResult) { + public FunctionalElmVisitor(BiFunction defaultResult, BiFunction aggregateResult) { this.defaultResult = Objects.requireNonNull(defaultResult); this.aggregateResult = Objects.requireNonNull(aggregateResult); } @@ -33,4 +33,9 @@ public T defaultResult(Trackable elm, C context) { public T aggregateResult(T aggregate, T nextResult) { return this.aggregateResult.apply(aggregate, nextResult); } + + public static FunctionalElmVisitor from( + BiFunction defaultResult, BiFunction aggregateResult) { + return new FunctionalElmVisitor<>(defaultResult, aggregateResult); + } } diff --git a/Src/java/elm/src/test/java/org/cqframework/cql/elm/IdObjectFactoryTest.java b/Src/java/elm/src/test/java/org/cqframework/cql/elm/IdObjectFactoryTest.java new file mode 100644 index 000000000..7d43e3d58 --- /dev/null +++ b/Src/java/elm/src/test/java/org/cqframework/cql/elm/IdObjectFactoryTest.java @@ -0,0 +1,27 @@ +package org.cqframework.cql.elm; + +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import org.hl7.elm.r1.Element; +import org.junit.Test; + +public class IdObjectFactoryTest { + + @Test + public void ensureAllElementsHaveLocalId() { + var factory = new IdObjectFactory(); + var methods = Arrays.asList(IdObjectFactory.class.getMethods()).stream() + .filter(x -> Element.class.isAssignableFrom(x.getReturnType())); + methods.forEach(x -> { + try { + Element e = (Element) x.invoke(factory); + if (e.getLocalId() == null) { + throw new RuntimeException( + String.format("%s missing localId", e.getClass().getSimpleName())); + } + } catch (InvocationTargetException | IllegalAccessException e) { + throw new RuntimeException(e); + } + }); + } +} diff --git a/Src/java/elm/src/test/java/org/cqframework/cql/elm/utility/VisitorsTest.java b/Src/java/elm/src/test/java/org/cqframework/cql/elm/utility/VisitorsTest.java new file mode 100644 index 000000000..13b5a1fb1 --- /dev/null +++ b/Src/java/elm/src/test/java/org/cqframework/cql/elm/utility/VisitorsTest.java @@ -0,0 +1,40 @@ +package org.cqframework.cql.elm.utility; + +import static org.junit.Assert.assertEquals; +import static org.testng.Assert.assertThrows; + +import org.hl7.elm.r1.ExpressionDef; +import org.hl7.elm.r1.Library; +import org.hl7.elm.r1.Library.Statements; +import org.junit.Test; + +public class VisitorsTest { + + @Test + public void constructVisitorTest() { + // set up visitor that counts all visited elements + var trackableCounter = Visitors.from((elm, context) -> 1, Integer::sum); + + var library = new Library(); + library.setStatements(new Statements()); + library.getStatements().getDef().add(new ExpressionDef()); + library.getStatements().getDef().add(new ExpressionDef()); + library.getStatements().getDef().add(new ExpressionDef()); + + var result = trackableCounter.visitLibrary(library, null); + assertEquals(4 + 3, result.intValue()); // ELM elements + implicit access modifiers + + // This visitor returns the context object that's passed in + var contextReturner = Visitors.from((t, c) -> c); + var context = new Object(); + assertEquals(context, contextReturner.visitLibrary(library, context)); + } + + @Test + public void nullVisitorTest() { + assertThrows(NullPointerException.class, () -> Visitors.from(null)); + assertThrows(NullPointerException.class, () -> Visitors.from(null, null)); + assertThrows(NullPointerException.class, () -> Visitors.from(null, (a, b) -> b)); + assertThrows(NullPointerException.class, () -> Visitors.from((t, c) -> null, null)); + } +} diff --git a/Src/java/elm/src/test/java/org/cqframework/cql/elm/ElmBaseVisitorTest.java b/Src/java/elm/src/test/java/org/cqframework/cql/elm/visiting/BaseElmVisitorTest.java similarity index 84% rename from Src/java/elm/src/test/java/org/cqframework/cql/elm/ElmBaseVisitorTest.java rename to Src/java/elm/src/test/java/org/cqframework/cql/elm/visiting/BaseElmVisitorTest.java index e9d83f813..6125f697c 100644 --- a/Src/java/elm/src/test/java/org/cqframework/cql/elm/ElmBaseVisitorTest.java +++ b/Src/java/elm/src/test/java/org/cqframework/cql/elm/visiting/BaseElmVisitorTest.java @@ -1,22 +1,20 @@ -package org.cqframework.cql.elm; +package org.cqframework.cql.elm.visiting; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.cqframework.cql.elm.tracking.Trackable; -import org.cqframework.cql.elm.visiting.ElmBaseVisitor; import org.hl7.elm.r1.ByDirection; import org.hl7.elm.r1.Sort; import org.hl7.elm.r1.SortByItem; import org.junit.Test; -public class ElmBaseVisitorTest { +public class BaseElmVisitorTest { @Test public void sortByVisited() { - // set up visitor that returns true if it visits a SortByItem - var sortByFinder = new ElmBaseVisitor() { + var sortByFinder = new BaseElmVisitor() { @Override public Boolean defaultResult(Trackable t, Void context) { if (t instanceof SortByItem) { diff --git a/Src/java/elm/src/test/java/org/cqframework/cql/elm/visiting/DesignTests.java b/Src/java/elm/src/test/java/org/cqframework/cql/elm/visiting/DesignTests.java new file mode 100644 index 000000000..20d494a13 --- /dev/null +++ b/Src/java/elm/src/test/java/org/cqframework/cql/elm/visiting/DesignTests.java @@ -0,0 +1,317 @@ +package org.cqframework.cql.elm.visiting; + +import static com.tngtech.archunit.base.DescribedPredicate.and; +import static com.tngtech.archunit.base.DescribedPredicate.anyElementThat; +import static com.tngtech.archunit.base.DescribedPredicate.not; +import static com.tngtech.archunit.core.domain.JavaClass.Predicates.assignableTo; +import static com.tngtech.archunit.core.domain.properties.HasModifiers.Predicates.modifier; +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.methods; +import static java.util.stream.Collectors.toSet; + +import com.tngtech.archunit.core.domain.JavaClasses; +import com.tngtech.archunit.core.domain.JavaMethod; +import com.tngtech.archunit.core.domain.JavaModifier; +import com.tngtech.archunit.core.importer.ClassFileImporter; +import com.tngtech.archunit.lang.ArchCondition; +import com.tngtech.archunit.lang.ConditionEvents; +import com.tngtech.archunit.lang.SimpleConditionEvent; +import java.util.function.Predicate; +import org.hl7.elm.r1.Element; +import org.hl7.elm.r1.OperatorExpression; +import org.hl7.elm.r1.TypeSpecifier; +import org.junit.Test; + +public class DesignTests { + + private static final JavaClasses importedClasses = + new ClassFileImporter().importPackages("org.cqframework.cql.elm", "org.hl7.elm.r1"); + + @Test + public void ensureVisitChildrenCallsDefaultResult() { + methods() + .that() + .areDeclaredInClassesThat() + .areAssignableTo(BaseElmVisitor.class) + .and() + .haveName("visitChildren") + .should(new CallDefaultResult()) + .because("The visitChildren methods are terminal methods in the visitor hierarchy, " + + "they should always call defaultResult") + .check(importedClasses); + } + + @Test + public void ensureVisitAbstractDoesNotCallDefaultResult() { + + var isAbstractElementType = and(modifier(JavaModifier.ABSTRACT), assignableTo(Element.class)); + + methods() + .that() + .areDeclaredInClassesThat() + .areAssignableTo(BaseElmVisitor.class) + .and() + .haveNameStartingWith("visit") + .and() + .doNotHaveName("visitChildren") + .and() + .haveRawParameterTypes(anyElementThat(isAbstractElementType)) + .should(new NotCallDefaultResult()) + .because("The visitXYZ (where XYZ is an Element type) methods " + + "for abstract classes should not call defaultResult, " + + "since that means the subtypes properties are probably missed. " + + "Instead, those methods should forward to the subtype visit method") + .check(importedClasses); + } + + @Test + public void ensureVisitElementUsesResultType() { + + // TypeSpecifiers are excluded because the are also Elements with a resultType + // and rather than recurse we consider them terminal nodes. + var isConcreteElement = and( + not(modifier(JavaModifier.ABSTRACT)), + assignableTo(Element.class), + not(assignableTo(TypeSpecifier.class))); + + methods() + .that() + .areDeclaredInClassesThat() + .areAssignableTo(BaseElmVisitor.class) + .and() + .haveNameStartingWith("visit") + .and() + .doNotHaveName("visitChildren") + .and() + .doNotHaveName("visitProperty") // Special exclusion for Property. See the implementation of + // visitProperty. + .and() + .haveRawParameterTypes(anyElementThat(isConcreteElement)) + .should(new UseResultTypeIfTheyDoNotForwardToVisitChildren()) + .because("visits to concrete Element type should visit the resultType of the of the element") + .check(importedClasses); + } + + @Test + public void ensureVisitOperatorExpressionUsesSignature() { + + var isConcreteOperatorExpression = + and(not(modifier(JavaModifier.ABSTRACT)), assignableTo(OperatorExpression.class)); + + methods() + .that() + .areDeclaredInClassesThat() + .areAssignableTo(BaseElmVisitor.class) + .and() + .haveNameStartingWith("visit") + .and() + .doNotHaveName("visitChildren") + .and() + .haveRawParameterTypes(anyElementThat(isConcreteOperatorExpression)) + .should(new UseSignatureOrForwardToVisitChildren()) + .because( + "visits to concrete OperatorExpression types should visit the signature of the OperatorExpression") + .check(importedClasses); + } + + @Test + public void ensureConcreteElementsVisitSubclassFields() { + // TypeSpecifiers are excluded because they are terminal modes. They have a + // result type which would + // infinitely recurse if we didn't exclude them. + var isConcreteElement = and( + assignableTo(Element.class), + not(assignableTo(TypeSpecifier.class)), + not(modifier(JavaModifier.ABSTRACT))); + + methods() + .that() + .areDeclaredInClassesThat() + .areAssignableTo(BaseElmVisitor.class) + .and() + .haveNameStartingWith("visit") + .and() + .doNotHaveName("visitChildren") + .and() + .doNotHaveName("visitProperty") // Special exclusion for Property. See the implementation of + // visitProperty. + .and() + .haveRawParameterTypes(anyElementThat(isConcreteElement)) + .should(new UseAllFieldsOrForwardToVisitChildren()) + .because( + "visits to concrete OperatorExpression types should visit all the Element-type properties of the class") + .check(importedClasses); + } + + static class UseAllFieldsOrForwardToVisitChildren extends ArchCondition { + + public UseAllFieldsOrForwardToVisitChildren() { + super("visit all the properties of the class if they do not forward to visitChildren"); + } + + @Override + public void check(JavaMethod item, ConditionEvents events) { + var callsVisitChildren = item.getCallsFromSelf().stream() + .anyMatch(x -> x.getTarget().getName().equals("visitChildren")); + + var elementParameter = item.getRawParameterTypes().get(0); + + Predicate isElementProperty = x -> x.getName().startsWith("get") + && (x.getRawReturnType().isAssignableTo(Element.class) + || x.getTypeParameters().stream() + .anyMatch(y -> y.getClass().isAssignableFrom(Element.class))); + + // get all the properties that are Elements or collections of Elements + var elementMethods = elementParameter.getMethods().stream() + .filter(isElementProperty) + .collect(toSet()); + + if (callsVisitChildren) { + if (elementMethods.isEmpty()) { + events.add(SimpleConditionEvent.satisfied( + item, + String.format( + "Method %s calls visitChildren, Element defines no new properties, no need to visit properties", + item.getFullName()))); + return; + } else { + events.add(SimpleConditionEvent.violated( + item, + String.format( + "Method %s calls visitChildren, but Element defines new properties and visitChildren can not be used", + item.getFullName()))); + return; + } + } + + // Collect all the methods from the superclasses that return Element or + // collections of Element. + elementParameter.getAllRawSuperclasses().stream() + .flatMap(x -> x.getMethods().stream().filter(isElementProperty)) + .forEach(elementMethods::add); + + var calls = item.getMethodCallsFromSelf(); + + var allPropertiesCalled = elementMethods.stream() + .allMatch(x -> calls.stream().anyMatch(y -> y.getName().equals(x.getName()))); + + if (allPropertiesCalled) { + events.add(SimpleConditionEvent.satisfied( + item, String.format("Method %s visits all Element properties", item.getFullName()))); + return; + } + + events.add(SimpleConditionEvent.violated( + item, + String.format( + "Method %s does not call visitChildren or does not visit all Element properties", + item.getFullName()))); + } + } + + static class UseResultTypeIfTheyDoNotForwardToVisitChildren extends ArchCondition { + + public UseResultTypeIfTheyDoNotForwardToVisitChildren() { + super("visit the ELM resultType is they do not forward to visitChildren"); + } + + @Override + public void check(JavaMethod item, ConditionEvents events) { + var callsVisitChildren = item.getCallsFromSelf().stream() + .anyMatch(x -> x.getTarget().getName().equals("visitChildren")); + if (callsVisitChildren) { + events.add(SimpleConditionEvent.satisfied( + item, + String.format( + "Method %s calls visitChildren, no need to call getResultTypeSpecifier", + item.getFullName()))); + return; + } + + var callsGetSignature = item.getMethodCallsFromSelf().stream() + .anyMatch(x -> x.getTarget().getName().equals("getResultTypeSpecifier") + && x.getTargetOwner().isAssignableTo(Element.class)); + + if (callsGetSignature) { + events.add(SimpleConditionEvent.satisfied( + item, String.format("Method %s calls getSignature", item.getFullName()))); + return; + } + + events.add(SimpleConditionEvent.violated( + item, String.format("Method %s does not call visitChildren or getSignature", item.getFullName()))); + } + } + + static class UseSignatureOrForwardToVisitChildren extends ArchCondition { + + public UseSignatureOrForwardToVisitChildren() { + super("visit the ELM signature is they do not forward to visitChildren"); + } + + @Override + public void check(JavaMethod item, ConditionEvents events) { + var callsVisitChildren = item.getCallsFromSelf().stream() + .anyMatch(x -> x.getTarget().getName().equals("visitChildren")); + if (callsVisitChildren) { + events.add(SimpleConditionEvent.satisfied( + item, + String.format( + "Method %s calls visitChildren, no need to call getSignature", item.getFullName()))); + return; + } + + var callsGetSignature = item.getMethodCallsFromSelf().stream() + .anyMatch(x -> x.getTarget().getName().equals("getSignature") + && x.getTargetOwner().isAssignableTo(OperatorExpression.class)); + + if (callsGetSignature) { + events.add(SimpleConditionEvent.satisfied( + item, String.format("Method %s calls getSignature", item.getFullName()))); + return; + } + + events.add(SimpleConditionEvent.violated( + item, String.format("Method %s does not call visitChildren or getSignature", item.getFullName()))); + } + } + + static class CallDefaultResult extends ArchCondition { + + public CallDefaultResult() { + super("call the defaultVisit method"); + } + + @Override + public void check(JavaMethod item, ConditionEvents events) { + var doesCallDefault = item.getCallsFromSelf().stream() + .anyMatch(x -> x.getTarget().getName().equals("defaultResult")); + if (!doesCallDefault) { + events.add(SimpleConditionEvent.violated( + item, String.format("Method %s does not call defaultResult", item.getFullName()))); + } else { + events.add(SimpleConditionEvent.satisfied( + item, String.format("Method %s calls defaultResult", item.getFullName()))); + } + } + } + + static class NotCallDefaultResult extends ArchCondition { + + public NotCallDefaultResult() { + super("not call the defaultVisit method"); + } + + @Override + public void check(JavaMethod item, ConditionEvents events) { + var doesCallDefault = item.getCallsFromSelf().stream() + .anyMatch(x -> x.getTarget().getName().equals("defaultResult")); + if (doesCallDefault) { + events.add(SimpleConditionEvent.violated( + item, String.format("Method %s does not call defaultResult", item.getFullName()))); + } else { + events.add(SimpleConditionEvent.satisfied( + item, String.format("Method %s calls defaultResult", item.getFullName()))); + } + } + } +} diff --git a/Src/java/elm/src/test/java/org/cqframework/cql/elm/visiting/ElmFunctionalVisitorTest.java b/Src/java/elm/src/test/java/org/cqframework/cql/elm/visiting/FunctionalElmVisitorTest.java similarity index 70% rename from Src/java/elm/src/test/java/org/cqframework/cql/elm/visiting/ElmFunctionalVisitorTest.java rename to Src/java/elm/src/test/java/org/cqframework/cql/elm/visiting/FunctionalElmVisitorTest.java index 2a0dfd876..4fa2c180f 100644 --- a/Src/java/elm/src/test/java/org/cqframework/cql/elm/visiting/ElmFunctionalVisitorTest.java +++ b/Src/java/elm/src/test/java/org/cqframework/cql/elm/visiting/FunctionalElmVisitorTest.java @@ -9,12 +9,12 @@ import org.hl7.elm.r1.Library.Statements; import org.junit.Test; -public class ElmFunctionalVisitorTest { +public class FunctionalElmVisitorTest { @Test public void countTest() { // set up visitor that counts all visited elements - var trackableCounter = new ElmFunctionalVisitor((elm, context) -> 1, Integer::sum); + var trackableCounter = new FunctionalElmVisitor((elm, context) -> 1, Integer::sum); var library = new Library(); library.setStatements(new Statements()); @@ -27,12 +27,12 @@ public void countTest() { // set up visitor that counts all visited ELM elements var elmCounter = - new ElmFunctionalVisitor((elm, context) -> elm instanceof Element ? 1 : 0, Integer::sum); + new FunctionalElmVisitor((elm, context) -> elm instanceof Element ? 1 : 0, Integer::sum); result = elmCounter.visitLibrary(library, null); assertEquals(4, result.intValue()); - var maxFiveCounter = new ElmFunctionalVisitor( + var maxFiveCounter = new FunctionalElmVisitor( (elm, context) -> 1, (aggregate, nextResult) -> aggregate >= 5 ? aggregate : aggregate + nextResult); result = maxFiveCounter.visitLibrary(library, null); @@ -41,8 +41,10 @@ public void countTest() { @Test public void nullVisitorTest() { - assertThrows(NullPointerException.class, () -> new ElmFunctionalVisitor(null, null)); - assertThrows(NullPointerException.class, () -> new ElmFunctionalVisitor(null, Integer::sum)); - assertThrows(NullPointerException.class, () -> new ElmFunctionalVisitor((x, y) -> 1, null)); + assertThrows(NullPointerException.class, () -> new FunctionalElmVisitor(null, null)); + assertThrows( + NullPointerException.class, () -> new FunctionalElmVisitor(null, Integer::sum)); + assertThrows( + NullPointerException.class, () -> new FunctionalElmVisitor((x, y) -> 1, null)); } } diff --git a/Src/java/elm/src/test/java/org/cqframework/cql/elm/visiting/RandomElmGraphTest.java b/Src/java/elm/src/test/java/org/cqframework/cql/elm/visiting/RandomElmGraphTest.java new file mode 100644 index 000000000..45a521828 --- /dev/null +++ b/Src/java/elm/src/test/java/org/cqframework/cql/elm/visiting/RandomElmGraphTest.java @@ -0,0 +1,162 @@ +package org.cqframework.cql.elm.visiting; + +import static org.junit.Assert.assertEquals; + +import java.lang.reflect.Field; +import java.nio.charset.Charset; +import java.util.HashMap; +import javax.xml.namespace.QName; +import org.hl7.cql_annotations.r1.Narrative; +import org.hl7.elm.r1.AccessModifier; +import org.hl7.elm.r1.Element; +import org.hl7.elm.r1.Library; +import org.hl7.elm.r1.TypeSpecifier; +import org.jeasy.random.EasyRandom; +import org.jeasy.random.EasyRandomParameters; +import org.jeasy.random.ObjenesisObjectFactory; +import org.jeasy.random.api.ExclusionPolicy; +import org.jeasy.random.api.RandomizerContext; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class RandomElmGraphTest { + + @Parameters + public static Iterable seeds() { + // I randomly picked these seeds until + // I got 3 in a row that passed without errors. + // Not perfect, but it's a start. + return java.util.Arrays.asList(new Object[][] {{96874}, {15895}, {121873}, {174617}}); + } + + public RandomElmGraphTest(int seed) { + this.seed = seed; + } + + private int seed; + + @Test + public void allNodesVisited() { + allNodesVisited(seed); + } + + public void allNodesVisited(int seed) { + // This test generates a random ELM graph and verifies that all nodes are + // visited exactly once. + var elementsGenerated = new HashMap(); + var countingObjectFactory = new ObjenesisObjectFactory() { + @Override + public T createInstance(Class type, RandomizerContext context) { + var t = super.createInstance(type, context); + if (t instanceof Element) { + var hash = System.identityHashCode(t); + elementsGenerated.put(hash, (Element) t); + } + + // Debugging for specific types and paths + // that aren't being visited. + // if (t instanceof CaseItem) { + // printContext((Element) t, context); + // } + + return t; + } + + private void printContext(Element t, RandomizerContext context) { + System.err.println(String.format( + "Type: %s, Parent: %s, Path: %s, Hash: %s", + t.getClass().getSimpleName(), + context.getCurrentObject().getClass().getSimpleName(), + context.getCurrentField(), + System.identityHashCode(t))); + } + }; + + var randomParams = new EasyRandomParameters() + .objectFactory(countingObjectFactory) + .seed(seed) + .randomizationDepth(15) + .objectPoolSize(1000) // Never reuse objects + .charset(Charset.forName("UTF-8")) + .stringLengthRange(5, 50) + .collectionSizeRange(1, 3) + .exclusionPolicy(new NoTypeSpecifierRecursionPolicy()) + .scanClasspathForConcreteTypes(true); + + var randomElmGenerator = new EasyRandom(randomParams); + var randomElm = randomElmGenerator.nextObject(Library.class); + + var elementsGeneratedCount = elementsGenerated.size(); + + var elementsVisited = new HashMap(); + var elementsDuplicated = new HashMap(); + var countingVisitor = new FunctionalElmVisitor>( + (x, y) -> { + if (x instanceof Element) { + var hash = System.identityHashCode(x); + if (!elementsVisited.containsKey(hash)) { + elementsVisited.put(hash, (Element) x); + return 1; + } + elementsDuplicated.put(hash, (Element) x); + return 0; + } + return 0; + }, + (a, b) -> a + b); + + var visitorCount = countingVisitor.visitLibrary(randomElm, elementsVisited); + + elementsGenerated.keySet().removeAll(elementsVisited.keySet()); + if (!elementsGenerated.isEmpty()) { + System.err.println("Elements Missed:"); + elementsGenerated.forEach((x, e) -> System.err.println( + String.format("Type: %s, Hash: %s", e.getClass().getSimpleName(), x))); + } + + // No missed nodes, working as intended + assertEquals(0, elementsGenerated.size()); + + // Check that we didn't double-visit any nodes + if (!elementsDuplicated.isEmpty()) { + System.err.println("Elements Duplicated:"); + elementsDuplicated.forEach((x, e) -> System.err.println( + String.format("Type: %s, Hash: %s", e.getClass().getSimpleName(), x))); + } + + // No duplicate visits, working as intended + assertEquals(0, elementsDuplicated.size()); + + // if these are equal, then aggregateResult + // ran once for every node in the graph (working as intended) + assertEquals(elementsGeneratedCount, visitorCount.intValue()); + } + + class NoTypeSpecifierRecursionPolicy implements ExclusionPolicy { + + // Don't recurse into TypeSpecifier.resultTypeSpecifier + @Override + public boolean shouldBeExcluded(Field field, RandomizerContext context) { + if (field.getType().getPackageName().startsWith("org.hl7.cql")) { + return true; + } + + return (field.getName().equals("resultTypeSpecifier") + && TypeSpecifier.class.isAssignableFrom(field.getType())) + || field.getName().equals("signature"); + } + + // These are excluded to simplify the ELM graph while bugs are being worked out. + @Override + public boolean shouldBeExcluded(Class type, RandomizerContext context) { + if (type.getPackageName().startsWith("org.hl7.cql")) { + return true; + } + + return type == QName.class || type == Narrative.class || type == AccessModifier.class; + } + } +} diff --git a/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/execution/EvaluationVisitor.java b/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/execution/EvaluationVisitor.java index 12d91cee8..b841b2def 100644 --- a/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/execution/EvaluationVisitor.java +++ b/Src/java/engine/src/main/java/org/opencds/cqf/cql/engine/execution/EvaluationVisitor.java @@ -4,14 +4,14 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; -import org.cqframework.cql.elm.visiting.ElmBaseLibraryVisitor; +import org.cqframework.cql.elm.visiting.BaseElmLibraryVisitor; import org.hl7.cql.model.IntervalType; import org.hl7.cql.model.ListType; import org.hl7.elm.r1.*; import org.opencds.cqf.cql.engine.elm.executing.*; import org.opencds.cqf.cql.engine.runtime.TemporalHelper; -public class EvaluationVisitor extends ElmBaseLibraryVisitor { +public class EvaluationVisitor extends BaseElmLibraryVisitor { @Override public Object visitExpressionDef(ExpressionDef expressionDef, State state) { diff --git a/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlLibraryLoadingTest.java b/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlLibraryLoadingTest.java index e03d8f5f8..413a39036 100644 --- a/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlLibraryLoadingTest.java +++ b/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/CqlLibraryLoadingTest.java @@ -1,7 +1,7 @@ package org.opencds.cqf.cql.engine.execution; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.assertThat; import org.cqframework.cql.cql2elm.CqlIncludeException; import org.hl7.elm.r1.VersionedIdentifier; diff --git a/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/model/CachingModelResolverDecoratorTest.java b/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/model/CachingModelResolverDecoratorTest.java index 1a77039b9..981701435 100644 --- a/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/model/CachingModelResolverDecoratorTest.java +++ b/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/model/CachingModelResolverDecoratorTest.java @@ -52,6 +52,7 @@ public void context_path_resolved_only_once() { } @Test + @SuppressWarnings("unchecked") public void type_resolved_only_once() { var m = mock(ModelResolver.class); when(m.getPackageName()).thenReturn("test.package"); diff --git a/Src/java/tools/cql-formatter/src/test/java/org/cqframework/cql/tools/formatter/CqlFormatterVisitorTest.java b/Src/java/tools/cql-formatter/src/test/java/org/cqframework/cql/tools/formatter/CqlFormatterVisitorTest.java index 59b78f1d2..e1bc64ad2 100644 --- a/Src/java/tools/cql-formatter/src/test/java/org/cqframework/cql/tools/formatter/CqlFormatterVisitorTest.java +++ b/Src/java/tools/cql-formatter/src/test/java/org/cqframework/cql/tools/formatter/CqlFormatterVisitorTest.java @@ -4,7 +4,7 @@ import java.io.IOException; import java.io.InputStream; -import org.cqframework.cql.cql2elm.Cql2ElmVisitor; +import org.cqframework.cql.cql2elm.ElmGenerator; import org.testng.Assert; import org.testng.annotations.Test; @@ -164,7 +164,7 @@ private boolean inputMatchesOutput(String input, String output) { } private InputStream getInput(String fileName) { - InputStream is = Cql2ElmVisitor.class.getResourceAsStream(fileName); + InputStream is = ElmGenerator.class.getResourceAsStream(fileName); if (is == null) { is = CqlFormatterVisitorTest.class.getResourceAsStream(fileName); @@ -172,7 +172,7 @@ private InputStream getInput(String fileName) { if (is == null) { throw new IllegalArgumentException(String.format( "Invalid test resource: %s not in %s or %s", - fileName, Cql2ElmVisitor.class.getSimpleName(), CqlFormatterVisitor.class.getSimpleName())); + fileName, ElmGenerator.class.getSimpleName(), CqlFormatterVisitor.class.getSimpleName())); } } diff --git a/codecov.yaml b/codecov.yaml index 9b5f5654a..fd907fd55 100644 --- a/codecov.yaml +++ b/codecov.yaml @@ -1,3 +1,6 @@ +codecov: + max_report_age: off + coverage: status: project: