001/*
002 * Copyright (c) 2012-2017 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 */
009
010package org.eclipse.golo.compiler.ir;
011
012import org.eclipse.golo.compiler.parser.GoloASTNode;
013
014public final class ConditionalBranching extends GoloStatement implements Scope {
015
016  private ExpressionStatement condition;
017  private Block trueBlock;
018  private ConditionalBranching elseConditionalBranching;
019  private Block falseBlock;
020
021  ConditionalBranching() {
022    super();
023  }
024
025  public ConditionalBranching condition(Object cond) {
026    if (cond == null) {
027      setCondition(Builders.constant(false));
028    } else {
029      setCondition((ExpressionStatement) cond);
030    }
031    return this;
032  }
033
034  public ConditionalBranching whenTrue(Object block) {
035    setTrueBlock(Builders.toBlock(block));
036    return this;
037  }
038
039  public ConditionalBranching whenFalse(Object block) {
040    setFalseBlock(block == null ? null : Builders.toBlock(block));
041    return this;
042  }
043
044  public ConditionalBranching elseBranch(Object elseBranch) {
045    this.elseConditionalBranching = (ConditionalBranching) elseBranch;
046    makeParentOf(elseConditionalBranching);
047    return this;
048  }
049
050  public ConditionalBranching otherwise(Object alternative) {
051    if (alternative instanceof ConditionalBranching) {
052      return elseBranch((ConditionalBranching) alternative);
053    }
054    return whenFalse(alternative);
055  }
056
057  @Override
058  public ConditionalBranching ofAST(GoloASTNode node) {
059    super.ofAST(node);
060    return this;
061  }
062
063  @Override
064  public void relink(ReferenceTable table) {
065    trueBlock.relink(table);
066    if (falseBlock != null) {
067      falseBlock.relink(table);
068    }
069    if (elseConditionalBranching != null) {
070      elseConditionalBranching.relink(table);
071    }
072  }
073
074  @Override
075  public void relinkTopLevel(ReferenceTable table) {
076    trueBlock.relinkTopLevel(table);
077    if (falseBlock != null) {
078      falseBlock.relinkTopLevel(table);
079    }
080    if (elseConditionalBranching != null) {
081      elseConditionalBranching.relinkTopLevel(table);
082    }
083  }
084
085  public ExpressionStatement getCondition() {
086    return condition;
087  }
088
089  public void setCondition(ExpressionStatement condition) {
090    this.condition = condition;
091    makeParentOf(condition);
092  }
093
094  public Block getTrueBlock() {
095    return trueBlock;
096  }
097
098  public void setTrueBlock(Block block) {
099    this.trueBlock = block;
100    makeParentOf(block);
101  }
102
103  public Block getFalseBlock() {
104    return falseBlock;
105  }
106
107  public void setFalseBlock(Block block) {
108    this.falseBlock = block;
109    if (block != null) {
110      makeParentOf(block);
111    }
112  }
113
114  public boolean hasFalseBlock() {
115    return falseBlock != null;
116  }
117
118  public ConditionalBranching getElseConditionalBranching() {
119    return elseConditionalBranching;
120  }
121
122  public void setElseConditionalBranching(ConditionalBranching elseBranch) {
123    this.elseConditionalBranching = elseBranch;
124    makeParentOf(elseBranch);
125  }
126
127  public boolean hasElseConditionalBranching() {
128    return elseConditionalBranching != null;
129  }
130
131  public boolean returnsFromBothBranches() {
132    if (hasFalseBlock()) {
133      return trueBlock.hasReturn() && falseBlock.hasReturn();
134    } else if (hasElseConditionalBranching()) {
135      return trueBlock.hasReturn() && elseConditionalBranching.returnsFromBothBranches();
136    } else {
137      return false;
138    }
139  }
140
141  @Override
142  public String toString() {
143    return String.format("if %s %s%s", condition, trueBlock,
144        hasFalseBlock() ? " else " + falseBlock.toString()
145        : hasElseConditionalBranching() ? " else " + elseConditionalBranching.toString()
146        : "");
147  }
148
149  @Override
150  public void accept(GoloIrVisitor visitor) {
151    visitor.visitConditionalBranching(this);
152  }
153
154  @Override
155  public void walk(GoloIrVisitor visitor) {
156    condition.accept(visitor);
157    trueBlock.accept(visitor);
158    if (falseBlock != null) {
159      falseBlock.accept(visitor);
160    }
161    if (elseConditionalBranching != null) {
162      elseConditionalBranching.accept(visitor);
163    }
164  }
165
166  @Override
167  protected void replaceElement(GoloElement original, GoloElement newElement) {
168    if (condition == original && newElement instanceof ExpressionStatement) {
169      condition(newElement);
170    } else if (elseConditionalBranching == original && newElement instanceof ConditionalBranching) {
171      elseBranch(newElement);
172    } else if (trueBlock == original) {
173      whenTrue(newElement);
174    } else if (falseBlock == original) {
175      whenFalse(newElement);
176    } else {
177      throw cantReplace(original, newElement);
178    }
179  }
180
181}