Пример #1
0
  @Override
  ALink analyze(Variables variables) {
    if (before == null) {
      throw new IllegalArgumentException(error("Illegal array access made without target."));
    }

    final Sort sort = before.sort;

    if (sort == Sort.ARRAY) {
      index.expected = Definition.INT_TYPE;
      index.analyze(variables);
      index = index.cast(variables);

      after = Definition.getType(before.struct, before.dimensions - 1);

      return this;
    } else if (sort == Sort.DEF) {
      return new LDefArray(line, offset, location, index).copy(this).analyze(variables);
    } else if (Map.class.isAssignableFrom(before.clazz)) {
      return new LMapShortcut(line, offset, location, index).copy(this).analyze(variables);
    } else if (List.class.isAssignableFrom(before.clazz)) {
      return new LListShortcut(line, offset, location, index).copy(this).analyze(variables);
    }

    throw new IllegalArgumentException(
        error("Illegal array access on type [" + before.name + "]."));
  }
Пример #2
0
  @Override
  void analyze(Variables variables) {
    expression.expected = Definition.OBJECT_TYPE;
    expression.internal = true;
    expression.analyze(variables);
    expression = expression.cast(variables);

    methodEscape = true;
    loopEscape = true;
    allEscape = true;

    statementCount = 1;
  }
Пример #3
0
  private void analyzeSimple(Locals locals) {
    AStoreable lhs = (AStoreable) this.lhs;

    // If the lhs node is a def optimized node we update the actual type to remove the need for a
    // cast.
    if (lhs.isDefOptimized()) {
      rhs.analyze(locals);
      rhs.expected = rhs.actual;
      lhs.updateActual(rhs.actual);
      // Otherwise, we must adapt the rhs type to the lhs type with a cast.
    } else {
      rhs.expected = lhs.actual;
      rhs.analyze(locals);
    }

    rhs = rhs.cast(locals);

    this.statement = true;
    this.actual = read ? lhs.actual : Definition.VOID_TYPE;
  }
Пример #4
0
 @Override
 void extractVariables(Set<String> variables) {
   lhs.extractVariables(variables);
   rhs.extractVariables(variables);
 }
Пример #5
0
  /**
   * Handles writing byte code for variable/method chains for all given possibilities including
   * String concatenation, compound assignment, regular assignment, and simple reads. Includes
   * proper duplication for chained assignments and assignments that are also read from.
   */
  @Override
  void write(MethodWriter writer, Globals globals) {
    writer.writeDebugInfo(location);

    // For the case where the assignment represents a String concatenation
    // we must, depending on the Java version, write a StringBuilder or
    // track types going onto the stack.  This must be done before the
    // lhs is read because we need the StringBuilder to be placed on the
    // stack ahead of any potential concatenation arguments.
    int catElementStackSize = 0;

    if (cat) {
      catElementStackSize = writer.writeNewStrings();
    }

    // Cast the lhs to a storeable to perform the necessary operations to store the rhs.
    AStoreable lhs = (AStoreable) this.lhs;
    lhs.setup(
        writer, globals); // call the setup method on the lhs to prepare for a load/store operation

    if (cat) {
      // Handle the case where we are doing a compound assignment
      // representing a String concatenation.

      writer.writeDup(
          lhs.accessElementCount(), catElementStackSize); // dup the top element and insert it
      // before concat helper on stack
      lhs.load(writer, globals); // read the current lhs's value
      writer.writeAppendStrings(lhs.actual); // append the lhs's value using the StringBuilder

      rhs.write(writer, globals); // write the bytecode for the rhs

      if (!(rhs instanceof EBinary)
          || !((EBinary) rhs).cat) { // check to see if the rhs has already done a concatenation
        writer.writeAppendStrings(rhs.actual); // append the rhs's value since it's hasn't already
      }

      writer.writeToStrings(); // put the value for string concat onto the stack
      writer.writeCast(back); // if necessary, cast the String to the lhs actual type

      if (lhs.read) {
        writer.writeDup(lhs.actual.sort.size, lhs.accessElementCount()); // if this lhs is also read
        // from dup the value onto the stack
      }

      lhs.store(
          writer,
          globals); // store the lhs's value from the stack in its respective variable/field/array
    } else if (operation != null) {
      // Handle the case where we are doing a compound assignment that
      // does not represent a String concatenation.

      writer.writeDup(lhs.accessElementCount(), 0); // if necessary, dup the previous lhs's value
      // to be both loaded from and stored to
      lhs.load(writer, globals); // load the current lhs's value

      if (lhs.read && post) {
        writer.writeDup(
            lhs.actual.sort.size, lhs.accessElementCount()); // dup the value if the lhs is also
        // read from and is a post increment
      }

      writer.writeCast(there); // if necessary cast the current lhs's value
      // to the promotion type between the lhs and rhs types
      rhs.write(writer, globals); // write the bytecode for the rhs

      // XXX: fix these types, but first we need def compound assignment tests.
      // its tricky here as there are possibly explicit casts, too.
      // write the operation instruction for compound assignment
      if (promote.sort == Sort.DEF) {
        writer.writeDynamicBinaryInstruction(
            location,
            promote,
            Definition.DEF_TYPE,
            Definition.DEF_TYPE,
            operation,
            DefBootstrap.OPERATOR_COMPOUND_ASSIGNMENT);
      } else {
        writer.writeBinaryInstruction(location, promote, operation);
      }

      writer.writeCast(back); // if necessary cast the promotion type value back to the lhs's type

      if (lhs.read && !post) {
        writer.writeDup(
            lhs.actual.sort.size, lhs.accessElementCount()); // dup the value if the lhs is also
        // read from and is not a post increment
      }

      lhs.store(
          writer,
          globals); // store the lhs's value from the stack in its respective variable/field/array
    } else {
      // Handle the case for a simple write.

      rhs.write(writer, globals); // write the bytecode for the rhs rhs

      if (lhs.read) {
        writer.writeDup(
            lhs.actual.sort.size,
            lhs.accessElementCount()); // dup the value if the lhs is also read from
      }

      lhs.store(
          writer,
          globals); // store the lhs's value from the stack in its respective variable/field/array
    }
  }
