
001package org.hl7.fhir.r5.elementmodel; 002 003import java.io.ByteArrayInputStream; 004import java.io.IOException; 005import java.io.InputStream; 006import java.io.OutputStream; 007import java.util.ArrayList; 008import java.util.HashMap; 009import java.util.List; 010import java.util.Map; 011 012import org.hl7.fhir.exceptions.DefinitionException; 013import org.hl7.fhir.exceptions.FHIRException; 014import org.hl7.fhir.exceptions.FHIRFormatError; 015import org.hl7.fhir.r5.context.IWorkerContext; 016import org.hl7.fhir.r5.elementmodel.Element.SpecialElement; 017import org.hl7.fhir.r5.fhirpath.ExpressionNode; 018import org.hl7.fhir.r5.fhirpath.FHIRLexer; 019import org.hl7.fhir.r5.fhirpath.FHIRPathEngine; 020import org.hl7.fhir.r5.fhirpath.FHIRLexer.FHIRLexerException; 021import org.hl7.fhir.r5.formats.IParser.OutputStyle; 022import org.hl7.fhir.r5.model.StructureDefinition; 023import org.hl7.fhir.r5.model.ConceptMap.ConceptMapGroupUnmappedMode; 024import org.hl7.fhir.r5.model.Enumerations.ConceptMapRelationship; 025import org.hl7.fhir.r5.model.Enumerations.PublicationStatus; 026import org.hl7.fhir.r5.model.StructureMap.StructureMapGroupTypeMode; 027import org.hl7.fhir.r5.model.StructureMap.StructureMapTransform; 028import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities; 029import org.hl7.fhir.utilities.SourceLocation; 030import org.hl7.fhir.utilities.FileUtilities; 031import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage; 032import org.hl7.fhir.utilities.Utilities; 033import org.hl7.fhir.utilities.VersionUtilities; 034import org.hl7.fhir.utilities.validation.ValidationMessage; 035import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; 036import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; 037import org.hl7.fhir.utilities.validation.ValidationMessage.Source; 038 039@MarkedToMoveToAdjunctPackage 040public class FmlParser extends ParserBase { 041 042 private FHIRPathEngine fpe; 043 044 public FmlParser(IWorkerContext context) { 045 super(context); 046 fpe = new FHIRPathEngine(context); 047 } 048 049 @Override 050 public List<ValidatedFragment> parse(InputStream inStream) throws IOException, FHIRFormatError, DefinitionException, FHIRException { 051 byte[] content = FileUtilities.streamToBytes(inStream); 052 ByteArrayInputStream stream = new ByteArrayInputStream(content); 053 String text = FileUtilities.streamToString(stream); 054 List<ValidatedFragment> result = new ArrayList<>(); 055 ValidatedFragment focusFragment = new ValidatedFragment(ValidatedFragment.FOCUS_NAME, "fml", content, false); 056 focusFragment.setElement(parse(focusFragment.getErrors(), text)); 057 result.add(focusFragment); 058 return result; 059 } 060 061 @Override 062 public void compose(Element e, OutputStream destination, OutputStyle style, String base) 063 throws FHIRException, IOException { 064 throw new Error("Not done yet"); 065 } 066 067 public Element parse(List<ValidationMessage> errors, String text) throws FHIRException { 068 FHIRLexer lexer = new FHIRLexer(text, "source", true, true); 069 if (lexer.done()) 070 throw lexer.error("Map Input cannot be empty"); 071 Element result = Manager.build(context, context.fetchTypeDefinition("StructureMap")); 072 try { 073 if (lexer.hasToken("map")) { 074 lexer.token("map"); 075 result.makeElement("url").markLocation(lexer.getCurrentLocation()).setValue(lexer.readConstant("url")); 076 lexer.token("="); 077 result.makeElement("name").markLocation(lexer.getCurrentLocation()).setValue(lexer.readConstant("name")); 078 if (lexer.hasComments()) { 079 result.makeElement("description").markLocation(lexer.getCurrentLocation()).setValue(lexer.getAllComments()); 080 } 081 } 082 while (lexer.hasToken("///")) { 083 lexer.next(); 084 String fid = lexer.takeDottedToken(); 085 Element e = result.makeElement(fid).markLocation(lexer.getCurrentLocation()); 086 lexer.token("="); 087 e.setValue(lexer.readConstant("meta value")); 088 } 089 lexer.setMetadataFormat(false); 090 if (!result.hasChild("status")) { 091 result.makeElement("status").setValue("draft"); 092 } 093 if (!result.hasChild("id") && result.hasChild("name")) { 094 String id = Utilities.makeId(result.getChildValue("name")); 095 if (!Utilities.noString(id)) { 096 result.makeElement("id").setValue(id); 097 } 098 } 099 if (!result.hasChild("description") && result.hasChild("title")) { 100 result.makeElement("description").setValue(Utilities.makeId(result.getChildValue("title"))); 101 } 102 103 while (lexer.hasToken("conceptmap")) 104 parseConceptMap(result, lexer); 105 106 while (lexer.hasToken("uses")) 107 parseUses(result, lexer); 108 while (lexer.hasToken("imports")) 109 parseImports(result, lexer); 110 111 while (lexer.hasToken("conceptmap")) 112 parseConceptMap(result, lexer); 113 114 while (!lexer.done()) { 115 parseGroup(result, lexer); 116 } 117 } catch (FHIRLexerException e) { 118 if (policy == ValidationPolicy.NONE) { 119 throw e; 120 } else { 121 logError(errors, "2023-02-24", e.getLocation().getLine(), e.getLocation().getColumn(), "??", IssueType.INVALID, e.getMessage(), IssueSeverity.FATAL); 122 } 123 } catch (Exception e) { 124 if (policy == ValidationPolicy.NONE) { 125 throw e; 126 } else { 127 logError(errors, "2023-02-24", -1, -1, "?", IssueType.INVALID, e.getMessage(), IssueSeverity.FATAL); 128 } 129 } 130 result.setIgnorePropertyOrder(true); 131 return result; 132 } 133 134 private void parseConceptMap(Element structureMap, FHIRLexer lexer) throws FHIRLexerException { 135 lexer.token("conceptmap"); 136 Element map = structureMap.makeElement("contained"); 137 StructureDefinition sd = context.fetchTypeDefinition("ConceptMap"); 138 map.updateProperty(new Property(context, sd.getSnapshot().getElement().get(0), sd, getProfileUtilities(), getContextUtilities()), SpecialElement.fromProperty(map.getElementProperty() != null ? map.getElementProperty() : map.getProperty()), map.getProperty()); 139 map.setType("ConceptMap"); 140 Element eid = map.makeElement("id").markLocation(lexer.getCurrentLocation()); 141 String id = lexer.readConstant("map id"); 142 if (id.startsWith("#")) 143 throw lexer.error("Concept Map identifier must not start with #"); 144 eid.setValue(id); 145 map.makeElement("status").setValue(structureMap.getChildValue("status")); 146 lexer.token("{"); 147 // lexer.token("source"); 148 // map.setSource(new UriType(lexer.readConstant("source"))); 149 // lexer.token("target"); 150 // map.setSource(new UriType(lexer.readConstant("target"))); 151 Map<String, String> prefixes = new HashMap<String, String>(); 152 while (lexer.hasToken("prefix")) { 153 lexer.token("prefix"); 154 String n = lexer.take(); 155 lexer.token("="); 156 String v = lexer.readConstant("prefix url"); 157 prefixes.put(n, v); 158 } 159 while (lexer.hasToken("unmapped")) { 160 lexer.token("unmapped"); 161 lexer.token("for"); 162 String n = readPrefix(prefixes, lexer); 163 Element g = getGroupE(map, n, null); 164 lexer.token("="); 165 SourceLocation loc = lexer.getCurrentLocation(); 166 String v = lexer.take(); 167 if (v.equals("provided")) { 168 g.makeElement("unmapped").makeElement("mode").markLocation(loc).setValue(ConceptMapGroupUnmappedMode.USESOURCECODE.toCode()); 169 } else 170 throw lexer.error("Only unmapped mode PROVIDED is supported at this time"); 171 } 172 while (!lexer.hasToken("}")) { 173 String comments = lexer.hasComments() ? lexer.getAllComments() : null; 174 String srcs = readPrefix(prefixes, lexer); 175 lexer.token(":"); 176 SourceLocation scloc = lexer.getCurrentLocation(); 177 String sc = lexer.getCurrent().startsWith("\"") ? lexer.readConstant("code") : lexer.take(); 178 SourceLocation relLoc = lexer.getCurrentLocation(); 179 ConceptMapRelationship rel = readRelationship(lexer); 180 String tgts = readPrefix(prefixes, lexer); 181 Element g = getGroupE(map, srcs, tgts); 182 Element e = g.addElement("element"); 183 if (comments != null) { 184 for (String s : comments.split("\\r\\n")) { 185 e.getComments().add(s); 186 } 187 } 188 e.makeElement("code").markLocation(scloc).setValue(sc.startsWith("\"") ? lexer.processConstant(sc) : sc); 189 Element tgt = e.addElement("target"); 190 tgt.makeElement("relationship").markLocation(relLoc).setValue(rel.toCode()); 191 lexer.token(":"); 192 tgt.makeElement("code").markLocation(lexer.getCurrentLocation()).setValue(lexer.getCurrent().startsWith("\"") ? lexer.readConstant("code") : lexer.take()); 193 if (lexer.hasComments()) { 194 tgt.makeElement("comment").markLocation(lexer.getCommentLocation()).setValue(lexer.getFirstComment()); 195 } 196 } 197 lexer.token("}"); 198 } 199 200 private Element getGroupE(Element map, String srcs, String tgts) { 201 for (Element grp : map.getChildrenByName("group")) { 202 if (grp.getChildValue("source").equals(srcs)) { 203 Element tgt = grp.getNamedChild("target"); 204 if (tgt == null || tgts == null || tgts.equals(tgt.getValue())) { 205 if (tgt == null && tgts != null) 206 grp.makeElement("target").setValue(tgts); 207 return grp; 208 } 209 } 210 } 211 Element grp = map.addElement("group"); 212 grp.makeElement("source").setValue(srcs); 213 grp.makeElement("target").setValue(tgts); 214 return grp; 215 } 216 217 private String readPrefix(Map<String, String> prefixes, FHIRLexer lexer) throws FHIRLexerException { 218 String prefix = lexer.take(); 219 if (!prefixes.containsKey(prefix)) 220 throw lexer.error("Unknown prefix '" + prefix + "'"); 221 return prefixes.get(prefix); 222 } 223 224 225 private ConceptMapRelationship readRelationship(FHIRLexer lexer) throws FHIRLexerException { 226 String token = lexer.take(); 227 if (token.equals("-")) 228 return ConceptMapRelationship.RELATEDTO; 229 if (token.equals("=")) // temporary 230 return ConceptMapRelationship.RELATEDTO; 231 if (token.equals("==")) 232 return ConceptMapRelationship.EQUIVALENT; 233 if (token.equals("!=")) 234 return ConceptMapRelationship.NOTRELATEDTO; 235 if (token.equals("<=")) 236 return ConceptMapRelationship.SOURCEISNARROWERTHANTARGET; 237 if (token.equals(">=")) 238 return ConceptMapRelationship.SOURCEISBROADERTHANTARGET; 239 throw lexer.error("Unknown relationship token '" + token + "'"); 240 } 241 242 private void parseUses(Element result, FHIRLexer lexer) throws FHIRException { 243 lexer.token("uses"); 244 Element st = result.addElement("structure"); 245 st.makeElement("url").markLocation(lexer.getCurrentLocation()).setValue(lexer.readConstant("url")); 246 if (lexer.hasToken("alias")) { 247 lexer.token("alias"); 248 st.makeElement("alias").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 249 } 250 lexer.token("as"); 251 st.makeElement("mode").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 252 lexer.skipToken(";"); 253 if (lexer.hasComments()) { 254 st.makeElement("documentation").markLocation(lexer.getCommentLocation()).setValue(lexer.getFirstComment()); 255 } 256 } 257 258 259 private void parseImports(Element result, FHIRLexer lexer) throws FHIRException { 260 lexer.token("imports"); 261 result.addElement("import").markLocation(lexer.getCurrentLocation()).setValue(lexer.readConstant("url")); 262 lexer.skipToken(";"); 263 } 264 265 private void parseGroup(Element result, FHIRLexer lexer) throws FHIRException { 266 SourceLocation commLoc = lexer.getCommentLocation(); 267 String comment = lexer.getAllComments(); 268 lexer.token("group"); 269 Element group = result.addElement("group").markLocation(lexer.getCurrentLocation()); 270 if (!Utilities.noString(comment)) { 271 group.makeElement("documentation").markLocation(commLoc).setValue(comment); 272 } 273 boolean newFmt = false; 274 if (lexer.hasToken("for")) { 275 lexer.token("for"); 276 SourceLocation loc = lexer.getCurrentLocation(); 277 if ("type".equals(lexer.getCurrent())) { 278 lexer.token("type"); 279 lexer.token("+"); 280 lexer.token("types"); 281 group.makeElement("typeMode").markLocation(loc).setValue(StructureMapGroupTypeMode.TYPEANDTYPES.toCode()); 282 } else { 283 lexer.token("types"); 284 group.makeElement("typeMode").markLocation(loc).setValue(StructureMapGroupTypeMode.TYPES.toCode()); 285 } 286 } 287 group.makeElement("name").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 288 if (lexer.hasToken("(")) { 289 newFmt = true; 290 lexer.take(); 291 while (!lexer.hasToken(")")) { 292 parseInput(group, lexer, true); 293 if (lexer.hasToken(",")) 294 lexer.token(","); 295 } 296 lexer.take(); 297 } 298 if (lexer.hasToken("extends")) { 299 lexer.next(); 300 group.makeElement("extends").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 301 } 302 if (newFmt) { 303 if (lexer.hasToken("<")) { 304 lexer.token("<"); 305 lexer.token("<"); 306 if (lexer.hasToken("types")) { 307 group.makeElement("typeMode").markLocation(lexer.getCurrentLocation()).setValue(StructureMapGroupTypeMode.TYPES.toCode()); 308 lexer.token("types"); 309 } else { 310 group.makeElement("typeMode").markLocation(lexer.getCurrentLocation()).setValue(StructureMapGroupTypeMode.TYPEANDTYPES.toCode()); 311 lexer.token("type"); 312 lexer.token("+"); 313 } 314 lexer.token(">"); 315 lexer.token(">"); 316 } 317 lexer.token("{"); 318 } 319 if (newFmt) { 320 while (!lexer.hasToken("}")) { 321 if (lexer.done()) 322 throw lexer.error("premature termination expecting 'endgroup'"); 323 parseRule(result, group, lexer, true); 324 } 325 } else { 326 while (lexer.hasToken("input")) 327 parseInput(group, lexer, false); 328 while (!lexer.hasToken("endgroup")) { 329 if (lexer.done()) 330 throw lexer.error("premature termination expecting 'endgroup'"); 331 parseRule(result, group, lexer, false); 332 } 333 } 334 lexer.next(); 335 if (newFmt && lexer.hasToken(";")) 336 lexer.next(); 337 } 338 339 340 private void parseRule(Element map, Element context, FHIRLexer lexer, boolean newFmt) throws FHIRException { 341 Element rule = context.addElement("rule").markLocation(lexer.getCurrentLocation()); 342 if (!newFmt) { 343 rule.makeElement("name").markLocation(lexer.getCurrentLocation()).setValue(lexer.takeDottedToken()); 344 lexer.token(":"); 345 lexer.token("for"); 346 } else { 347 if (lexer.hasComments()) { 348 rule.makeElement("documentation").markLocation(lexer.getCommentLocation()).setValue(lexer.getFirstComment()); 349 } 350 } 351 352 boolean done = false; 353 while (!done) { 354 parseSource(rule, lexer); 355 done = !lexer.hasToken(","); 356 if (!done) 357 lexer.next(); 358 } 359 if ((newFmt && lexer.hasToken("->")) || (!newFmt && lexer.hasToken("make"))) { 360 lexer.token(newFmt ? "->" : "make"); 361 done = false; 362 while (!done) { 363 parseTarget(rule, lexer); 364 done = !lexer.hasToken(","); 365 if (!done) 366 lexer.next(); 367 } 368 } 369 if (lexer.hasToken("then")) { 370 lexer.token("then"); 371 if (lexer.hasToken("{")) { 372 lexer.token("{"); 373 while (!lexer.hasToken("}")) { 374 if (lexer.done()) 375 throw lexer.error("premature termination expecting '}' in nested group"); 376 parseRule(map, rule, lexer, newFmt); 377 } 378 lexer.token("}"); 379 } else { 380 done = false; 381 while (!done) { 382 parseRuleReference(rule, lexer); 383 done = !lexer.hasToken(","); 384 if (!done) 385 lexer.next(); 386 } 387 } 388 } 389 if (!rule.hasChild("documentation") && lexer.hasComments()) { 390 rule.makeElement("documentation").markLocation(lexer.getCommentLocation()).setValue(lexer.getFirstComment()); 391 } 392 393 if (isSimpleSyntax(rule)) { 394 rule.forceElement("source").makeElement("variable").setValue(StructureMapUtilities.AUTO_VAR_NAME); 395 rule.forceElement("target").makeElement("variable").setValue(StructureMapUtilities.AUTO_VAR_NAME); 396 rule.forceElement("target").makeElement("transform").setValue(StructureMapTransform.CREATE.toCode()); 397 Element dep = rule.forceElement("dependent").markLocation(rule); 398 dep.makeElement("name").markLocation(rule).setValue(StructureMapUtilities.DEF_GROUP_NAME); 399 dep.addElement("parameter").markLocation(dep).makeElement("valueId").markLocation(dep).setValue(StructureMapUtilities.AUTO_VAR_NAME); 400 dep.addElement("parameter").markLocation(dep).makeElement("valueId").markLocation(dep).setValue(StructureMapUtilities.AUTO_VAR_NAME); 401 // no dependencies - imply what is to be done based on types 402 } 403 if (newFmt) { 404 if (lexer.isConstant()) { 405 if (lexer.isStringConstant()) { 406 rule.makeElement("name").markLocation(lexer.getCurrentLocation()).setValue(fixName(lexer.readConstant("ruleName"))); 407 } else { 408 rule.makeElement("name").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 409 } 410 } else { 411 if (rule.getChildrenByName("source").size() != 1 || !rule.getChildrenByName("source").get(0).hasChild("element")) 412 throw lexer.error("Complex rules must have an explicit name"); 413 if (rule.getChildrenByName("source").get(0).hasChild("type")) 414 rule.makeElement("name").setValue(rule.getChildrenByName("source").get(0).getNamedChildValue("element") + Utilities.capitalize(rule.getChildrenByName("source").get(0).getNamedChildValue("type"))); 415 else 416 rule.makeElement("name").setValue(rule.getChildrenByName("source").get(0).getNamedChildValue("element")); 417 } 418 lexer.token(";"); 419 } 420 } 421 422 private String fixName(String c) { 423 return c.replace("-", ""); 424 } 425 426 private void parseRuleReference(Element rule, FHIRLexer lexer) throws FHIRLexerException { 427 Element ref = rule.addElement("dependent").markLocation(lexer.getCurrentLocation()); 428 ref.makeElement("name").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 429 lexer.token("("); 430 boolean done = false; 431 while (!done) { 432 parseParameter(ref, lexer, false); 433 done = !lexer.hasToken(","); 434 if (!done) 435 lexer.next(); 436 } 437 lexer.token(")"); 438 } 439 440 private void parseSource(Element rule, FHIRLexer lexer) throws FHIRException { 441 Element source = rule.addElement("source").markLocation(lexer.getCurrentLocation()); 442 source.makeElement("context").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 443 if (source.getChildValue("context").equals("search") && lexer.hasToken("(")) { 444 source.makeElement("context").markLocation(lexer.getCurrentLocation()).setValue("@search"); 445 lexer.take(); 446 SourceLocation loc = lexer.getCurrentLocation(); 447 ExpressionNode node = fpe.parse(lexer); 448 source.setUserData(StructureMapUtilities.MAP_SEARCH_EXPRESSION, node); 449 source.makeElement("element").markLocation(loc).setValue(node.toString()); 450 lexer.token(")"); 451 } else if (lexer.hasToken(".")) { 452 lexer.token("."); 453 source.makeElement("element").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 454 } 455 if (lexer.hasToken(":")) { 456 // type and cardinality 457 lexer.token(":"); 458 source.makeElement("type").markLocation(lexer.getCurrentLocation()).setValue(lexer.takeDottedToken()); 459 } 460 if (Utilities.isInteger(lexer.getCurrent())) { 461 source.makeElement("min").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 462 lexer.token(".."); 463 source.makeElement("max").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 464 } 465 if (lexer.hasToken("default")) { 466 lexer.token("default"); 467 source.makeElement("defaultValue").markLocation(lexer.getCurrentLocation()).setValue(lexer.readConstant("default value")); 468 } 469 if (Utilities.existsInList(lexer.getCurrent(), "first", "last", "not_first", "not_last", "only_one")) { 470 source.makeElement("listMode").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 471 } 472 473 if (lexer.hasToken("as")) { 474 lexer.take(); 475 source.makeElement("variable").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 476 } 477 if (lexer.hasToken("where")) { 478 lexer.take(); 479 SourceLocation loc = lexer.getCurrentLocation(); 480 ExpressionNode node = fpe.parse(lexer); 481 source.setUserData(StructureMapUtilities.MAP_WHERE_EXPRESSION, node); 482 source.makeElement("condition").markLocation(loc).setValue(node.toString()); 483 } 484 if (lexer.hasToken("check")) { 485 lexer.take(); 486 SourceLocation loc = lexer.getCurrentLocation(); 487 ExpressionNode node = fpe.parse(lexer); 488 source.setUserData(StructureMapUtilities.MAP_WHERE_CHECK, node); 489 source.makeElement("check").markLocation(loc).setValue(node.toString()); 490 } 491 if (lexer.hasToken("log")) { 492 lexer.take(); 493 SourceLocation loc = lexer.getCurrentLocation(); 494 ExpressionNode node = fpe.parse(lexer); 495 source.setUserData(StructureMapUtilities.MAP_WHERE_CHECK, node); 496 source.makeElement("logMessage").markLocation(loc).setValue(lexer.take()); 497 } 498 } 499 500 private void parseTarget(Element rule, FHIRLexer lexer) throws FHIRException { 501 Element target = rule.addElement("target").markLocation(lexer.getCurrentLocation()); 502 SourceLocation loc = lexer.getCurrentLocation(); 503 String start = lexer.take(); 504 if (lexer.hasToken(".")) { 505 target.makeElement("context").markLocation(loc).setValue(start); 506 start = null; 507 lexer.token("."); 508 target.makeElement("element").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 509 } 510 String name; 511 boolean isConstant = false; 512 if (lexer.hasToken("=")) { 513 if (start != null) { 514 target.makeElement("context").markLocation(loc).setValue(start); 515 } 516 lexer.token("="); 517 isConstant = lexer.isConstant(); 518 loc = lexer.getCurrentLocation(); 519 name = lexer.take(); 520 } else { 521 loc = lexer.getCurrentLocation(); 522 name = start; 523 } 524 525 if ("(".equals(name)) { 526 // inline fluentpath expression 527 target.makeElement("transform").markLocation(lexer.getCurrentLocation()).setValue(StructureMapTransform.EVALUATE.toCode()); 528 loc = lexer.getCurrentLocation(); 529 ExpressionNode node = fpe.parse(lexer); 530 target.setUserData(StructureMapUtilities.MAP_EXPRESSION, node); 531 target.addElement("parameter").markLocation(loc).makeElement("valueString").setValue(node.toString()); 532 lexer.token(")"); 533 } else if (lexer.hasToken("(")) { 534 target.makeElement("transform").markLocation(loc).setValue(name); 535 lexer.token("("); 536 if (target.getChildValue("transform").equals(StructureMapTransform.EVALUATE.toCode())) { 537 parseParameter(target, lexer, true); 538 lexer.token(","); 539 loc = lexer.getCurrentLocation(); 540 ExpressionNode node = fpe.parse(lexer); 541 target.setUserData(StructureMapUtilities.MAP_EXPRESSION, node); 542 target.addElement("parameter").markLocation(loc).makeElement("valueString").setValue(node.toString()); 543 } else { 544 while (!lexer.hasToken(")")) { 545 parseParameter(target, lexer, true); 546 if (!lexer.hasToken(")")) 547 lexer.token(","); 548 } 549 } 550 lexer.token(")"); 551 } else if (name != null) { 552 target.makeElement("transform").markLocation(loc).setValue(StructureMapTransform.COPY.toCode()); 553 if (!isConstant) { 554 loc = lexer.getCurrentLocation(); 555 String id = name; 556 while (lexer.hasToken(".")) { 557 id = id + lexer.take() + lexer.take(); 558 } 559 target.addElement("parameter").markLocation(loc).makeElement("valueId").setValue(id); 560 } else { 561 target.addElement("parameter").markLocation(lexer.getCurrentLocation()).makeElement("valueString").setValue(readConstant(name, lexer)); 562 } 563 } 564 if (lexer.hasToken("as")) { 565 lexer.take(); 566 target.makeElement("variable").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 567 } 568 while (Utilities.existsInList(lexer.getCurrent(), "first", "last", "share", "collate")) { 569 if (lexer.getCurrent().equals("share")) { 570 target.makeElement("listMode").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 571 target.makeElement("listRuleId").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 572 } else { 573 target.makeElement("listMode").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 574 } 575 } 576 } 577 578 private void parseParameter(Element ref, FHIRLexer lexer, boolean isTarget) throws FHIRLexerException, FHIRFormatError { 579 boolean r5 = VersionUtilities.isR5Plus(context.getVersion()); 580 String name = r5 || isTarget ? "parameter" : "variable"; 581 if (ref.hasChildren(name) && !ref.getChildByName(name).isList()) { 582 throw lexer.error("variable on target is not a list, so can't add an element"); 583 } else if (!lexer.isConstant()) { 584 ref.addElement(name).markLocation(lexer.getCurrentLocation()).makeElement(r5 ? "valueId" : "value").setValue(lexer.take()); 585 } else if (lexer.isStringConstant()) 586 ref.addElement(name).markLocation(lexer.getCurrentLocation()).makeElement(r5 ? "valueString" : "value").setValue(lexer.readConstant("??")); 587 else { 588 ref.addElement(name).markLocation(lexer.getCurrentLocation()).makeElement(r5 ? "valueString" : "value").setValue(readConstant(lexer.take(), lexer)); 589 } 590 } 591 592 private void parseInput(Element group, FHIRLexer lexer, boolean newFmt) throws FHIRException { 593 Element input = group.addElement("input").markLocation(lexer.getCurrentLocation()); 594 if (newFmt) { 595 input.makeElement("mode").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 596 } else 597 lexer.token("input"); 598 input.makeElement("name").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 599 if (lexer.hasToken(":")) { 600 lexer.token(":"); 601 input.makeElement("type").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 602 } 603 if (!newFmt) { 604 lexer.token("as"); 605 input.makeElement("mode").markLocation(lexer.getCurrentLocation()).setValue(lexer.take()); 606 if (lexer.hasComments()) { 607 input.makeElement("documentation").markLocation(lexer.getCommentLocation()).setValue(lexer.getFirstComment()); 608 } 609 lexer.skipToken(";"); 610 } 611 } 612 613 private boolean isSimpleSyntax(Element rule) { 614 return 615 (rule.getChildren("source").size() == 1 && rule.getChildren("source").get(0).hasChild("context") && rule.getChildren("source").get(0).hasChild("element") && !rule.getChildren("source").get(0).hasChild("variable")) && 616 (rule.getChildren("target").size() == 1 && rule.getChildren("target").get(0).hasChild("context") && rule.getChildren("target").get(0).hasChild("element") && !rule.getChildren("target").get(0).hasChild("variable") && 617 !rule.getChildren("target").get(0).hasChild("parameter")) && 618 (rule.getChildren("dependent").size() == 0 && rule.getChildren("rule").size() == 0); 619 } 620 621 private String readConstant(String s, FHIRLexer lexer) throws FHIRLexerException { 622 if (Utilities.isInteger(s)) 623 return s; 624 else if (Utilities.isDecimal(s, false)) 625 return s; 626 else if (Utilities.existsInList(s, "true", "false")) 627 return s; 628 else 629 return lexer.processConstant(s); 630 } 631 632 633}