@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 + "].")); }
@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; }
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; }
@Override void extractVariables(Set<String> variables) { lhs.extractVariables(variables); rhs.extractVariables(variables); }
/** * 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 } }
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; }
@Override void write(MethodWriter writer) { writer.writeStatementOffset(offset); expression.write(writer); writer.returnValue(); }
@Override void write(MethodWriter writer) { index.write(writer); }