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.*;
014
015import static java.util.Collections.unmodifiableSet;
016
017/**
018 * Represents a {@code union} element.
019 *
020 * <p>For instance:
021 * <pre class="listing"><code class="lang-golo" data-lang="golo">
022 * union ConsList = {
023 *   Empty
024 *   Cons = {head, tail}
025 * }
026 * </code></pre>
027 */
028public final class Union extends GoloType<Union> implements ToplevelGoloElement {
029
030  private final Set<UnionValue> values = new LinkedHashSet<>();
031
032  private Union(String name) {
033    super(name);
034  }
035
036  /**
037   * Creates a union type.
038   *
039   * <p>Typical usage:
040   * <pre class="listing"><code class="lang-java" data-lang="java">
041   * union("ConsList")
042   *   .value("Empty")
043   *   .value("Cons",
044   *      "head",
045   *      "tail")
046   * </code></pre>
047   * creates
048   * <pre class="listing"><code class="lang-golo" data-lang="golo">
049   * union ConsList = {
050   *   Empty
051   *   Cons = {head, tail}
052   * }
053   * </code></pre>
054   *
055   * @param name the name of the union.
056   */
057  public static Union union(String name) {
058    return new Union(name);
059  }
060
061  protected Union self() { return this; }
062
063  /**
064   * Adds a new value to this union.
065   */
066  public boolean addValue(UnionValue value) {
067    makeParentOf(value);
068    return values.add(value);
069  }
070
071  /**
072   * Adds a value according to the given argument.
073   *
074   * @see #addValue(UnionValue)
075   */
076  public boolean addElement(GoloElement<?> elt) {
077    if (elt instanceof UnionValue) {
078      return addValue((UnionValue) elt);
079    }
080    throw cantConvert("UnionValue", elt);
081  }
082
083  public Collection<UnionValue> getValues() {
084    return unmodifiableSet(values);
085  }
086
087  /**
088   * Adds a new value to this union.
089   *
090   * <p>Convenient fluent method to add a new value.
091   * <p>This is a builder method.
092   *
093   * @see #addValue(UnionValue)
094   * @see UnionValue#members(Object...)
095   */
096  public Union value(String name, Object... members) {
097    UnionValue value = new UnionValue(name);
098    value.members(members);
099    addValue(value);
100    return this;
101  }
102
103  /**
104   * {@inheritDoc}
105   */
106  @Override
107  public void accept(GoloIrVisitor visitor) {
108    visitor.visitUnion(this);
109  }
110
111  /**
112   * {@inheritDoc}
113   */
114  @Override
115  public List<GoloElement<?>> children() {
116    List<GoloElement<?>> children = new LinkedList<>(values);
117    return children;
118  }
119
120  /**
121   * {@inheritDoc}
122   */
123  @Override
124  protected void replaceElement(GoloElement<?> original, GoloElement<?> newElement) {
125    if (values.contains(original)) {
126      values.remove(original);
127    } else {
128      throw cantReplace(original, newElement);
129    }
130    addElement(newElement);
131  }
132}