diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java
index e35d08127..939d93026 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java
@@ -2903,6 +2903,8 @@ public class FHIRPathEngine {
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Quantity);
} else if (constant instanceof FHIRConstant) {
return resolveConstantType(context, ((FHIRConstant) constant).getValue(), expr);
+ } else if (constant == null) {
+ return new TypeDetails(CollectionStatus.SINGLETON);
} else {
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String);
}
@@ -3140,60 +3142,60 @@ public class FHIRPathEngine {
return types;
}
case Lower : {
- checkContextString(focus, "lower", exp);
+ checkContextString(focus, "lower", exp, true);
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String);
}
case Upper : {
- checkContextString(focus, "upper", exp);
+ checkContextString(focus, "upper", exp, true);
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String);
}
case ToChars : {
- checkContextString(focus, "toChars", exp);
+ checkContextString(focus, "toChars", exp, true);
return new TypeDetails(CollectionStatus.ORDERED, TypeDetails.FP_String);
}
case IndexOf : {
- checkContextString(focus, "indexOf", exp);
+ checkContextString(focus, "indexOf", exp, true);
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer);
}
case Substring : {
- checkContextString(focus, "subString", exp);
+ checkContextString(focus, "subString", exp, true);
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Integer));
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String);
}
case StartsWith : {
- checkContextString(focus, "startsWith", exp);
+ checkContextString(focus, "startsWith", exp, true);
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean);
}
case EndsWith : {
- checkContextString(focus, "endsWith", exp);
+ checkContextString(focus, "endsWith", exp, true);
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean);
}
case Matches : {
- checkContextString(focus, "matches", exp);
+ checkContextString(focus, "matches", exp, true);
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean);
}
case MatchesFull : {
- checkContextString(focus, "matches", exp);
+ checkContextString(focus, "matches", exp, true);
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean);
}
case ReplaceMatches : {
- checkContextString(focus, "replaceMatches", exp);
+ checkContextString(focus, "replaceMatches", exp, true);
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String);
}
case Contains : {
- checkContextString(focus, "contains", exp);
+ checkContextString(focus, "contains", exp, true);
checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean);
}
case Replace : {
- checkContextString(focus, "replace", exp);
- checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, "string"), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
+ checkContextString(focus, "replace", exp, true);
+ checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String), new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String));
return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String);
}
case Length : {
@@ -3427,37 +3429,39 @@ public class FHIRPathEngine {
}
- private void checkContextString(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException {
- if (!focus.hasType(worker, "string") && !focus.hasType(worker, "code") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "canonical") && !focus.hasType(worker, "id")) {
- throw makeException(expr, I18nConstants.FHIRPATH_STRING_ONLY, name, focus.describe());
+ private void checkContextString(TypeDetails focus, String name, ExpressionNode expr, boolean sing) throws PathEngineException {
+ if (!focus.hasNoTypes() && !focus.hasType(worker, "string") && !focus.hasType(worker, "code") && !focus.hasType(worker, "uri") && !focus.hasType(worker, "canonical") && !focus.hasType(worker, "id")) {
+ throw makeException(expr, sing ? I18nConstants.FHIRPATH_STRING_SING_ONLY : I18nConstants.FHIRPATH_STRING_ORD_ONLY, name, focus.describe());
}
}
private void checkContextPrimitive(TypeDetails focus, String name, boolean canQty, ExpressionNode expr) throws PathEngineException {
- if (canQty) {
- if (!focus.hasType(primitiveTypes) && !focus.hasType("Quantity")) {
- throw makeException(expr, I18nConstants.FHIRPATH_PRIMITIVE_ONLY, name, focus.describe(), "Quantity, "+primitiveTypes.toString());
+ if (!focus.hasNoTypes()) {
+ if (canQty) {
+ if (!focus.hasType(primitiveTypes) && !focus.hasType("Quantity")) {
+ throw makeException(expr, I18nConstants.FHIRPATH_PRIMITIVE_ONLY, name, focus.describe(), "Quantity, "+primitiveTypes.toString());
+ }
+ } else if (!focus.hasType(primitiveTypes)) {
+ throw makeException(expr, I18nConstants.FHIRPATH_PRIMITIVE_ONLY, name, focus.describe(), primitiveTypes.toString());
}
- } else if (!focus.hasType(primitiveTypes)) {
- throw makeException(expr, I18nConstants.FHIRPATH_PRIMITIVE_ONLY, name, focus.describe(), primitiveTypes.toString());
}
}
private void checkContextNumerical(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException {
- if (!focus.hasType("integer") && !focus.hasType("decimal") && !focus.hasType("Quantity")) {
+ if (!focus.hasNoTypes() && !focus.hasType("integer") && !focus.hasType("decimal") && !focus.hasType("Quantity")) {
throw makeException(expr, I18nConstants.FHIRPATH_NUMERICAL_ONLY, name, focus.describe());
}
}
private void checkContextDecimal(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException {
- if (!focus.hasType("decimal") && !focus.hasType("integer")) {
+ if (!focus.hasNoTypes() && !focus.hasType("decimal") && !focus.hasType("integer")) {
throw makeException(expr, I18nConstants.FHIRPATH_DECIMAL_ONLY, name, focus.describe());
}
}
private void checkContextContinuous(TypeDetails focus, String name, ExpressionNode expr) throws PathEngineException {
- if (!focus.hasType("decimal") && !focus.hasType("date") && !focus.hasType("dateTime") && !focus.hasType("time")) {
+ if (!focus.hasNoTypes() && !focus.hasType("decimal") && !focus.hasType("date") && !focus.hasType("dateTime") && !focus.hasType("time")) {
throw makeException(expr, I18nConstants.FHIRPATH_CONTINUOUS_ONLY, name, focus.describe());
}
}
@@ -3672,7 +3676,10 @@ public class FHIRPathEngine {
private List funcExp(ExecutionContext context, List focus, ExpressionNode expr) {
- if (focus.size() != 1) {
+ if (focus.size() == 0) {
+ return new ArrayList();
+ }
+ if (focus.size() > 1) {
throw makeException(expr, I18nConstants.FHIRPATH_FOCUS_PLURAL, "exp", focus.size());
}
Base base = focus.get(0);
@@ -4218,15 +4225,19 @@ public class FHIRPathEngine {
private List funcReplace(ExecutionContext context, List focus, ExpressionNode expr) throws FHIRException, PathEngineException {
List result = new ArrayList();
+ List tB = execute(context, focus, expr.getParameters().get(0), true);
+ String t = convertToString(tB);
+ List rB = execute(context, focus, expr.getParameters().get(1), true);
+ String r = convertToString(rB);
- if (focus.size() == 1) {
+ if (focus.size() == 0 || tB.size() == 0 || rB.size() == 0) {
+ //
+ } else if (focus.size() == 1) {
if (focus.get(0).hasType(FHIR_TYPES_STRING) || doImplicitStringConversion) {
String f = convertToString(focus.get(0));
if (Utilities.noString(f)) {
result.add(new StringType(""));
} else {
- String t = convertToString(execute(context, focus, expr.getParameters().get(0), true));
- String r = convertToString(execute(context, focus, expr.getParameters().get(1), true));
String n = f.replace(t, r);
result.add(new StringType(n));
}
@@ -4240,10 +4251,14 @@ public class FHIRPathEngine {
private List funcReplaceMatches(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException {
List result = new ArrayList();
- String regex = convertToString(execute(context, focus, exp.getParameters().get(0), true));
- String repl = convertToString(execute(context, focus, exp.getParameters().get(1), true));
+ List regexB = execute(context, focus, exp.getParameters().get(0), true);
+ String regex = convertToString(regexB);
+ List replB = execute(context, focus, exp.getParameters().get(1), true);
+ String repl = convertToString(replB);
- if (focus.size() == 1 && !Utilities.noString(regex)) {
+ if (focus.size() == 0 || regexB.size() == 0 || replB.size() == 0) {
+ //
+ } else if (focus.size() == 1 && !Utilities.noString(regex)) {
if (focus.get(0).hasType(FHIR_TYPES_STRING) || doImplicitStringConversion) {
result.add(new StringType(convertToString(focus.get(0)).replaceAll(regex, repl)).noExtensions());
}
@@ -4256,10 +4271,13 @@ public class FHIRPathEngine {
private List funcEndsWith(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException {
List result = new ArrayList();
- String sw = convertToString(execute(context, focus, exp.getParameters().get(0), true));
+ List swb = execute(context, focus, exp.getParameters().get(0), true);
+ String sw = convertToString(swb);
if (focus.size() == 0) {
- result.add(new BooleanType(false).noExtensions());
+ //
+ } else if (swb.size() == 0) {
+ //
} else if (Utilities.noString(sw)) {
result.add(new BooleanType(true).noExtensions());
} else if (focus.get(0).hasType(FHIR_TYPES_STRING) || doImplicitStringConversion) {
@@ -4929,9 +4947,12 @@ public class FHIRPathEngine {
private List funcMatches(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException {
List result = new ArrayList();
- String sw = convertToString(execute(context, focus, exp.getParameters().get(0), true));
+ List swb = execute(context, focus, exp.getParameters().get(0), true);
+ String sw = convertToString(swb);
- if (focus.size() == 1 && !Utilities.noString(sw)) {
+ if (focus.size() == 0 || swb.size() == 0) {
+ //
+ } else if (focus.size() == 1 && !Utilities.noString(sw)) {
if (focus.get(0).hasType(FHIR_TYPES_STRING) || doImplicitStringConversion) {
String st = convertToString(focus.get(0));
if (Utilities.noString(st)) {
@@ -4973,10 +4994,13 @@ public class FHIRPathEngine {
private List funcContains(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException {
List result = new ArrayList();
- String sw = convertToString(execute(context, baseToList(context.thisItem), exp.getParameters().get(0), true));
+ List swb = execute(context, baseToList(context.thisItem), exp.getParameters().get(0), true);
+ String sw = convertToString(swb);
if (focus.size() != 1) {
- result.add(new BooleanType(false).noExtensions());
+ //
+ } else if (swb.size() != 1) {
+ //
} else if (Utilities.noString(sw)) {
result.add(new BooleanType(true).noExtensions());
} else if (focus.get(0).hasType(FHIR_TYPES_STRING) || doImplicitStringConversion) {
@@ -5018,10 +5042,13 @@ public class FHIRPathEngine {
private List funcStartsWith(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException {
List result = new ArrayList();
- String sw = convertToString(execute(context, focus, exp.getParameters().get(0), true));
+ List swb = execute(context, focus, exp.getParameters().get(0), true);
+ String sw = convertToString(swb);
if (focus.size() == 0) {
- result.add(new BooleanType(false).noExtensions());
+ // no result
+ } else if (swb.size() == 0) {
+ // no result
} else if (Utilities.noString(sw)) {
result.add(new BooleanType(true).noExtensions());
} else if (focus.get(0).hasType(FHIR_TYPES_STRING) || doImplicitStringConversion) {
@@ -5071,9 +5098,12 @@ public class FHIRPathEngine {
private List funcIndexOf(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException {
List result = new ArrayList();
- String sw = convertToString(execute(context, focus, exp.getParameters().get(0), true));
+ List swb = execute(context, focus, exp.getParameters().get(0), true);
+ String sw = convertToString(swb);
if (focus.size() == 0) {
- result.add(new IntegerType(0).noExtensions());
+ // no result
+ } else if (swb.size() == 0) {
+ // no result
} else if (Utilities.noString(sw)) {
result.add(new IntegerType(0).noExtensions());
} else if (focus.get(0).hasType(FHIR_TYPES_STRING) || doImplicitStringConversion) {