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