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