1 // © 2022 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 4 package com.ibm.icu.message2; 5 6 import java.util.ArrayList; 7 import java.util.Collection; 8 import java.util.Collections; 9 import java.util.LinkedHashMap; 10 import java.util.List; 11 import java.util.Map; 12 import java.util.Map.Entry; 13 import java.util.StringJoiner; 14 15 /** 16 * This maps closely to the official specification. 17 * Since it is not final, we will not add javadoc everywhere. 18 * 19 * <p>See <a target="github" href="https://github.com/unicode-org/message-format-wg/blob/main/spec/syntax.md">the 20 * description of the syntax with examples and use cases</a> and the corresponding 21 * <a target="github" href="https://github.com/unicode-org/message-format-wg/blob/main/spec/message.ebnf">EBNF</a>.</p> 22 * 23 * @internal ICU 72 technology preview 24 * @deprecated This API is for technology preview only. 25 */ 26 @Deprecated 27 @SuppressWarnings("javadoc") 28 public class Mf2DataModel { 29 30 /** 31 * @internal ICU 72 technology preview 32 * @deprecated This API is for technology preview only. 33 */ 34 @Deprecated 35 public static class SelectorKeys { 36 private final List<String> keys; 37 SelectorKeys(Builder builder)38 private SelectorKeys(Builder builder) { 39 keys = new ArrayList<>(); 40 keys.addAll(builder.keys); 41 } 42 43 /** 44 * Creates a builder. 45 * 46 * @return the Builder. 47 * 48 * @internal ICU 72 technology preview 49 * @deprecated This API is for technology preview only. 50 */ 51 @Deprecated builder()52 public static Builder builder() { 53 return new Builder(); 54 } 55 56 /** 57 * @internal ICU 72 technology preview 58 * @deprecated This API is for technology preview only. 59 */ 60 @Deprecated getKeys()61 public List<String> getKeys() { 62 return Collections.unmodifiableList(keys); 63 } 64 65 /** 66 * @internal ICU 72 technology preview 67 * @deprecated This API is for technology preview only. 68 */ 69 @Deprecated 70 @Override toString()71 public String toString() { 72 StringJoiner result = new StringJoiner(" "); 73 for (String key : keys) { 74 result.add(key); 75 } 76 return result.toString(); 77 } 78 79 /** 80 * @internal ICU 72 technology preview 81 * @deprecated This API is for technology preview only. 82 */ 83 @Deprecated 84 public static class Builder { 85 private final List<String> keys = new ArrayList<>(); 86 87 // Prevent direct creation Builder()88 private Builder() { 89 } 90 91 /** 92 * @internal ICU 72 technology preview 93 * @deprecated This API is for technology preview only. 94 */ 95 @Deprecated add(String key)96 public Builder add(String key) { 97 keys.add(key); 98 return this; 99 } 100 101 /** 102 * @internal ICU 72 technology preview 103 * @deprecated This API is for technology preview only. 104 */ 105 @Deprecated addAll(Collection<String> otherKeys)106 public Builder addAll(Collection<String> otherKeys) { 107 this.keys.addAll(otherKeys); 108 return this; 109 } 110 111 /** 112 * @internal ICU 72 technology preview 113 * @deprecated This API is for technology preview only. 114 */ 115 @Deprecated build()116 public SelectorKeys build() { 117 return new SelectorKeys(this); 118 } 119 } 120 } 121 122 /** 123 * @internal ICU 72 technology preview 124 * @deprecated This API is for technology preview only. 125 */ 126 @Deprecated 127 public static class Pattern { 128 private final List<Part> parts; 129 Pattern(Builder builder)130 private Pattern(Builder builder) { 131 parts = new ArrayList<>(); 132 parts.addAll(builder.parts); 133 } 134 135 /** 136 * Creates a builder. 137 * 138 * @return the Builder. 139 * 140 * @internal ICU 72 technology preview 141 * @deprecated This API is for technology preview only. 142 */ 143 @Deprecated builder()144 public static Builder builder() { 145 return new Builder(); 146 } 147 148 /** 149 * @internal ICU 72 technology preview 150 * @deprecated This API is for technology preview only. 151 */ 152 @Deprecated getParts()153 public List<Part> getParts() { 154 return parts; 155 } 156 157 /** 158 * @internal ICU 72 technology preview 159 * @deprecated This API is for technology preview only. 160 */ 161 @Deprecated 162 @Override toString()163 public String toString() { 164 StringBuilder result = new StringBuilder(); 165 result.append("{"); 166 for (Part part : parts) { 167 result.append(part); 168 } 169 result.append("}"); 170 return result.toString(); 171 } 172 173 /** 174 * @internal ICU 72 technology preview 175 * @deprecated This API is for technology preview only. 176 */ 177 @Deprecated 178 public static class Builder { 179 private final List<Part> parts = new ArrayList<>(); 180 181 // Prevent direct creation Builder()182 private Builder() { 183 } 184 185 /** 186 * @internal ICU 72 technology preview 187 * @deprecated This API is for technology preview only. 188 */ 189 @Deprecated add(Part part)190 public Builder add(Part part) { 191 parts.add(part); 192 return this; 193 } 194 195 /** 196 * @internal ICU 72 technology preview 197 * @deprecated This API is for technology preview only. 198 */ 199 @Deprecated addAll(Collection<Part> otherParts)200 public Builder addAll(Collection<Part> otherParts) { 201 parts.addAll(otherParts); 202 return this; 203 } 204 205 /** 206 * @internal ICU 72 technology preview 207 * @deprecated This API is for technology preview only. 208 */ 209 @Deprecated build()210 public Pattern build() { 211 return new Pattern(this); 212 } 213 214 } 215 } 216 217 /** 218 * No functional role, this is only to be able to say that a message is a sequence of Part(s), 219 * and that plain text {@link Text} and {@link Expression} are Part(s). 220 * 221 * @internal ICU 72 technology preview 222 * @deprecated This API is for technology preview only. 223 */ 224 @Deprecated 225 public interface Part { 226 } 227 228 /** 229 * @internal ICU 72 technology preview 230 * @deprecated This API is for technology preview only. 231 */ 232 @Deprecated 233 public static class Text implements Part { 234 private final String value; 235 236 /** 237 * @internal ICU 72 technology preview 238 * @deprecated This API is for technology preview only. 239 */ 240 @Deprecated Text(Builder builder)241 private Text(Builder builder) { 242 this(builder.value); 243 } 244 245 /** 246 * Creates a builder. 247 * 248 * @return the Builder. 249 * 250 * @internal ICU 72 technology preview 251 * @deprecated This API is for technology preview only. 252 */ 253 @Deprecated builder()254 public static Builder builder() { 255 return new Builder(); 256 } 257 258 /** 259 * @internal ICU 72 technology preview 260 * @deprecated This API is for technology preview only. 261 */ 262 @Deprecated Text(String value)263 public Text(String value) { 264 this.value = value; 265 } 266 267 /** 268 * @internal ICU 72 technology preview 269 * @deprecated This API is for technology preview only. 270 */ 271 @Deprecated getValue()272 public String getValue() { 273 return value; 274 } 275 276 /** 277 * @internal ICU 72 technology preview 278 * @deprecated This API is for technology preview only. 279 */ 280 @Deprecated 281 @Override toString()282 public String toString() { 283 return value; 284 } 285 286 /** 287 * @internal ICU 72 technology preview 288 * @deprecated This API is for technology preview only. 289 */ 290 @Deprecated 291 public static class Builder { 292 private String value; 293 294 // Prevent direct creation Builder()295 private Builder() { 296 } 297 298 /** 299 * @internal ICU 72 technology preview 300 * @deprecated This API is for technology preview only. 301 */ 302 @Deprecated setValue(String value)303 public Builder setValue(String value) { 304 this.value = value; 305 return this; 306 } 307 308 /** 309 * @internal ICU 72 technology preview 310 * @deprecated This API is for technology preview only. 311 */ 312 @Deprecated build()313 public Text build() { 314 return new Text(this); 315 } 316 } 317 } 318 319 /** 320 * @internal ICU 72 technology preview 321 * @deprecated This API is for technology preview only. 322 */ 323 @Deprecated 324 public static class Expression implements Part { 325 private final Value operand; // Literal | Variable 326 private final String functionName; 327 private final Map<String, Value> options; 328 Formatter formatter = null; 329 Expression(Builder builder)330 private Expression(Builder builder) { 331 this.operand = builder.operand; 332 this.functionName = builder.functionName; 333 this.options = builder.options; 334 } 335 336 /** 337 * Creates a builder. 338 * 339 * @return the Builder. 340 * 341 * @internal ICU 72 technology preview 342 * @deprecated This API is for technology preview only. 343 */ 344 @Deprecated builder()345 public static Builder builder() { 346 return new Builder(); 347 } 348 349 /** 350 * @internal ICU 72 technology preview 351 * @deprecated This API is for technology preview only. 352 */ 353 @Deprecated getOperand()354 public Value getOperand() { 355 return operand; 356 } 357 358 /** 359 * @internal ICU 72 technology preview 360 * @deprecated This API is for technology preview only. 361 */ 362 @Deprecated getFunctionName()363 public String getFunctionName() { 364 return functionName; 365 } 366 367 /** 368 * @internal ICU 72 technology preview 369 * @deprecated This API is for technology preview only. 370 */ 371 @Deprecated getOptions()372 public Map<String, Value> getOptions() { 373 return options; 374 } 375 376 /** 377 * @internal ICU 72 technology preview 378 * @deprecated This API is for technology preview only. 379 */ 380 @Deprecated 381 @Override toString()382 public String toString() { 383 StringBuilder result = new StringBuilder(); 384 result.append("{"); 385 if (operand != null) { 386 result.append(operand); 387 } 388 if (functionName != null) { 389 result.append(" :").append(functionName); 390 } 391 for (Entry<String, Value> option : options.entrySet()) { 392 result.append(" ").append(option.getKey()).append("=").append(option.getValue()); 393 } 394 result.append("}"); 395 return result.toString(); 396 } 397 398 /** 399 * @internal ICU 72 technology preview 400 * @deprecated This API is for technology preview only. 401 */ 402 @Deprecated 403 public static class Builder { 404 private Value operand = null; 405 private String functionName = null; 406 private final OrderedMap<String, Value> options = new OrderedMap<>(); 407 408 // Prevent direct creation Builder()409 private Builder() { 410 } 411 412 /** 413 * @internal ICU 72 technology preview 414 * @deprecated This API is for technology preview only. 415 */ 416 @Deprecated setOperand(Value operand)417 public Builder setOperand(Value operand) { 418 this.operand = operand; 419 return this; 420 } 421 422 /** 423 * @internal ICU 72 technology preview 424 * @deprecated This API is for technology preview only. 425 */ 426 @Deprecated setFunctionName(String functionName)427 public Builder setFunctionName(String functionName) { 428 this.functionName = functionName; 429 return this; 430 } 431 432 /** 433 * @internal ICU 72 technology preview 434 * @deprecated This API is for technology preview only. 435 */ 436 @Deprecated addOption(String key, Value value)437 public Builder addOption(String key, Value value) { 438 options.put(key, value); 439 return this; 440 } 441 442 /** 443 * @internal ICU 72 technology preview 444 * @deprecated This API is for technology preview only. 445 */ 446 @Deprecated addOptions(Map<String, Value> otherOptions)447 public Builder addOptions(Map<String, Value> otherOptions) { 448 options.putAll(otherOptions); 449 return this; 450 } 451 452 /** 453 * @internal ICU 72 technology preview 454 * @deprecated This API is for technology preview only. 455 */ 456 @Deprecated build()457 public Expression build() { 458 return new Expression(this); 459 } 460 } 461 } 462 463 // public static class Placeholder extends Expression implements Part { 464 // public Placeholder(Builder builder) { 465 // super(builder); 466 // } 467 // } 468 469 /** 470 * A Value can be either a Literal, or a Variable, but not both. 471 * 472 * @internal ICU 72 technology preview 473 * @deprecated This API is for technology preview only. 474 */ 475 @Deprecated 476 public static class Value { 477 private final String literal; 478 private final String variableName; 479 Value(Builder builder)480 private Value(Builder builder) { 481 this.literal = builder.literal; 482 this.variableName = builder.variableName; 483 // this(builder.literal, builder.variableName); 484 } 485 486 /** 487 * Creates a builder. 488 * 489 * @return the Builder. 490 * 491 * @internal ICU 72 technology preview 492 * @deprecated This API is for technology preview only. 493 */ 494 @Deprecated builder()495 public static Builder builder() { 496 return new Builder(); 497 } 498 499 /** 500 * @internal ICU 72 technology preview 501 * @deprecated This API is for technology preview only. 502 */ 503 @Deprecated getLiteral()504 public String getLiteral() { 505 return literal; 506 } 507 508 /** 509 * @internal ICU 72 technology preview 510 * @deprecated This API is for technology preview only. 511 */ 512 @Deprecated getVariableName()513 public String getVariableName() { 514 return variableName; 515 } 516 517 /** 518 * @internal ICU 72 technology preview 519 * @deprecated This API is for technology preview only. 520 */ 521 @Deprecated isLiteral()522 public boolean isLiteral() { 523 return literal != null; 524 } 525 526 /** 527 * @internal ICU 72 technology preview 528 * @deprecated This API is for technology preview only. 529 */ 530 @Deprecated isVariable()531 public boolean isVariable() { 532 return variableName != null; 533 } 534 535 /** 536 * @internal ICU 72 technology preview 537 * @deprecated This API is for technology preview only. 538 */ 539 @Deprecated 540 @Override toString()541 public String toString() { 542 return isLiteral() ? "(" + literal + ")" : "$" + variableName; 543 } 544 545 /** 546 * @internal ICU 72 technology preview 547 * @deprecated This API is for technology preview only. 548 */ 549 @Deprecated 550 public static class Builder { 551 private String literal; 552 private String variableName; 553 554 // Prevent direct creation Builder()555 private Builder() { 556 } 557 558 /** 559 * @internal ICU 72 technology preview 560 * @deprecated This API is for technology preview only. 561 */ 562 @Deprecated setLiteral(String literal)563 public Builder setLiteral(String literal) { 564 this.literal = literal; 565 this.variableName = null; 566 return this; 567 } 568 569 /** 570 * @internal ICU 72 technology preview 571 * @deprecated This API is for technology preview only. 572 */ 573 @Deprecated setVariableName(String variableName)574 public Builder setVariableName(String variableName) { 575 this.variableName = variableName; 576 this.literal = null; 577 return this; 578 } 579 580 /** 581 * @internal ICU 72 technology preview 582 * @deprecated This API is for technology preview only. 583 */ 584 @Deprecated build()585 public Value build() { 586 return new Value(this); 587 } 588 } 589 } 590 591 /** 592 * @internal ICU 72 technology preview 593 * @deprecated This API is for technology preview only. 594 */ 595 @Deprecated 596 public static class Variable { 597 private final String name; 598 Variable(Builder builder)599 private Variable(Builder builder) { 600 this.name = builder.name; 601 } 602 603 /** 604 * Creates a builder. 605 * 606 * @return the Builder. 607 * 608 * @internal ICU 72 technology preview 609 * @deprecated This API is for technology preview only. 610 */ 611 @Deprecated builder()612 public static Builder builder() { 613 return new Builder(); 614 } 615 616 /** 617 * @internal ICU 72 technology preview 618 * @deprecated This API is for technology preview only. 619 */ 620 @Deprecated getName()621 public String getName() { 622 return name; 623 } 624 625 /** 626 * @internal ICU 72 technology preview 627 * @deprecated This API is for technology preview only. 628 */ 629 @Deprecated 630 public static class Builder { 631 private String name; 632 633 // Prevent direct creation Builder()634 private Builder() { 635 } 636 637 /** 638 * @internal ICU 72 technology preview 639 * @deprecated This API is for technology preview only. 640 */ 641 @Deprecated setName(String name)642 public Builder setName(String name) { 643 this.name = name; 644 return this; 645 } 646 647 /** 648 * @internal ICU 72 technology preview 649 * @deprecated This API is for technology preview only. 650 */ 651 @Deprecated build()652 public Variable build() { 653 return new Variable(this); 654 } 655 } 656 } 657 658 /** 659 * This is only to not force LinkedHashMap on the public API. 660 * 661 * @internal ICU 72 technology preview 662 * @deprecated This API is for technology preview only. 663 */ 664 @Deprecated 665 public static class OrderedMap<K, V> extends LinkedHashMap<K, V> { 666 private static final long serialVersionUID = -7049361727790825496L; 667 668 /** 669 * {@inheritDoc} 670 * 671 * @internal ICU 72 technology preview 672 * @deprecated This API is for technology preview only. 673 */ 674 @Deprecated OrderedMap()675 public OrderedMap() { 676 super(); 677 } 678 } 679 680 private final OrderedMap<String, Expression> localVariables; 681 private final List<Expression> selectors; 682 private final OrderedMap<SelectorKeys, Pattern> variants; 683 private final Pattern pattern; 684 Mf2DataModel(Builder builder)685 private Mf2DataModel(Builder builder) { 686 this.localVariables = builder.localVariables; 687 this.selectors = builder.selectors; 688 this.variants = builder.variants; 689 this.pattern = builder.pattern; 690 } 691 692 /** 693 * Creates a builder. 694 * 695 * @return the Builder. 696 * 697 * @internal ICU 72 technology preview 698 * @deprecated This API is for technology preview only. 699 */ 700 @Deprecated builder()701 public static Builder builder() { 702 return new Builder(); 703 } 704 705 /** 706 * @internal ICU 72 technology preview 707 * @deprecated This API is for technology preview only. 708 */ 709 @Deprecated getLocalVariables()710 public OrderedMap<String, Expression> getLocalVariables() { 711 return localVariables; 712 } 713 714 /** 715 * @internal ICU 72 technology preview 716 * @deprecated This API is for technology preview only. 717 */ 718 @Deprecated getSelectors()719 public List<Expression> getSelectors() { 720 return selectors; 721 } 722 723 /** 724 * @internal ICU 72 technology preview 725 * @deprecated This API is for technology preview only. 726 */ 727 @Deprecated getVariants()728 public OrderedMap<SelectorKeys, Pattern> getVariants() { 729 return variants; 730 } 731 732 /** 733 * @internal ICU 72 technology preview 734 * @deprecated This API is for technology preview only. 735 */ 736 @Deprecated getPattern()737 public Pattern getPattern() { 738 return pattern; 739 } 740 741 /** 742 * @internal ICU 72 technology preview 743 * @deprecated This API is for technology preview only. 744 */ 745 @Deprecated 746 @Override toString()747 public String toString() { 748 StringBuilder result = new StringBuilder(); 749 for (Entry<String, Expression> lv : localVariables.entrySet()) { 750 result.append("let $").append(lv.getKey()); 751 result.append(" = "); 752 result.append(lv.getValue()); 753 result.append("\n"); 754 } 755 if (!selectors.isEmpty()) { 756 result.append("match"); 757 for (Expression e : this.selectors) { 758 result.append(" ").append(e); 759 } 760 result.append("\n"); 761 for (Entry<SelectorKeys, Pattern> variant : variants.entrySet()) { 762 result.append(" when ").append(variant.getKey()); 763 result.append(" "); 764 result.append(variant.getValue()); 765 result.append("\n"); 766 } 767 } else { 768 result.append(pattern); 769 } 770 return result.toString(); 771 } 772 773 /** 774 * @internal ICU 72 technology preview 775 * @deprecated This API is for technology preview only. 776 */ 777 @Deprecated 778 public static class Builder { 779 private final OrderedMap<String, Expression> localVariables = new OrderedMap<>(); // declaration* 780 private final List<Expression> selectors = new ArrayList<>(); 781 private final OrderedMap<SelectorKeys, Pattern> variants = new OrderedMap<>(); 782 private Pattern pattern = Pattern.builder().build(); 783 784 // Prevent direct creation Builder()785 private Builder() { 786 } 787 788 /** 789 * @internal ICU 72 technology preview 790 * @deprecated This API is for technology preview only. 791 */ 792 @Deprecated addLocalVariable(String variableName, Expression expression)793 public Builder addLocalVariable(String variableName, Expression expression) { 794 this.localVariables.put(variableName, expression); 795 return this; 796 } 797 798 /** 799 * @internal ICU 72 technology preview 800 * @deprecated This API is for technology preview only. 801 */ 802 @Deprecated addLocalVariables(OrderedMap<String, Expression> otherLocalVariables)803 public Builder addLocalVariables(OrderedMap<String, Expression> otherLocalVariables) { 804 this.localVariables.putAll(otherLocalVariables); 805 return this; 806 } 807 808 /** 809 * @internal ICU 72 technology preview 810 * @deprecated This API is for technology preview only. 811 */ 812 @Deprecated addSelector(Expression otherSelector)813 public Builder addSelector(Expression otherSelector) { 814 this.selectors.add(otherSelector); 815 return this; 816 } 817 818 /** 819 * @internal ICU 72 technology preview 820 * @deprecated This API is for technology preview only. 821 */ 822 @Deprecated addSelectors(List<Expression> otherSelectors)823 public Builder addSelectors(List<Expression> otherSelectors) { 824 this.selectors.addAll(otherSelectors); 825 return this; 826 } 827 828 /** 829 * @internal ICU 72 technology preview 830 * @deprecated This API is for technology preview only. 831 */ 832 @Deprecated addVariant(SelectorKeys keys, Pattern newPattern)833 public Builder addVariant(SelectorKeys keys, Pattern newPattern) { 834 this.variants.put(keys, newPattern); 835 return this; 836 } 837 838 /** 839 * @internal ICU 72 technology preview 840 * @deprecated This API is for technology preview only. 841 */ 842 @Deprecated addVariants(OrderedMap<SelectorKeys, Pattern> otherVariants)843 public Builder addVariants(OrderedMap<SelectorKeys, Pattern> otherVariants) { 844 this.variants.putAll(otherVariants); 845 return this; 846 } 847 848 /** 849 * @internal ICU 72 technology preview 850 * @deprecated This API is for technology preview only. 851 */ 852 @Deprecated setPattern(Pattern pattern)853 public Builder setPattern(Pattern pattern) { 854 this.pattern = pattern; 855 return this; 856 } 857 858 /** 859 * @internal ICU 72 technology preview 860 * @deprecated This API is for technology preview only. 861 */ 862 @Deprecated build()863 public Mf2DataModel build() { 864 return new Mf2DataModel(this); 865 } 866 } 867 } 868