001/*
002 * Copyright (c) 2012-2021 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.Arrays;
014import java.util.List;
015import gololang.Tuple;
016import org.eclipse.golo.runtime.InvalidDestructuringException;
017
018public final class WhenClause<T extends GoloElement<?>> extends GoloElement<WhenClause<T>> {
019  private ExpressionStatement<?> condition;
020  private T action;
021
022  WhenClause(ExpressionStatement<?> condition, T action) {
023    this.condition = makeParentOf(condition);
024    setAction(action);
025  }
026
027  protected WhenClause<T> self() { return this; }
028
029  public ExpressionStatement<?> condition() { return this.condition; }
030
031  public T action() { return this.action; }
032
033  private void setAction(T a) {
034    this.action = makeParentOf(a);
035  }
036
037  public WhenClause<T> then(T action) {
038    setAction(action);
039    return this;
040  }
041
042  @Override
043  public String toString() {
044    return String.format("when %s then %s", condition, action);
045  }
046
047  /**
048   * {@inheritDoc}
049   */
050  @Override
051  protected void replaceElement(GoloElement<?> original, GoloElement<?> newElement) {
052    if (this.condition.equals(original)) {
053      if (!(newElement instanceof ExpressionStatement)) {
054        throw cantConvert("ExpressionStatement", newElement);
055      }
056      this.condition = makeParentOf(ExpressionStatement.of(newElement));
057    } else if (this.action.equals(original)) {
058      @SuppressWarnings("unchecked")
059      T element = (T) newElement;
060      setAction(element);
061    } else {
062      throw doesNotContain(original);
063    }
064  }
065
066  /**
067   * {@inheritDoc}
068   */
069  @Override
070  public void accept(GoloIrVisitor visitor) {
071    visitor.visitWhenClause(this);
072  }
073
074  /**
075   * {@inheritDoc}
076   */
077  @Override
078  public List<GoloElement<?>> children() {
079    return Arrays.asList(condition, action);
080  }
081
082  /**
083   * Destructuring helper.
084   * @deprecated This method should not be called directly and is no more used by new style destructuring.
085   */
086  @Deprecated
087  public Tuple destruct() {
088    return new Tuple(condition, action);
089  }
090
091  /**
092   * New style destructuring helper.
093   *
094   * <p>The destructuring must be to exactly two values. No remainer syntax is allowed.
095   * <p>The destructured values are the condition and the action.
096   *
097   * @param number number of variable that will be affected.
098   * @param substruct whether the destructuring is complete or should contains a sub structure.
099   * @param toSkip a boolean array indicating the elements to skip.
100   * @return an array containing the values to assign.
101   */
102  public Object[] __$$_destruct(int number, boolean substruct, Object[] toSkip) {
103    if (number == 2 && !substruct) {
104      return new Object[]{condition, action};
105    }
106    throw new InvalidDestructuringException("A WhenClause must destructure to exactly two values");
107  }
108}
109
110