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 */
021package org.biojava.utils.bytecode;
022
023import 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
041public 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}