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 gololang.FunctionReference;
014
015import java.util.ArrayList;
016import java.util.Iterator;
017import java.util.LinkedHashSet;
018import java.util.List;
019
020/**
021 * A container of top-level {@code GoloElement}.
022 *
023 * <p>This element must never be present in a tree.
024 */
025public final class ToplevelElements extends GoloElement<ToplevelElements> implements Iterable<GoloElement<?>> {
026
027  private final LinkedHashSet<GoloElement<?>> elements = new LinkedHashSet<>();
028
029  private ToplevelElements(GoloElement<?>... elements) {
030    for (GoloElement<?> e : elements) {
031      this.add(e);
032    }
033  }
034
035  /**
036   * Creates a top-level elements container.
037   */
038  public static ToplevelElements of(Object... elements) {
039    ToplevelElements tl = new ToplevelElements();
040    for (Object e : elements) {
041      tl.add(e);
042    }
043    return tl;
044  }
045
046  protected ToplevelElements self() { return this; }
047
048  public ToplevelElements add(Object element) {
049    if (element instanceof ToplevelElements) {
050      for (GoloElement<?> e : (ToplevelElements) element) {
051        this.add(e);
052      }
053    } else if (element instanceof ToplevelGoloElement && !(element instanceof Noop)) {
054      GoloElement<?> elt = (GoloElement<?>) element;
055      this.elements.add(makeParentOf(elt));
056    } else {
057      throw new IllegalArgumentException(element.toString());
058    }
059    return this;
060  }
061
062  public boolean isEmpty() {
063    return this.elements.isEmpty();
064  }
065
066  /**
067   * Map a golo function on the contained elements.
068   */
069  public ToplevelElements map(FunctionReference fun) throws Throwable {
070    ToplevelElements res = new ToplevelElements();
071    for (GoloElement<?> elt : this) {
072      res.add(fun.invoke(elt));
073    }
074    return res;
075  }
076
077  @Override
078  public Iterator<GoloElement<?>> iterator() {
079    return elements.iterator();
080  }
081
082  @Override
083  public List<GoloElement<?>> children() {
084    return new ArrayList<>(elements);
085  }
086
087  @Override
088  public void replaceElement(GoloElement<?> original, GoloElement<?> newElement) {
089    if (elements.contains(original)) {
090      elements.remove(original);
091      add(newElement);
092    } else {
093      throw cantReplace(original, newElement);
094    }
095  }
096
097  @Override
098  public void accept(GoloIrVisitor visitor) {
099    visitor.visitToplevelElements(this);
100  }
101}
102