001package org.hl7.fhir.r4.model; 002 003/* 004 Copyright (c) 2011+, HL7, Inc. 005 All rights reserved. 006 007 Redistribution and use in source and binary forms, with or without modification, 008 are permitted provided that the following conditions are met: 009 010 * Redistributions of source code must retain the above copyright notice, this 011 list of conditions and the following disclaimer. 012 * Redistributions in binary form must reproduce the above copyright notice, 013 this list of conditions and the following disclaimer in the documentation 014 and/or other materials provided with the distribution. 015 * Neither the name of HL7 nor the names of its contributors may be used to 016 endorse or promote products derived from this software without specific 017 prior written permission. 018 019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 022 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 023 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 024 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 025 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 026 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 028 POSSIBILITY OF SUCH DAMAGE. 029 030 */ 031 032import java.util.ArrayList; 033import java.util.List; 034 035import org.hl7.fhir.utilities.SourceLocation; 036import org.hl7.fhir.utilities.Utilities; 037 038public class ExpressionNode { 039 040 public enum Kind { 041 Name, Function, Constant, Group, Unary 042 } 043 044 public enum Function { 045 Custom, 046 047 Empty, Not, Exists, SubsetOf, SupersetOf, IsDistinct, Distinct, Count, Where, Select, All, Repeat, Aggregate, 048 Item /* implicit from name[] */, As, Is, Single, First, Last, Tail, Skip, Take, Union, Combine, Intersect, Exclude, 049 Iif, Upper, Lower, ToChars, IndexOf, Substring, StartsWith, EndsWith, Matches, MatchesFull, ReplaceMatches, 050 Contains, Replace, Length, Children, Descendants, MemberOf, Trace, Check, Today, Now, Resolve, Extension, AllFalse, 051 AnyFalse, AllTrue, AnyTrue, HasValue, OfType, Type, ConvertsToBoolean, ConvertsToInteger, ConvertsToString, 052 ConvertsToDecimal, ConvertsToQuantity, ConvertsToDateTime, ConvertsToDate, ConvertsToTime, ToBoolean, ToInteger, 053 ToString, ToDecimal, ToQuantity, ToDateTime, ToTime, ConformsTo, Round, Sqrt, Abs, Ceiling, Exp, Floor, Ln, Log, 054 Power, Truncate, 055 056 // R3 functions 057 Encode, Decode, Escape, Unescape, Trim, Split, Join, LowBoundary, HighBoundary, Precision, 058 059 // Local extensions to FHIRPath 060 HtmlChecks1, HtmlChecks2, AliasAs, Alias, Comparable; 061 062 public static Function fromCode(String name) { 063 if (name.equals("empty")) 064 return Function.Empty; 065 if (name.equals("not")) 066 return Function.Not; 067 if (name.equals("exists")) 068 return Function.Exists; 069 if (name.equals("subsetOf")) 070 return Function.SubsetOf; 071 if (name.equals("supersetOf")) 072 return Function.SupersetOf; 073 if (name.equals("isDistinct")) 074 return Function.IsDistinct; 075 if (name.equals("distinct")) 076 return Function.Distinct; 077 if (name.equals("count")) 078 return Function.Count; 079 if (name.equals("where")) 080 return Function.Where; 081 if (name.equals("select")) 082 return Function.Select; 083 if (name.equals("all")) 084 return Function.All; 085 if (name.equals("repeat")) 086 return Function.Repeat; 087 if (name.equals("aggregate")) 088 return Function.Aggregate; 089 if (name.equals("item")) 090 return Function.Item; 091 if (name.equals("as")) 092 return Function.As; 093 if (name.equals("is")) 094 return Function.Is; 095 if (name.equals("single")) 096 return Function.Single; 097 if (name.equals("first")) 098 return Function.First; 099 if (name.equals("last")) 100 return Function.Last; 101 if (name.equals("tail")) 102 return Function.Tail; 103 if (name.equals("skip")) 104 return Function.Skip; 105 if (name.equals("take")) 106 return Function.Take; 107 if (name.equals("union")) 108 return Function.Union; 109 if (name.equals("combine")) 110 return Function.Combine; 111 if (name.equals("intersect")) 112 return Function.Intersect; 113 if (name.equals("exclude")) 114 return Function.Exclude; 115 if (name.equals("iif")) 116 return Function.Iif; 117 if (name.equals("lower")) 118 return Function.Lower; 119 if (name.equals("upper")) 120 return Function.Upper; 121 if (name.equals("toChars")) 122 return Function.ToChars; 123 if (name.equals("indexOf")) 124 return Function.IndexOf; 125 if (name.equals("substring")) 126 return Function.Substring; 127 if (name.equals("startsWith")) 128 return Function.StartsWith; 129 if (name.equals("endsWith")) 130 return Function.EndsWith; 131 if (name.equals("matches")) 132 return Function.Matches; 133 if (name.equals("matchesFull")) 134 return Function.MatchesFull; 135 if (name.equals("replaceMatches")) 136 return Function.ReplaceMatches; 137 if (name.equals("contains")) 138 return Function.Contains; 139 if (name.equals("replace")) 140 return Function.Replace; 141 if (name.equals("length")) 142 return Function.Length; 143 if (name.equals("children")) 144 return Function.Children; 145 if (name.equals("descendants")) 146 return Function.Descendants; 147 if (name.equals("memberOf")) 148 return Function.MemberOf; 149 if (name.equals("trace")) 150 return Function.Trace; 151 if (name.equals("check")) 152 return Function.Check; 153 if (name.equals("today")) 154 return Function.Today; 155 if (name.equals("now")) 156 return Function.Now; 157 if (name.equals("resolve")) 158 return Function.Resolve; 159 if (name.equals("extension")) 160 return Function.Extension; 161 if (name.equals("allFalse")) 162 return Function.AllFalse; 163 if (name.equals("anyFalse")) 164 return Function.AnyFalse; 165 if (name.equals("allTrue")) 166 return Function.AllTrue; 167 if (name.equals("anyTrue")) 168 return Function.AnyTrue; 169 if (name.equals("hasValue")) 170 return Function.HasValue; 171 if (name.equals("alias")) 172 return Function.Alias; 173 if (name.equals("aliasAs")) 174 return Function.AliasAs; 175 if (name.equals("htmlChecks")) 176 return Function.HtmlChecks1; 177 if (name.equals("htmlchecks")) 178 return Function.HtmlChecks1; // support change of care from R3 179 if (name.equals("htmlChecks2")) 180 return Function.HtmlChecks2; 181 if (name.equals("comparable")) 182 return Function.Comparable; 183 if (name.equals("encode")) 184 return Function.Encode; 185 if (name.equals("decode")) 186 return Function.Decode; 187 if (name.equals("escape")) 188 return Function.Escape; 189 if (name.equals("unescape")) 190 return Function.Unescape; 191 if (name.equals("trim")) 192 return Function.Trim; 193 if (name.equals("split")) 194 return Function.Split; 195 if (name.equals("join")) 196 return Function.Join; 197 if (name.equals("ofType")) 198 return Function.OfType; 199 if (name.equals("type")) 200 return Function.Type; 201 if (name.equals("toInteger")) 202 return Function.ToInteger; 203 if (name.equals("toDecimal")) 204 return Function.ToDecimal; 205 if (name.equals("toString")) 206 return Function.ToString; 207 if (name.equals("toQuantity")) 208 return Function.ToQuantity; 209 if (name.equals("toBoolean")) 210 return Function.ToBoolean; 211 if (name.equals("toDateTime")) 212 return Function.ToDateTime; 213 if (name.equals("toTime")) 214 return Function.ToTime; 215 if (name.equals("convertsToInteger")) 216 return Function.ConvertsToInteger; 217 if (name.equals("convertsToDecimal")) 218 return Function.ConvertsToDecimal; 219 if (name.equals("convertsToString")) 220 return Function.ConvertsToString; 221 if (name.equals("convertsToQuantity")) 222 return Function.ConvertsToQuantity; 223 if (name.equals("convertsToBoolean")) 224 return Function.ConvertsToBoolean; 225 if (name.equals("convertsToDateTime")) 226 return Function.ConvertsToDateTime; 227 if (name.equals("convertsToDate")) 228 return Function.ConvertsToDate; 229 if (name.equals("convertsToTime")) 230 return Function.ConvertsToTime; 231 if (name.equals("conformsTo")) 232 return Function.ConformsTo; 233 if (name.equals("round")) 234 return Function.Round; 235 if (name.equals("sqrt")) 236 return Function.Sqrt; 237 if (name.equals("abs")) 238 return Function.Abs; 239 if (name.equals("ceiling")) 240 return Function.Ceiling; 241 if (name.equals("exp")) 242 return Function.Exp; 243 if (name.equals("floor")) 244 return Function.Floor; 245 if (name.equals("ln")) 246 return Function.Ln; 247 if (name.equals("log")) 248 return Function.Log; 249 if (name.equals("power")) 250 return Function.Power; 251 if (name.equals("truncate")) 252 return Function.Truncate; 253 if (name.equals("lowBoundary")) 254 return Function.LowBoundary; 255 if (name.equals("highBoundary")) 256 return Function.HighBoundary; 257 if (name.equals("precision")) 258 return Function.Precision; 259 260 return null; 261 } 262 263 public String toCode() { 264 switch (this) { 265 case Empty: 266 return "empty"; 267 case Not: 268 return "not"; 269 case Exists: 270 return "exists"; 271 case SubsetOf: 272 return "subsetOf"; 273 case SupersetOf: 274 return "supersetOf"; 275 case IsDistinct: 276 return "isDistinct"; 277 case Distinct: 278 return "distinct"; 279 case Count: 280 return "count"; 281 case Where: 282 return "where"; 283 case Select: 284 return "select"; 285 case All: 286 return "all"; 287 case Repeat: 288 return "repeat"; 289 case Aggregate: 290 return "aggregate"; 291 case Item: 292 return "item"; 293 case As: 294 return "as"; 295 case Is: 296 return "is"; 297 case Single: 298 return "single"; 299 case First: 300 return "first"; 301 case Last: 302 return "last"; 303 case Tail: 304 return "tail"; 305 case Skip: 306 return "skip"; 307 case Take: 308 return "take"; 309 case Union: 310 return "union"; 311 case Combine: 312 return "combine"; 313 case Intersect: 314 return "intersect"; 315 case Exclude: 316 return "exclude"; 317 case Iif: 318 return "iif"; 319 case ToChars: 320 return "toChars"; 321 case Lower: 322 return "lower"; 323 case Upper: 324 return "upper"; 325 case IndexOf: 326 return "indexOf"; 327 case Substring: 328 return "substring"; 329 case StartsWith: 330 return "startsWith"; 331 case EndsWith: 332 return "endsWith"; 333 case Matches: 334 return "matches"; 335 case MatchesFull: 336 return "matchesFull"; 337 case ReplaceMatches: 338 return "replaceMatches"; 339 case Contains: 340 return "contains"; 341 case Replace: 342 return "replace"; 343 case Length: 344 return "length"; 345 case Children: 346 return "children"; 347 case Descendants: 348 return "descendants"; 349 case MemberOf: 350 return "memberOf"; 351 case Trace: 352 return "trace"; 353 case Check: 354 return "check"; 355 case Today: 356 return "today"; 357 case Now: 358 return "now"; 359 case Resolve: 360 return "resolve"; 361 case Extension: 362 return "extension"; 363 case AllFalse: 364 return "allFalse"; 365 case AnyFalse: 366 return "anyFalse"; 367 case AllTrue: 368 return "allTrue"; 369 case AnyTrue: 370 return "anyTrue"; 371 case HasValue: 372 return "hasValue"; 373 case Alias: 374 return "alias"; 375 case AliasAs: 376 return "aliasAs"; 377 case Encode: 378 return "encode"; 379 case Decode: 380 return "decode"; 381 case Escape: 382 return "escape"; 383 case Unescape: 384 return "unescape"; 385 case Trim: 386 return "trim"; 387 case Split: 388 return "split"; 389 case Join: 390 return "join"; 391 case HtmlChecks1: 392 return "htmlChecks"; 393 case HtmlChecks2: 394 return "htmlChecks2"; 395 case Comparable: 396 return "comparable"; 397 case OfType: 398 return "ofType"; 399 case Type: 400 return "type"; 401 case ToInteger: 402 return "toInteger"; 403 case ToDecimal: 404 return "toDecimal"; 405 case ToString: 406 return "toString"; 407 case ToBoolean: 408 return "toBoolean"; 409 case ToQuantity: 410 return "toQuantity"; 411 case ToDateTime: 412 return "toDateTime"; 413 case ToTime: 414 return "toTime"; 415 case ConvertsToInteger: 416 return "convertsToInteger"; 417 case ConvertsToDecimal: 418 return "convertsToDecimal"; 419 case ConvertsToString: 420 return "convertsToString"; 421 case ConvertsToBoolean: 422 return "convertsToBoolean"; 423 case ConvertsToQuantity: 424 return "convertsToQuantity"; 425 case ConvertsToDateTime: 426 return "convertsToDateTime"; 427 case ConvertsToDate: 428 return "convertsToDate"; 429 case ConvertsToTime: 430 return "isTime"; 431 case ConformsTo: 432 return "conformsTo"; 433 case Round: 434 return "round"; 435 case Sqrt: 436 return "sqrt"; 437 case Abs: 438 return "abs"; 439 case Ceiling: 440 return "ceiling"; 441 case Exp: 442 return "exp"; 443 case Floor: 444 return "floor"; 445 case Ln: 446 return "ln"; 447 case Log: 448 return "log"; 449 case Power: 450 return "power"; 451 case Truncate: 452 return "truncate"; 453 case LowBoundary: 454 return "lowBoundary"; 455 case HighBoundary: 456 return "highBoundary"; 457 case Precision: 458 return "precision"; 459 default: 460 return "?custom?"; 461 } 462 } 463 } 464 465 public enum Operation { 466 Equals, Equivalent, NotEquals, NotEquivalent, LessThan, Greater, LessOrEqual, GreaterOrEqual, Is, As, Union, Or, 467 And, Xor, Implies, Times, DivideBy, Plus, Minus, Concatenate, Div, Mod, In, Contains, MemberOf; 468 469 public static Operation fromCode(String name) { 470 if (Utilities.noString(name)) 471 return null; 472 if (name.equals("=")) 473 return Operation.Equals; 474 if (name.equals("~")) 475 return Operation.Equivalent; 476 if (name.equals("!=")) 477 return Operation.NotEquals; 478 if (name.equals("!~")) 479 return Operation.NotEquivalent; 480 if (name.equals(">")) 481 return Operation.Greater; 482 if (name.equals("<")) 483 return Operation.LessThan; 484 if (name.equals(">=")) 485 return Operation.GreaterOrEqual; 486 if (name.equals("<=")) 487 return Operation.LessOrEqual; 488 if (name.equals("|")) 489 return Operation.Union; 490 if (name.equals("or")) 491 return Operation.Or; 492 if (name.equals("and")) 493 return Operation.And; 494 if (name.equals("xor")) 495 return Operation.Xor; 496 if (name.equals("is")) 497 return Operation.Is; 498 if (name.equals("as")) 499 return Operation.As; 500 if (name.equals("*")) 501 return Operation.Times; 502 if (name.equals("/")) 503 return Operation.DivideBy; 504 if (name.equals("+")) 505 return Operation.Plus; 506 if (name.equals("-")) 507 return Operation.Minus; 508 if (name.equals("&")) 509 return Operation.Concatenate; 510 if (name.equals("implies")) 511 return Operation.Implies; 512 if (name.equals("div")) 513 return Operation.Div; 514 if (name.equals("mod")) 515 return Operation.Mod; 516 if (name.equals("in")) 517 return Operation.In; 518 if (name.equals("contains")) 519 return Operation.Contains; 520 if (name.equals("memberOf")) 521 return Operation.MemberOf; 522 return null; 523 524 } 525 526 public String toCode() { 527 switch (this) { 528 case Equals: 529 return "="; 530 case Equivalent: 531 return "~"; 532 case NotEquals: 533 return "!="; 534 case NotEquivalent: 535 return "!~"; 536 case Greater: 537 return ">"; 538 case LessThan: 539 return "<"; 540 case GreaterOrEqual: 541 return ">="; 542 case LessOrEqual: 543 return "<="; 544 case Union: 545 return "|"; 546 case Or: 547 return "or"; 548 case And: 549 return "and"; 550 case Xor: 551 return "xor"; 552 case Times: 553 return "*"; 554 case DivideBy: 555 return "/"; 556 case Plus: 557 return "+"; 558 case Minus: 559 return "-"; 560 case Concatenate: 561 return "&"; 562 case Implies: 563 return "implies"; 564 case Is: 565 return "is"; 566 case As: 567 return "as"; 568 case Div: 569 return "div"; 570 case Mod: 571 return "mod"; 572 case In: 573 return "in"; 574 case Contains: 575 return "contains"; 576 case MemberOf: 577 return "memberOf"; 578 default: 579 return "?custom?"; 580 } 581 } 582 } 583 584 public enum CollectionStatus { 585 SINGLETON, ORDERED, UNORDERED; 586 } 587 588 // the expression will have one of either name or constant 589 private String uniqueId; 590 private Kind kind; 591 private String name; 592 private Base constant; 593 private Function function; 594 private List<ExpressionNode> parameters; // will be created if there is a function 595 private ExpressionNode inner; 596 private ExpressionNode group; 597 private Operation operation; 598 private boolean proximal; // a proximal operation is the first in the sequence of operations. This is 599 // significant when evaluating the outcomes 600 private ExpressionNode opNext; 601 private SourceLocation start; 602 private SourceLocation end; 603 private SourceLocation opStart; 604 private SourceLocation opEnd; 605 private TypeDetails types; 606 private TypeDetails opTypes; 607 608 public ExpressionNode(int uniqueId) { 609 super(); 610 this.uniqueId = Integer.toString(uniqueId); 611 } 612 613 public String toString() { 614 StringBuilder b = new StringBuilder(); 615 switch (kind) { 616 case Name: 617 b.append(name); 618 break; 619 case Function: 620 if (function == Function.Item) 621 b.append("["); 622 else { 623 b.append(name); 624 b.append("("); 625 } 626 boolean first = true; 627 for (ExpressionNode n : parameters) { 628 if (first) 629 first = false; 630 else 631 b.append(", "); 632 b.append(n.toString()); 633 } 634 if (function == Function.Item) { 635 b.append("]"); 636 } else { 637 b.append(")"); 638 } 639 break; 640 case Constant: 641 if (constant == null) { 642 b.append("{}"); 643 } else if (constant instanceof StringType) { 644 b.append("'" + Utilities.escapeJson(constant.primitiveValue()) + "'"); 645 } else if (constant instanceof Quantity) { 646 Quantity q = (Quantity) constant; 647 b.append(Utilities.escapeJson(q.getValue().toPlainString())); 648 b.append(" '"); 649 b.append(Utilities.escapeJson(q.getUnit())); 650 b.append("'"); 651 } else if (constant.primitiveValue() != null) { 652 b.append(Utilities.escapeJson(constant.primitiveValue())); 653 } else { 654 b.append(Utilities.escapeJson(constant.toString())); 655 } 656 break; 657 case Group: 658 b.append("("); 659 b.append(group.toString()); 660 b.append(")"); 661 } 662 if (inner != null) { 663 if (!((ExpressionNode.Kind.Function == inner.getKind()) 664 && (ExpressionNode.Function.Item == inner.getFunction()))) { 665 b.append("."); 666 } 667 b.append(inner.toString()); 668 } 669 if (operation != null) { 670 b.append(" "); 671 b.append(operation.toCode()); 672 b.append(" "); 673 b.append(opNext.toString()); 674 } 675 676 return b.toString(); 677 } 678 679 public String getName() { 680 return name; 681 } 682 683 public void setName(String name) { 684 this.name = name; 685 } 686 687 public Base getConstant() { 688 return constant; 689 } 690 691 public void setConstant(Base constant) { 692 this.constant = constant; 693 } 694 695 public Function getFunction() { 696 return function; 697 } 698 699 public void setFunction(Function function) { 700 this.function = function; 701 if (parameters == null) 702 parameters = new ArrayList<ExpressionNode>(); 703 } 704 705 public boolean isProximal() { 706 return proximal; 707 } 708 709 public void setProximal(boolean proximal) { 710 this.proximal = proximal; 711 } 712 713 public Operation getOperation() { 714 return operation; 715 } 716 717 public void setOperation(Operation operation) { 718 this.operation = operation; 719 } 720 721 public ExpressionNode getInner() { 722 return inner; 723 } 724 725 public void setInner(ExpressionNode value) { 726 this.inner = value; 727 } 728 729 public ExpressionNode getOpNext() { 730 return opNext; 731 } 732 733 public void setOpNext(ExpressionNode value) { 734 this.opNext = value; 735 } 736 737 public List<ExpressionNode> getParameters() { 738 return parameters; 739 } 740 741 public boolean checkName() { 742 if (!name.startsWith("$")) 743 return true; 744 else 745 return Utilities.existsInList(name, "$this", "$total", "$index"); 746 } 747 748 public Kind getKind() { 749 return kind; 750 } 751 752 public void setKind(Kind kind) { 753 this.kind = kind; 754 } 755 756 public ExpressionNode getGroup() { 757 return group; 758 } 759 760 public void setGroup(ExpressionNode group) { 761 this.group = group; 762 } 763 764 public SourceLocation getStart() { 765 return start; 766 } 767 768 public void setStart(SourceLocation start) { 769 this.start = start; 770 } 771 772 public SourceLocation getEnd() { 773 return end; 774 } 775 776 public void setEnd(SourceLocation end) { 777 this.end = end; 778 } 779 780 public SourceLocation getOpStart() { 781 return opStart; 782 } 783 784 public void setOpStart(SourceLocation opStart) { 785 this.opStart = opStart; 786 } 787 788 public SourceLocation getOpEnd() { 789 return opEnd; 790 } 791 792 public void setOpEnd(SourceLocation opEnd) { 793 this.opEnd = opEnd; 794 } 795 796 public String getUniqueId() { 797 return uniqueId; 798 } 799 800 public int parameterCount() { 801 if (parameters == null) 802 return 0; 803 else 804 return parameters.size(); 805 } 806 807 public String Canonical() { 808 StringBuilder b = new StringBuilder(); 809 write(b); 810 return b.toString(); 811 } 812 813 public String summary() { 814 switch (kind) { 815 case Name: 816 return uniqueId + ": " + name; 817 case Function: 818 return uniqueId + ": " + function.toString() + "()"; 819 case Constant: 820 return uniqueId + ": " + constant; 821 case Group: 822 return uniqueId + ": (Group)"; 823 } 824 return "?exp-kind?"; 825 } 826 827 private void write(StringBuilder b) { 828 829 switch (kind) { 830 case Name: 831 b.append(name); 832 break; 833 case Constant: 834 b.append(constant); 835 break; 836 case Function: 837 b.append(function.toCode()); 838 b.append('('); 839 boolean f = true; 840 for (ExpressionNode n : parameters) { 841 if (f) 842 f = false; 843 else 844 b.append(", "); 845 n.write(b); 846 } 847 b.append(')'); 848 849 break; 850 case Group: 851 b.append('('); 852 group.write(b); 853 b.append(')'); 854 } 855 856 if (inner != null) { 857 b.append('.'); 858 inner.write(b); 859 } 860 if (operation != null) { 861 b.append(' '); 862 b.append(operation.toCode()); 863 b.append(' '); 864 opNext.write(b); 865 } 866 } 867 868 public String check() { 869 870 if (kind == null) { 871 return "Error in expression - node has no kind"; 872 } 873 switch (kind) { 874 case Name: 875 if (Utilities.noString(name)) 876 return "No Name provided @ " + location(); 877 break; 878 879 case Function: 880 if (function == null) 881 return "No Function id provided @ " + location(); 882 for (ExpressionNode n : parameters) { 883 String msg = n.check(); 884 if (msg != null) 885 return msg; 886 } 887 888 break; 889 890 case Unary: 891 break; 892 case Constant: 893 if (constant == null) 894 return "No Constant provided @ " + location(); 895 break; 896 897 case Group: 898 if (group == null) 899 return "No Group provided @ " + location(); 900 else { 901 String msg = group.check(); 902 if (msg != null) 903 return msg; 904 } 905 } 906 if (inner != null) { 907 String msg = inner.check(); 908 if (msg != null) 909 return msg; 910 } 911 if (operation == null) { 912 913 if (opNext != null) 914 return "Next provided when it shouldn't be @ " + location(); 915 } else { 916 if (opNext == null) 917 return "No Next provided @ " + location(); 918 else 919 opNext.check(); 920 } 921 return null; 922 923 } 924 925 private String location() { 926 return Integer.toString(start.getLine()) + ", " + Integer.toString(start.getColumn()); 927 } 928 929 public TypeDetails getTypes() { 930 return types; 931 } 932 933 public void setTypes(TypeDetails types) { 934 this.types = types; 935 } 936 937 public TypeDetails getOpTypes() { 938 return opTypes; 939 } 940 941 public void setOpTypes(TypeDetails opTypes) { 942 this.opTypes = opTypes; 943 } 944 945}