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.List;
014import java.util.LinkedList;
015
016import static java.util.Collections.unmodifiableList;
017
018/**
019 * A {@code match} node.
020 * <p> This node describe tree such as:
021 * <pre class="listing"><code class="lang-golo" data-lang="golo">
022 *  match {
023 *    when condition_1 then expression_1
024 *    when condition_2 then expression_2
025 *    otherwise default_expression
026 *  }
027 * </code></pre>
028 */
029public final class MatchExpression extends ExpressionStatement<MatchExpression> implements Alternatives<ExpressionStatement<?>> {
030
031  private ExpressionStatement<?> otherwise;
032  private final LinkedList<WhenClause<ExpressionStatement<?>>> clauses = new LinkedList<>();
033
034  MatchExpression() {
035    super();
036  }
037
038  /**
039   * Creates an empty match expression.
040   */
041  public static MatchExpression match() {
042    return new MatchExpression();
043  }
044
045  protected MatchExpression self() { return this; }
046
047  /**
048   * {@inheritDoc}
049   */
050  @Override
051  public MatchExpression when(Object cond) {
052    if (cond instanceof WhenClause) {
053      @SuppressWarnings("unchecked")
054      WhenClause<ExpressionStatement<?>> clause = (WhenClause<ExpressionStatement<?>>) cond;
055      this.clauses.add(makeParentOf(clause));
056    } else {
057      this.clauses.add(makeParentOf(new WhenClause<ExpressionStatement<?>>(ExpressionStatement.of(cond), null)));
058    }
059    return this;
060  }
061
062  /**
063   * {@inheritDoc}
064   *
065   * @param action a {@link gololang.ir.ExpressionStatement} containing the expression to return.
066   */
067  @Override
068  public MatchExpression then(Object action) {
069    this.clauses.getLast().then(ExpressionStatement.of(action));
070    return this;
071  }
072
073  /**
074   * {@inheritDoc}
075   *
076   * @param action a {@link gololang.ir.ExpressionStatement} containing the expression to return.
077   */
078  @Override
079  public MatchExpression otherwise(Object action) {
080    this.otherwise = makeParentOf(ExpressionStatement.of(action));
081    return this;
082  }
083
084  public List<WhenClause<ExpressionStatement<?>>> getClauses() {
085    return unmodifiableList(this.clauses);
086  }
087
088  public ExpressionStatement<?> getOtherwise() {
089    return this.otherwise;
090  }
091
092  /**
093   * {@inheritDoc}
094   */
095  @Override
096  public void accept(GoloIrVisitor visitor) {
097    visitor.visitMatchExpression(this);
098  }
099
100  /**
101   * {@inheritDoc}
102   */
103  @Override
104  public List<GoloElement<?>> children() {
105    LinkedList<GoloElement<?>> children = new LinkedList<>(clauses);
106    children.add(otherwise);
107    return children;
108  }
109
110  /**
111   * {@inheritDoc}
112   */
113  @Override
114  protected void replaceElement(GoloElement<?> original, GoloElement<?> newElement) {
115    if (!(newElement instanceof ExpressionStatement || newElement instanceof WhenClause)) {
116      throw cantConvert("ExpressionStatement or WhenClause", newElement);
117    }
118    if (otherwise.equals(original)) {
119      otherwise(newElement);
120      return;
121    }
122    if (clauses.contains(original)) {
123      @SuppressWarnings("unchecked")
124      WhenClause<ExpressionStatement<?>> when = (WhenClause<ExpressionStatement<?>>) newElement;
125      clauses.set(clauses.indexOf(original), makeParentOf(when));
126      return;
127    }
128    throw doesNotContain(original);
129  }
130}