Operators.java revision 2957:098657cc98c9
1/* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.tools.javac.comp; 27 28import com.sun.tools.javac.code.Symbol; 29import com.sun.tools.javac.code.Symbol.OperatorSymbol; 30import com.sun.tools.javac.code.Symtab; 31import com.sun.tools.javac.code.Type; 32import com.sun.tools.javac.code.Type.MethodType; 33import com.sun.tools.javac.code.TypeTag; 34import com.sun.tools.javac.code.Types; 35import com.sun.tools.javac.jvm.ByteCodes; 36import com.sun.tools.javac.resources.CompilerProperties.Errors; 37import com.sun.tools.javac.tree.JCTree; 38import com.sun.tools.javac.tree.JCTree.Tag; 39import com.sun.tools.javac.util.Assert; 40import com.sun.tools.javac.util.Context; 41import com.sun.tools.javac.util.JCDiagnostic; 42import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 43import com.sun.tools.javac.util.List; 44import com.sun.tools.javac.util.Log; 45import com.sun.tools.javac.util.Name; 46import com.sun.tools.javac.util.Names; 47 48import java.util.HashMap; 49import java.util.Map; 50import java.util.Optional; 51import java.util.function.BiPredicate; 52import java.util.function.Function; 53import java.util.function.Predicate; 54import java.util.function.Supplier; 55import java.util.stream.Stream; 56 57import static com.sun.tools.javac.jvm.ByteCodes.*; 58import static com.sun.tools.javac.comp.Operators.OperatorType.*; 59 60/** 61 * This class contains the logic for unary and binary operator resolution/lookup. 62 * 63 * <p><b>This is NOT part of any supported API. 64 * If you write code that depends on this, you do so at your own risk. 65 * This code and its internal interfaces are subject to change or 66 * deletion without notice.</b> 67 */ 68public class Operators { 69 protected static final Context.Key<Operators> operatorsKey = new Context.Key<>(); 70 71 private final Names names; 72 private final Log log; 73 private final Symtab syms; 74 private final Types types; 75 76 /** Unary operators map. */ 77 private Map<Name, List<UnaryOperatorHelper>> unaryOperators = new HashMap<>(Tag.getNumberOfOperators()); 78 79 /** Binary operators map. */ 80 private Map<Name, List<BinaryOperatorHelper>> binaryOperators = new HashMap<>(Tag.getNumberOfOperators()); 81 82 /** The names of all operators. */ 83 private Name[] opname = new Name[Tag.getNumberOfOperators()]; 84 85 public static Operators instance(Context context) { 86 Operators instance = context.get(operatorsKey); 87 if (instance == null) 88 instance = new Operators(context); 89 return instance; 90 } 91 92 protected Operators(Context context) { 93 context.put(operatorsKey, this); 94 syms = Symtab.instance(context); 95 names = Names.instance(context); 96 log = Log.instance(context); 97 types = Types.instance(context); 98 initOperatorNames(); 99 initUnaryOperators(); 100 initBinaryOperators(); 101 } 102 103 /** 104 * Perform unary promotion of a type; this routine implements JLS 5.6.1. 105 * If the input type is not supported by unary promotion, it is returned unaltered. 106 */ 107 Type unaryPromotion(Type t) { 108 Type unboxed = types.unboxedTypeOrType(t); 109 switch (unboxed.getTag()) { 110 case BYTE: 111 case SHORT: 112 case CHAR: 113 return syms.intType; 114 default: 115 return unboxed; 116 } 117 } 118 119 /** 120 * Perform binary promotion of a pair of types; this routine implements JLS 5.6.2. 121 * If the input types are not supported by unary promotion, if such types are identical to 122 * a type C, then C is returned, otherwise Object is returned. 123 */ 124 Type binaryPromotion(Type t1, Type t2) { 125 Type unboxedT1 = types.unboxedTypeOrType(t1); 126 Type unboxedT2 = types.unboxedTypeOrType(t2); 127 128 if (unboxedT1.isNumeric() && unboxedT2.isNumeric()) { 129 if (unboxedT1.hasTag(TypeTag.DOUBLE) || unboxedT2.hasTag(TypeTag.DOUBLE)) { 130 return syms.doubleType; 131 } else if (unboxedT1.hasTag(TypeTag.FLOAT) || unboxedT2.hasTag(TypeTag.FLOAT)) { 132 return syms.floatType; 133 } else if (unboxedT1.hasTag(TypeTag.LONG) || unboxedT2.hasTag(TypeTag.LONG)) { 134 return syms.longType; 135 } else { 136 return syms.intType; 137 } 138 } else if (types.isSameType(unboxedT1, unboxedT2)) { 139 return unboxedT1; 140 } else { 141 return syms.objectType; 142 } 143 } 144 145 /** 146 * Entry point for resolving a unary operator given an operator tag and an argument type. 147 */ 148 Symbol resolveUnary(DiagnosticPosition pos, JCTree.Tag tag, Type op) { 149 return resolve(tag, 150 unaryOperators, 151 unop -> unop.test(op), 152 unop -> unop.resolve(op), 153 () -> reportErrorIfNeeded(pos, tag, op)); 154 } 155 156 /** 157 * Entry point for resolving a binary operator given an operator tag and a pair of argument types. 158 */ 159 Symbol resolveBinary(DiagnosticPosition pos, JCTree.Tag tag, Type op1, Type op2) { 160 return resolve(tag, 161 binaryOperators, 162 binop -> binop.test(op1, op2), 163 binop -> binop.resolve(op1, op2), 164 () -> reportErrorIfNeeded(pos, tag, op1, op2)); 165 } 166 167 /** 168 * Main operator lookup routine; lookup an operator (either unary or binary) in its corresponding 169 * map. If there's a matching operator, its resolve routine is called and the result is returned; 170 * otherwise the result of a fallback function is returned. 171 */ 172 private <O> Symbol resolve(Tag tag, Map<Name, List<O>> opMap, Predicate<O> opTestFunc, 173 Function<O, Symbol> resolveFunc, Supplier<Symbol> noResultFunc) { 174 return opMap.get(operatorName(tag)).stream() 175 .filter(opTestFunc) 176 .map(resolveFunc) 177 .findFirst() 178 .orElseGet(noResultFunc); 179 } 180 181 /** 182 * Creates an operator symbol. 183 */ 184 private Symbol makeOperator(Name name, List<OperatorType> formals, OperatorType res, int... opcodes) { 185 MethodType opType = new MethodType( 186 formals.stream() 187 .map(o -> o.asType(syms)) 188 .collect(List.collector()), 189 res.asType(syms), List.nil(), syms.methodClass); 190 return new OperatorSymbol(name, opType, mergeOpcodes(opcodes), syms.noSymbol); 191 } 192 193 /** 194 * Fold two opcodes in a single int value (if required). 195 */ 196 private int mergeOpcodes(int... opcodes) { 197 int opcodesLen = opcodes.length; 198 Assert.check(opcodesLen == 1 || opcodesLen == 2); 199 return (opcodesLen == 1) ? 200 opcodes[0] : 201 ((opcodes[0] << ByteCodes.preShift) | opcodes[1]); 202 } 203 204 /** 205 * Report an operator lookup error. 206 */ 207 private Symbol reportErrorIfNeeded(DiagnosticPosition pos, Tag tag, Type... args) { 208 if (Stream.of(args).noneMatch(Type::isErroneous)) { 209 Name opName = operatorName(tag); 210 JCDiagnostic.Error opError = (args.length) == 1 ? 211 Errors.OperatorCantBeApplied(opName, args[0]) : 212 Errors.OperatorCantBeApplied1(opName, args[0], args[1]); 213 log.error(pos, opError); 214 } 215 return syms.noSymbol; 216 } 217 218 /** 219 * Return name of operator with given tree tag. 220 */ 221 public Name operatorName(JCTree.Tag tag) { 222 return opname[tag.operatorIndex()]; 223 } 224 225 /** 226 * The constants in this enum represent the types upon which all the operator helpers 227 * operate upon. This allows lazy and consise mapping between a type name and a type instance. 228 */ 229 enum OperatorType { 230 BYTE(syms -> syms.byteType), 231 SHORT(syms -> syms.shortType), 232 INT(syms -> syms.intType), 233 LONG(syms -> syms.longType), 234 FLOAT(syms -> syms.floatType), 235 DOUBLE(syms -> syms.doubleType), 236 CHAR(syms -> syms.charType), 237 BOOLEAN(syms -> syms.booleanType), 238 OBJECT(syms -> syms.objectType), 239 STRING(syms -> syms.stringType), 240 BOT(syms -> syms.botType); 241 242 final Function<Symtab, Type> asTypeFunc; 243 244 OperatorType(Function<Symtab, Type> asTypeFunc) { 245 this.asTypeFunc = asTypeFunc; 246 } 247 248 Type asType(Symtab syms) { 249 return asTypeFunc.apply(syms); 250 } 251 } 252 253 /** 254 * Common root for all operator helpers. An operator helper instance is associated with a 255 * given operator (i.e. '+'); it contains routines to perform operator lookup, i.e. find 256 * which version of the '+' operator is the best given an argument type list. Supported 257 * operator symbols are initialized lazily upon first lookup request - this is in order to avoid 258 * initialization circularities between this class and {@code Symtab}. 259 */ 260 abstract class OperatorHelper { 261 262 /** The operator name. */ 263 final Name name; 264 265 /** The list of symbols associated with this operator (lazily populated). */ 266 Optional<Symbol[]> alternatives = Optional.empty(); 267 268 /** An array of operator symbol suppliers (used to lazily populate the symbol list). */ 269 List<Supplier<Symbol>> operatorSuppliers = List.nil(); 270 271 @SuppressWarnings("varargs") 272 OperatorHelper(Tag tag) { 273 this.name = operatorName(tag); 274 } 275 276 /** 277 * This routine implements the main operator lookup process. Each operator is tested 278 * using an applicability predicate; if the test suceeds that same operator is returned, 279 * otherwise a dummy symbol is returned. 280 */ 281 final Symbol doLookup(Predicate<Symbol> applicabilityTest) { 282 return Stream.of(alternatives.orElseGet(this::initOperators)) 283 .filter(applicabilityTest) 284 .findFirst() 285 .orElse(syms.noSymbol); 286 } 287 288 /** 289 * This routine performs lazy instantiation of the operator symbols supported by this helper. 290 * After initialization is done, the suppliers are cleared, to free up memory. 291 */ 292 private Symbol[] initOperators() { 293 Symbol[] operators = operatorSuppliers.stream() 294 .map(op -> op.get()) 295 .toArray(Symbol[]::new); 296 alternatives = Optional.of(operators); 297 operatorSuppliers = null; //let GC do its work 298 return operators; 299 } 300 } 301 302 /** 303 * Common superclass for all unary operator helpers. 304 */ 305 abstract class UnaryOperatorHelper extends OperatorHelper implements Predicate<Type> { 306 307 UnaryOperatorHelper(Tag tag) { 308 super(tag); 309 } 310 311 /** 312 * This routine implements the unary operator lookup process. It customizes the behavior 313 * of the shared lookup routine in {@link OperatorHelper}, by using an unary applicability test 314 * (see {@link UnaryOperatorHelper#isUnaryOperatorApplicable(OperatorSymbol, Type)} 315 */ 316 final Symbol doLookup(Type t) { 317 return doLookup(op -> isUnaryOperatorApplicable((OperatorSymbol)op, t)); 318 } 319 320 /** 321 * Unary operator applicability test - is the input type the same as the expected operand type? 322 */ 323 boolean isUnaryOperatorApplicable(OperatorSymbol op, Type t) { 324 return types.isSameType(op.type.getParameterTypes().head, t); 325 } 326 327 /** 328 * Adds a unary operator symbol. 329 */ 330 final UnaryOperatorHelper addUnaryOperator(OperatorType arg, OperatorType res, int... opcode) { 331 operatorSuppliers = operatorSuppliers.prepend(() -> makeOperator(name, List.of(arg), res, opcode)); 332 return this; 333 } 334 335 /** 336 * This method will be overridden by unary operator helpers to provide custom resolution 337 * logic. 338 */ 339 abstract Symbol resolve(Type t); 340 } 341 342 abstract class BinaryOperatorHelper extends OperatorHelper implements BiPredicate<Type, Type> { 343 344 BinaryOperatorHelper(Tag tag) { 345 super(tag); 346 } 347 348 /** 349 * This routine implements the binary operator lookup process. It customizes the behavior 350 * of the shared lookup routine in {@link OperatorHelper}, by using an unary applicability test 351 * (see {@link BinaryOperatorHelper#isBinaryOperatorApplicable(OperatorSymbol, Type, Type)} 352 */ 353 final Symbol doLookup(Type t1, Type t2) { 354 return doLookup(op -> isBinaryOperatorApplicable((OperatorSymbol)op, t1, t2)); 355 } 356 357 /** 358 * Binary operator applicability test - are the input types the same as the expected operand types? 359 */ 360 boolean isBinaryOperatorApplicable(OperatorSymbol op, Type t1, Type t2) { 361 List<Type> formals = op.type.getParameterTypes(); 362 return types.isSameType(formals.head, t1) && 363 types.isSameType(formals.tail.head, t2); 364 } 365 366 /** 367 * Adds a binary operator symbol. 368 */ 369 final BinaryOperatorHelper addBinaryOperator(OperatorType arg1, OperatorType arg2, OperatorType res, int... opcode) { 370 operatorSuppliers = operatorSuppliers.prepend(() -> makeOperator(name, List.of(arg1, arg2), res, opcode)); 371 return this; 372 } 373 374 /** 375 * This method will be overridden by binary operator helpers to provide custom resolution 376 * logic. 377 */ 378 abstract Symbol resolve(Type t1, Type t2); 379 } 380 381 /** 382 * Class representing unary operator helpers that operate on reference types. 383 */ 384 class UnaryReferenceOperator extends UnaryOperatorHelper { 385 386 UnaryReferenceOperator(Tag tag) { 387 super(tag); 388 } 389 390 @Override 391 public boolean test(Type type) { 392 return type.isNullOrReference(); 393 } 394 395 @Override 396 public Symbol resolve(Type arg) { 397 return doLookup(syms.objectType); 398 } 399 } 400 401 /** 402 * Class representing unary operator helpers that operate on numeric types (either boxed or unboxed). 403 * Operator lookup is performed after applying numeric promotion of the input type. 404 */ 405 class UnaryNumericOperator extends UnaryOperatorHelper { 406 407 UnaryNumericOperator(Tag tag) { 408 super(tag); 409 } 410 411 @Override 412 public boolean test(Type type) { 413 return unaryPromotion(type).isNumeric(); 414 } 415 416 @Override 417 public Symbol resolve(Type arg) { 418 return doLookup(unaryPromotion(arg)); 419 } 420 } 421 422 /** 423 * Class representing unary operator helpers that operate on boolean types (either boxed or unboxed). 424 * Operator lookup is performed assuming the input type is a boolean type. 425 */ 426 class UnaryBooleanOperator extends UnaryOperatorHelper { 427 428 UnaryBooleanOperator(Tag tag) { 429 super(tag); 430 } 431 432 @Override 433 public boolean test(Type type) { 434 return types.unboxedTypeOrType(type).hasTag(TypeTag.BOOLEAN); 435 } 436 437 @Override 438 public Symbol resolve(Type arg) { 439 return doLookup(syms.booleanType); 440 } 441 } 442 443 /** 444 * Class representing prefix/postfix unary operator helpers. Operates on numeric types (either 445 * boxed or unboxed). Operator lookup is performed on the unboxed version of the input type. 446 */ 447 class UnaryPrefixPostfixOperator extends UnaryNumericOperator { 448 449 UnaryPrefixPostfixOperator(Tag tag) { 450 super(tag); 451 } 452 453 @Override 454 public Symbol resolve(Type arg) { 455 return doLookup(types.unboxedTypeOrType(arg)); 456 } 457 } 458 459 /** 460 * Class representing binary operator helpers that operate on numeric types (either boxed or unboxed). 461 * Operator lookup is performed after applying binary numeric promotion of the input types. 462 */ 463 class BinaryNumericOperator extends BinaryOperatorHelper { 464 465 BinaryNumericOperator(Tag tag) { 466 super(tag); 467 } 468 469 @Override 470 public Symbol resolve(Type arg1, Type arg2) { 471 Type t = binaryPromotion(arg1, arg2); 472 return doLookup(t, t); 473 } 474 475 @Override 476 public boolean test(Type arg1, Type arg2) { 477 return unaryPromotion(arg1).isNumeric() && unaryPromotion(arg2).isNumeric(); 478 } 479 } 480 481 /** 482 * Class representing bitwise operator helpers that operate on boolean types (either boxed or unboxed). 483 * Operator lookup is performed assuming both input types are boolean types. 484 */ 485 class BinaryBooleanOperator extends BinaryOperatorHelper { 486 487 BinaryBooleanOperator(Tag tag) { 488 super(tag); 489 } 490 491 @Override 492 public Symbol resolve(Type arg1, Type arg2) { 493 return doLookup(syms.booleanType, syms.booleanType); 494 } 495 496 @Override 497 public boolean test(Type arg1, Type arg2) { 498 return types.unboxedTypeOrType(arg1).hasTag(TypeTag.BOOLEAN) && 499 types.unboxedTypeOrType(arg2).hasTag(TypeTag.BOOLEAN); 500 } 501 } 502 503 /** 504 * Class representing string concatenation operator helper that operates on at least an 505 * string operand. Input types subject to an operator lookup undergoes a special string promotion 506 * (see {@link BinaryStringOperator#stringPromotion(Type)}. 507 */ 508 class BinaryStringOperator extends BinaryOperatorHelper { 509 510 BinaryStringOperator(Tag tag) { 511 super(tag); 512 } 513 514 @Override 515 public Symbol resolve(Type arg1, Type arg2) { 516 return doLookup(stringPromotion(arg1), stringPromotion(arg2)); 517 } 518 519 @Override 520 public boolean test(Type arg1, Type arg2) { 521 return types.isSameType(arg1, syms.stringType) || 522 types.isSameType(arg2, syms.stringType); 523 } 524 525 /** 526 * This routine applies following mappings: 527 * - if input type is primitive, apply numeric promotion 528 * - if input type is either 'null' or 'String' leave it untouched 529 * - otherwise return 'Object' 530 */ 531 private Type stringPromotion(Type t) { 532 if (t.isPrimitive()) { 533 return unaryPromotion(t); 534 } else if (t.hasTag(TypeTag.BOT) || 535 types.isSameType(t, syms.stringType)) { 536 return t; 537 } else if (t.hasTag(TypeTag.TYPEVAR)) { 538 return stringPromotion(t.getUpperBound()); 539 } else { 540 return syms.objectType; 541 } 542 } 543 } 544 545 /** 546 * Class representing shift operator helper that operates on integral operand types (either boxed 547 * or unboxed). Operator lookup is performed after applying unary numeric promotion to each input type. 548 */ 549 class BinaryShiftOperator extends BinaryOperatorHelper { 550 551 BinaryShiftOperator(Tag tag) { 552 super(tag); 553 } 554 555 @Override 556 public Symbol resolve(Type arg1, Type arg2) { 557 return doLookup(unaryPromotion(arg1), unaryPromotion(arg2)); 558 } 559 560 @Override 561 public boolean test(Type arg1, Type arg2) { 562 TypeTag op1 = unaryPromotion(arg1).getTag(); 563 TypeTag op2 = unaryPromotion(arg2).getTag(); 564 return (op1 == TypeTag.LONG || op1 == TypeTag.INT) && 565 (op2 == TypeTag.LONG || op2 == TypeTag.INT); 566 } 567 } 568 569 /** 570 * This enum represent the possible kinds of an comparison test ('==' and '!='). 571 */ 572 enum ComparisonKind { 573 /** equality between numeric or boolean operands. */ 574 NUMERIC_OR_BOOLEAN, 575 /** equality between reference operands. */ 576 REFERENCE, 577 /** erroneous equality */ 578 INVALID 579 } 580 581 /** 582 * Class representing equality operator helper that operates on either numeric, boolean or reference 583 * types. Operator lookup for numeric/boolean equality test is performed after binary numeric 584 * promotion to the input types. Operator lookup for reference equality test is performed assuming 585 * the input type is 'Object'. 586 */ 587 class BinaryEqualityOperator extends BinaryOperatorHelper { 588 589 BinaryEqualityOperator(Tag tag) { 590 super(tag); 591 } 592 593 @Override 594 public boolean test(Type arg1, Type arg2) { 595 return getKind(arg1, arg2) != ComparisonKind.INVALID; 596 } 597 598 @Override 599 public Symbol resolve(Type t1, Type t2) { 600 ComparisonKind kind = getKind(t1, t2); 601 Type t = (kind == ComparisonKind.NUMERIC_OR_BOOLEAN) ? 602 binaryPromotion(t1, t2) : 603 syms.objectType; 604 return doLookup(t, t); 605 } 606 607 /** 608 * Retrieve the comparison kind associated with the given argument type pair. 609 */ 610 private ComparisonKind getKind(Type arg1, Type arg2) { 611 boolean arg1Primitive = arg1.isPrimitive(); 612 boolean arg2Primitive = arg2.isPrimitive(); 613 if (arg1Primitive && arg2Primitive) { 614 return ComparisonKind.NUMERIC_OR_BOOLEAN; 615 } else if (arg1Primitive) { 616 return unaryPromotion(arg2).isPrimitive() ? 617 ComparisonKind.NUMERIC_OR_BOOLEAN : ComparisonKind.INVALID; 618 } else if (arg2Primitive) { 619 return unaryPromotion(arg1).isPrimitive() ? 620 ComparisonKind.NUMERIC_OR_BOOLEAN : ComparisonKind.INVALID; 621 } else { 622 return arg1.isNullOrReference() && arg2.isNullOrReference() ? 623 ComparisonKind.REFERENCE : ComparisonKind.INVALID; 624 } 625 } 626 } 627 628 /** 629 * Initialize all unary operators. 630 */ 631 private void initUnaryOperators() { 632 initOperators(unaryOperators, 633 new UnaryNumericOperator(Tag.POS) 634 .addUnaryOperator(DOUBLE, DOUBLE, nop) 635 .addUnaryOperator(FLOAT, FLOAT, nop) 636 .addUnaryOperator(LONG, LONG, nop) 637 .addUnaryOperator(INT, INT, nop), 638 new UnaryNumericOperator(Tag.NEG) 639 .addUnaryOperator(DOUBLE, DOUBLE, dneg) 640 .addUnaryOperator(FLOAT, FLOAT, fneg) 641 .addUnaryOperator(LONG, LONG, lneg) 642 .addUnaryOperator(INT, INT, ineg), 643 new UnaryNumericOperator(Tag.COMPL) 644 .addUnaryOperator(LONG, LONG, lxor) 645 .addUnaryOperator(INT, INT, ixor), 646 new UnaryPrefixPostfixOperator(Tag.POSTINC) 647 .addUnaryOperator(DOUBLE, DOUBLE, dadd) 648 .addUnaryOperator(FLOAT, FLOAT, fadd) 649 .addUnaryOperator(LONG, LONG, ladd) 650 .addUnaryOperator(INT, INT, iadd) 651 .addUnaryOperator(CHAR, CHAR, iadd) 652 .addUnaryOperator(SHORT, SHORT, iadd) 653 .addUnaryOperator(BYTE, BYTE, iadd), 654 new UnaryPrefixPostfixOperator(Tag.POSTDEC) 655 .addUnaryOperator(DOUBLE, DOUBLE, dsub) 656 .addUnaryOperator(FLOAT, FLOAT, fsub) 657 .addUnaryOperator(LONG, LONG, lsub) 658 .addUnaryOperator(INT, INT, isub) 659 .addUnaryOperator(CHAR, CHAR, isub) 660 .addUnaryOperator(SHORT, SHORT, isub) 661 .addUnaryOperator(BYTE, BYTE, isub), 662 new UnaryBooleanOperator(Tag.NOT) 663 .addUnaryOperator(BOOLEAN, BOOLEAN, bool_not), 664 new UnaryReferenceOperator(Tag.NULLCHK) 665 .addUnaryOperator(OBJECT, OBJECT, nullchk)); 666 } 667 668 /** 669 * Initialize all binary operators. 670 */ 671 private void initBinaryOperators() { 672 initOperators(binaryOperators, 673 new BinaryStringOperator(Tag.PLUS) 674 .addBinaryOperator(STRING, OBJECT, STRING, string_add) 675 .addBinaryOperator(OBJECT, STRING, STRING, string_add) 676 .addBinaryOperator(STRING, STRING, STRING, string_add) 677 .addBinaryOperator(STRING, INT, STRING, string_add) 678 .addBinaryOperator(STRING, LONG, STRING, string_add) 679 .addBinaryOperator(STRING, FLOAT, STRING, string_add) 680 .addBinaryOperator(STRING, DOUBLE, STRING, string_add) 681 .addBinaryOperator(STRING, BOOLEAN, STRING, string_add) 682 .addBinaryOperator(STRING, BOT, STRING, string_add) 683 .addBinaryOperator(INT, STRING, STRING, string_add) 684 .addBinaryOperator(LONG, STRING, STRING, string_add) 685 .addBinaryOperator(FLOAT, STRING, STRING, string_add) 686 .addBinaryOperator(DOUBLE, STRING, STRING, string_add) 687 .addBinaryOperator(BOOLEAN, STRING, STRING, string_add) 688 .addBinaryOperator(BOT, STRING, STRING, string_add), 689 new BinaryNumericOperator(Tag.PLUS) 690 .addBinaryOperator(DOUBLE, DOUBLE, DOUBLE, dadd) 691 .addBinaryOperator(FLOAT, FLOAT, FLOAT, fadd) 692 .addBinaryOperator(LONG, LONG, LONG, ladd) 693 .addBinaryOperator(INT, INT, INT, iadd), 694 new BinaryNumericOperator(Tag.MINUS) 695 .addBinaryOperator(DOUBLE, DOUBLE, DOUBLE, dsub) 696 .addBinaryOperator(FLOAT, FLOAT, FLOAT, fsub) 697 .addBinaryOperator(LONG, LONG, LONG, lsub) 698 .addBinaryOperator(INT, INT, INT, isub), 699 new BinaryNumericOperator(Tag.MUL) 700 .addBinaryOperator(DOUBLE, DOUBLE, DOUBLE, dmul) 701 .addBinaryOperator(FLOAT, FLOAT, FLOAT, fmul) 702 .addBinaryOperator(LONG, LONG, LONG, lmul) 703 .addBinaryOperator(INT, INT, INT, imul), 704 new BinaryNumericOperator(Tag.DIV) 705 .addBinaryOperator(DOUBLE, DOUBLE, DOUBLE, ddiv) 706 .addBinaryOperator(FLOAT, FLOAT, FLOAT, fdiv) 707 .addBinaryOperator(LONG, LONG, LONG, ldiv) 708 .addBinaryOperator(INT, INT, INT, idiv), 709 new BinaryNumericOperator(Tag.MOD) 710 .addBinaryOperator(DOUBLE, DOUBLE, DOUBLE, dmod) 711 .addBinaryOperator(FLOAT, FLOAT, FLOAT, fmod) 712 .addBinaryOperator(LONG, LONG, LONG, lmod) 713 .addBinaryOperator(INT, INT, INT, imod), 714 new BinaryBooleanOperator(Tag.BITAND) 715 .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, iand), 716 new BinaryNumericOperator(Tag.BITAND) 717 .addBinaryOperator(LONG, LONG, LONG, land) 718 .addBinaryOperator(INT, INT, INT, iand), 719 new BinaryBooleanOperator(Tag.BITOR) 720 .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, ior), 721 new BinaryNumericOperator(Tag.BITOR) 722 .addBinaryOperator(LONG, LONG, LONG, lor) 723 .addBinaryOperator(INT, INT, INT, ior), 724 new BinaryBooleanOperator(Tag.BITXOR) 725 .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, ixor), 726 new BinaryNumericOperator(Tag.BITXOR) 727 .addBinaryOperator(LONG, LONG, LONG, lxor) 728 .addBinaryOperator(INT, INT, INT, ixor), 729 new BinaryShiftOperator(Tag.SL) 730 .addBinaryOperator(INT, INT, INT, ishl) 731 .addBinaryOperator(INT, LONG, INT, ishll) 732 .addBinaryOperator(LONG, INT, LONG, lshl) 733 .addBinaryOperator(LONG, LONG, LONG, lshll), 734 new BinaryShiftOperator(Tag.SR) 735 .addBinaryOperator(INT, INT, INT, ishr) 736 .addBinaryOperator(INT, LONG, INT, ishrl) 737 .addBinaryOperator(LONG, INT, LONG, lshr) 738 .addBinaryOperator(LONG, LONG, LONG, lshrl), 739 new BinaryShiftOperator(Tag.USR) 740 .addBinaryOperator(INT, INT, INT, iushr) 741 .addBinaryOperator(INT, LONG, INT, iushrl) 742 .addBinaryOperator(LONG, INT, LONG, lushr) 743 .addBinaryOperator(LONG, LONG, LONG, lushrl), 744 new BinaryNumericOperator(Tag.LT) 745 .addBinaryOperator(DOUBLE, DOUBLE, BOOLEAN, dcmpg, iflt) 746 .addBinaryOperator(FLOAT, FLOAT, BOOLEAN, fcmpg, iflt) 747 .addBinaryOperator(LONG, LONG, BOOLEAN, lcmp, iflt) 748 .addBinaryOperator(INT, INT, BOOLEAN, if_icmplt), 749 new BinaryNumericOperator(Tag.GT) 750 .addBinaryOperator(DOUBLE, DOUBLE, BOOLEAN, dcmpl, ifgt) 751 .addBinaryOperator(FLOAT, FLOAT, BOOLEAN, fcmpl, ifgt) 752 .addBinaryOperator(LONG, LONG, BOOLEAN, lcmp, ifgt) 753 .addBinaryOperator(INT, INT, BOOLEAN, if_icmpgt), 754 new BinaryNumericOperator(Tag.LE) 755 .addBinaryOperator(DOUBLE, DOUBLE, BOOLEAN, dcmpg, ifle) 756 .addBinaryOperator(FLOAT, FLOAT, BOOLEAN, fcmpg, ifle) 757 .addBinaryOperator(LONG, LONG, BOOLEAN, lcmp, ifle) 758 .addBinaryOperator(INT, INT, BOOLEAN, if_icmple), 759 new BinaryNumericOperator(Tag.GE) 760 .addBinaryOperator(DOUBLE, DOUBLE, BOOLEAN, dcmpl, ifge) 761 .addBinaryOperator(FLOAT, FLOAT, BOOLEAN, fcmpl, ifge) 762 .addBinaryOperator(LONG, LONG, BOOLEAN, lcmp, ifge) 763 .addBinaryOperator(INT, INT, BOOLEAN, if_icmpge), 764 new BinaryEqualityOperator(Tag.EQ) 765 .addBinaryOperator(OBJECT, OBJECT, BOOLEAN, if_acmpeq) 766 .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, if_icmpeq) 767 .addBinaryOperator(DOUBLE, DOUBLE, BOOLEAN, dcmpl, ifeq) 768 .addBinaryOperator(FLOAT, FLOAT, BOOLEAN, fcmpl, ifeq) 769 .addBinaryOperator(LONG, LONG, BOOLEAN, lcmp, ifeq) 770 .addBinaryOperator(INT, INT, BOOLEAN, if_icmpeq), 771 new BinaryEqualityOperator(Tag.NE) 772 .addBinaryOperator(OBJECT, OBJECT, BOOLEAN, if_acmpne) 773 .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, if_icmpne) 774 .addBinaryOperator(DOUBLE, DOUBLE, BOOLEAN, dcmpl, ifne) 775 .addBinaryOperator(FLOAT, FLOAT, BOOLEAN, fcmpl, ifne) 776 .addBinaryOperator(LONG, LONG, BOOLEAN, lcmp, ifne) 777 .addBinaryOperator(INT, INT, BOOLEAN, if_icmpne), 778 new BinaryBooleanOperator(Tag.AND) 779 .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, bool_and), 780 new BinaryBooleanOperator(Tag.OR) 781 .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, bool_or)); 782 } 783 784 /** 785 * Complete the initialization of an operator helper by storing it into the corresponding operator map. 786 */ 787 @SafeVarargs 788 private final <O extends OperatorHelper> void initOperators(Map<Name, List<O>> opsMap, O... ops) { 789 for (O o : ops) { 790 Name opName = o.name; 791 List<O> helpers = opsMap.getOrDefault(opName, List.nil()); 792 opsMap.put(opName, helpers.prepend(o)); 793 } 794 } 795 796 /** 797 * Initialize operator name array. 798 */ 799 private void initOperatorNames() { 800 setOperatorName(Tag.POS, "+"); 801 setOperatorName(Tag.NEG, "-"); 802 setOperatorName(Tag.NOT, "!"); 803 setOperatorName(Tag.COMPL, "~"); 804 setOperatorName(Tag.PREINC, "++"); 805 setOperatorName(Tag.PREDEC, "--"); 806 setOperatorName(Tag.POSTINC, "++"); 807 setOperatorName(Tag.POSTDEC, "--"); 808 setOperatorName(Tag.NULLCHK, "<*nullchk*>"); 809 setOperatorName(Tag.OR, "||"); 810 setOperatorName(Tag.AND, "&&"); 811 setOperatorName(Tag.EQ, "=="); 812 setOperatorName(Tag.NE, "!="); 813 setOperatorName(Tag.LT, "<"); 814 setOperatorName(Tag.GT, ">"); 815 setOperatorName(Tag.LE, "<="); 816 setOperatorName(Tag.GE, ">="); 817 setOperatorName(Tag.BITOR, "|"); 818 setOperatorName(Tag.BITXOR, "^"); 819 setOperatorName(Tag.BITAND, "&"); 820 setOperatorName(Tag.SL, "<<"); 821 setOperatorName(Tag.SR, ">>"); 822 setOperatorName(Tag.USR, ">>>"); 823 setOperatorName(Tag.PLUS, "+"); 824 setOperatorName(Tag.MINUS, names.hyphen); 825 setOperatorName(Tag.MUL, names.asterisk); 826 setOperatorName(Tag.DIV, names.slash); 827 setOperatorName(Tag.MOD, "%"); 828 } 829 //where 830 private void setOperatorName(Tag tag, String name) { 831 setOperatorName(tag, names.fromString(name)); 832 } 833 834 private void setOperatorName(Tag tag, Name name) { 835 opname[tag.operatorIndex()] = name; 836 } 837} 838