001/*
002 * Copyright (c) 2012-2018 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others
003 *
004 * This program and the accompanying materials are made available under the
005 * terms of the Eclipse Public License 2.0 which is available at
006 * http://www.eclipse.org/legal/epl-2.0.
007 *
008 * SPDX-License-Identifier: EPL-2.0
009 */
010
011package gololang.ir;
012
013import java.util.LinkedList;
014import java.util.List;
015
016import static java.util.Collections.unmodifiableList;
017
018/**
019 * A {@code case} node.
020 * <p> This node describe tree such as:
021 * <pre class="listing"><code class="lang-golo" data-lang="golo">
022 *  case {
023 *    when condition_1 {
024 *      action_1
025 *    }
026 *    when condition_2 {
027 *      action_2
028 *    }
029 *    otherwise {
030 *      default_action
031 *    }
032 *  }
033 * </code></pre>
034 */
035public final class CaseStatement extends GoloStatement<CaseStatement> implements Alternatives<Block> {
036
037  private Block otherwise;
038  private final LinkedList<WhenClause<Block>> clauses = new LinkedList<>();
039
040  private CaseStatement() {
041    super();
042  }
043
044  /**
045   * Creates an empty case switch.
046   */
047  public static CaseStatement cases() {
048    return new CaseStatement();
049  }
050
051  protected CaseStatement self() { return this; }
052
053  /**
054   * {@inheritDoc}
055   */
056  @Override
057  public CaseStatement when(Object cond) {
058    if (cond instanceof WhenClause) {
059      @SuppressWarnings("unchecked")
060      WhenClause<Block> clause = (WhenClause<Block>) cond;
061      this.clauses.add(makeParentOf(clause));
062    } else {
063      this.clauses.add(makeParentOf(new WhenClause<Block>(ExpressionStatement.of(cond), null)));
064    }
065    return this;
066  }
067
068  /**
069   * {@inheritDoc}
070   *
071   * @param action a {@link gololang.ir.Block} containing the statements to execute.
072   */
073  @Override
074  public CaseStatement then(Object action) {
075    this.clauses.getLast().then(Block.of(action));
076    return this;
077  }
078
079  /**
080   * {@inheritDoc}
081   *
082   * @param action a {@link gololang.ir.Block} containing the statements to execute.
083   */
084  @Override
085  public CaseStatement otherwise(Object action) {
086    this.otherwise = makeParentOf(Block.of(action));
087    return this;
088  }
089
090  public List<WhenClause<Block>> getClauses() {
091    return unmodifiableList(this.clauses);
092  }
093
094  public Block getOtherwise() {
095    return this.otherwise;
096  }
097
098  /**
099   * {@inheritDoc}
100   */
101  @Override
102  public void accept(GoloIrVisitor visitor) {
103    visitor.visitCaseStatement(this);
104  }
105
106  /**
107   * {@inheritDoc}
108   */
109  @Override
110  public List<GoloElement<?>> children() {
111    LinkedList<GoloElement<?>> children = new LinkedList<>(clauses);
112    children.add(otherwise);
113    return children;
114  }
115
116  /**
117   * {@inheritDoc}
118   */
119  @Override
120  public void replaceElement(GoloElement<?> original, GoloElement<?> newElement) {
121    if (!(newElement instanceof Block || newElement instanceof WhenClause)) {
122      throw cantConvert("Block or WhenClause", newElement);
123    }
124    if (otherwise.equals(original)) {
125      otherwise(newElement);
126      return;
127    }
128    if (clauses.contains(original)) {
129      @SuppressWarnings("unchecked")
130      WhenClause<Block> when = (WhenClause<Block>) newElement;
131      clauses.set(clauses.indexOf(original), makeParentOf(when));
132      return;
133    }
134    throw doesNotContain(original);
135  }
136}