001    /*
002     *                    BioJava development code
003     *
004     * This code may be freely distributed and modified under the
005     * terms of the GNU Lesser General Public Licence.  This should
006     * be distributed with the code.  If you do not have a copy,
007     * see:
008     *
009     *      http://www.gnu.org/copyleft/lesser.html
010     *
011     * Copyright for this code is held jointly by the individual
012     * authors.  These should be listed in @author doc comments.
013     *
014     * For more information on the BioJava project and its aims,
015     * or to join the biojava-l mailing list, visit the home page
016     * at:
017     *
018     *      http://www.biojava.org/
019     *
020     */
021    package org.biojava.utils.bytecode;
022    
023    import java.util.*;
024    
025    /**
026     * A CodeGenerator that provides something semanticaly identical to if.
027     * <P>
028     * It generates code of the form:
029     * <P>
030     * conditional branch to trueLabel<br>
031     * ifFalse instructions here<br>
032     * branch to endLabel<br>
033     * trueLabel<br>
034     * ifTrue instructions here<br>
035     * endLabel
036     *
037     *
038     * @author Matthew Pocock
039     */
040    
041    public class IfExpression implements CodeGenerator {
042      private Instruction ifInstruction;
043      private CodeGenerator ifTrue;
044      private CodeGenerator ifFalse;
045      private Label trueLabel;
046      private Label endLabel;
047      private Instruction skipTrue;
048      
049      private InstructionVector instructions;
050      
051      public IfExpression(
052        byte ifInstruction, 
053        CodeGenerator ifTrue, 
054        CodeGenerator ifFalse
055      ) {
056        this.trueLabel = new Label();
057        this.endLabel = new Label();
058        this.skipTrue = ByteCode.make_goto(endLabel);
059    
060        this.ifInstruction = ByteCode.make_if(ifInstruction, trueLabel);
061        this.ifTrue = ifTrue;
062        this.ifFalse = ifFalse;
063        
064        // lazyness - avoid work later
065        instructions = new InstructionVector();
066        instructions.add(this.ifInstruction);
067        instructions.add(this.ifFalse);
068        instructions.add(this.skipTrue);
069        instructions.add(ByteCode.make_markLabel(trueLabel));
070        instructions.add(this.ifTrue);
071        instructions.add(ByteCode.make_markLabel(endLabel));
072      }
073      
074      public Instruction getIfInstruction() {
075        return ifInstruction;
076      }
077      
078      public CodeGenerator getIfTrue() {
079        return ifTrue;
080      }
081      
082      public CodeGenerator getIfFalse() {
083        return ifFalse;
084      }
085      
086      public void writeCode(CodeContext ctx) throws CodeException {
087        instructions.writeCode(ctx);
088      }
089      
090      public int stackDepth() {
091        // custom handlers needed because of jumps
092        return
093          ifInstruction.stackDepth() +
094          Math.max(ifFalse.stackDepth(), ifTrue.stackDepth());
095      }
096      
097      public int stackDelta() {
098        // custom handler needed because of jumps
099        return
100          ifInstruction.stackDepth() +
101          Math.max(ifFalse.stackDepth(), ifTrue.stackDepth()); // these should agree
102      }
103    }