Пример #6
0
  private void analyzeCompound(Locals locals) {
    rhs.analyze(locals);

    boolean shift = false;

    if (operation == Operation.MUL) {
      promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true);
    } else if (operation == Operation.DIV) {
      promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true);
    } else if (operation == Operation.REM) {
      promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true);
    } else if (operation == Operation.ADD) {
      promote = AnalyzerCaster.promoteAdd(lhs.actual, rhs.actual);
    } else if (operation == Operation.SUB) {
      promote = AnalyzerCaster.promoteNumeric(lhs.actual, rhs.actual, true);
    } else if (operation == Operation.LSH) {
      promote = AnalyzerCaster.promoteNumeric(lhs.actual, false);
      shiftDistance = AnalyzerCaster.promoteNumeric(rhs.actual, false);
      shift = true;
    } else if (operation == Operation.RSH) {
      promote = AnalyzerCaster.promoteNumeric(lhs.actual, false);
      shiftDistance = AnalyzerCaster.promoteNumeric(rhs.actual, false);
      shift = true;
    } else if (operation == Operation.USH) {
      promote = AnalyzerCaster.promoteNumeric(lhs.actual, false);
      shiftDistance = AnalyzerCaster.promoteNumeric(rhs.actual, false);
      shift = true;
    } else if (operation == Operation.BWAND) {
      promote = AnalyzerCaster.promoteXor(lhs.actual, rhs.actual);
    } else if (operation == Operation.XOR) {
      promote = AnalyzerCaster.promoteXor(lhs.actual, rhs.actual);
    } else if (operation == Operation.BWOR) {
      promote = AnalyzerCaster.promoteXor(lhs.actual, rhs.actual);
    } else {
      throw createError(new IllegalStateException("Illegal tree structure."));
    }

    if (promote == null || (shift && shiftDistance == null)) {
      throw createError(
          new ClassCastException(
              "Cannot apply compound assignment "
                  + "["
                  + operation.symbol
                  + "=] to types ["
                  + lhs.actual
                  + "] and ["
                  + rhs.actual
                  + "]."));
    }

    cat = operation == Operation.ADD && promote.sort == Sort.STRING;

    if (cat) {
      if (rhs instanceof EBinary
          && ((EBinary) rhs).operation == Operation.ADD
          && rhs.actual.sort == Sort.STRING) {
        ((EBinary) rhs).cat = true;
      }

      rhs.expected = rhs.actual;
    } else if (shift) {
      if (promote.sort == Sort.DEF) {
        // shifts are promoted independently, but for the def type, we need object.
        rhs.expected = promote;
      } else if (shiftDistance.sort == Sort.LONG) {
        rhs.expected = Definition.INT_TYPE;
        rhs.explicit = true;
      } else {
        rhs.expected = shiftDistance;
      }
    } else {
      rhs.expected = promote;
    }

    rhs = rhs.cast(locals);

    there = AnalyzerCaster.getLegalCast(location, lhs.actual, promote, false, false);
    back = AnalyzerCaster.getLegalCast(location, promote, lhs.actual, true, false);

    this.statement = true;
    this.actual = read ? lhs.actual : Definition.VOID_TYPE;
  }
Пример #7
0
 @Override
 void write(MethodWriter writer) {
   writer.writeStatementOffset(offset);
   expression.write(writer);
   writer.returnValue();
 }
Пример #8
0
 @Override
 void write(MethodWriter writer) {
   index.write(writer);
 }