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.*; 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 private final Set<MacroInvocation> macroCalls = new LinkedHashSet<>(); 032 033 private Union(String name) { 034 super(name); 035 } 036 037 /** 038 * Creates a union type. 039 * 040 * <p>Typical usage: 041 * <pre class="listing"><code class="lang-java" data-lang="java"> 042 * union("ConsList") 043 * .value("Empty") 044 * .value("Cons", 045 * "head", 046 * "tail") 047 * </code></pre> 048 * creates 049 * <pre class="listing"><code class="lang-golo" data-lang="golo"> 050 * union ConsList = { 051 * Empty 052 * Cons = {head, tail} 053 * } 054 * </code></pre> 055 * 056 * @param name the name of the union. 057 */ 058 public static Union union(String name) { 059 return new Union(name); 060 } 061 062 protected Union self() { return this; } 063 064 /** 065 * Adds a new value to this union. 066 */ 067 public boolean addValue(UnionValue value) { 068 makeParentOf(value); 069 return values.add(value); 070 } 071 072 /** 073 * Adds a macro invocation to this union. 074 * 075 * <p>The macro is supposed to return a {@link UnionValue} when expanded. 076 * This allows decorator-like syntax on union values: 077 * <pre class="listing"><code class="lang-golo" data-lang="golo"> 078 * union Foo = { 079 * @someMacro 080 * Value = {a, b} 081 * 082 * @otherMacro 083 * OtherValue 084 * } 085 * </code></pre> 086 */ 087 public boolean addMacroInvocation(MacroInvocation macroCall) { 088 return macroCalls.add(makeParentOf(macroCall)); 089 } 090 091 /** 092 * Adds a value or a macro invocation according to the given argument. 093 * 094 * @see #addValue(UnionValue) 095 * @see #addMacroInvocation(MacroInvocation) 096 */ 097 public boolean addElement(GoloElement<?> elt) { 098 if (elt instanceof UnionValue) { 099 return addValue((UnionValue) elt); 100 } 101 if (elt instanceof MacroInvocation) { 102 return addMacroInvocation((MacroInvocation) elt); 103 } 104 throw cantConvert("UnionValue or MacroInvocation", elt); 105 } 106 107 public Collection<UnionValue> getValues() { 108 return unmodifiableSet(values); 109 } 110 111 /** 112 * Adds a new value to this union. 113 * 114 * <p>Convenient fluent method to add a new value. 115 * <p>This is a builder method. 116 * 117 * @see #addValue(UnionValue) 118 * @see UnionValue#members(Object...) 119 */ 120 public Union value(String name, Object... members) { 121 UnionValue value = new UnionValue(name); 122 value.members(members); 123 addValue(value); 124 return this; 125 } 126 127 /** 128 * {@inheritDoc} 129 */ 130 @Override 131 public void accept(GoloIrVisitor visitor) { 132 visitor.visitUnion(this); 133 } 134 135 /** 136 * {@inheritDoc} 137 */ 138 @Override 139 public List<GoloElement<?>> children() { 140 List<GoloElement<?>> children = new LinkedList<>(values); 141 children.addAll(macroCalls); 142 return children; 143 } 144 145 /** 146 * {@inheritDoc} 147 */ 148 @Override 149 protected void replaceElement(GoloElement<?> original, GoloElement<?> newElement) { 150 if (values.contains(original)) { 151 values.remove(original); 152 } else if (macroCalls.contains(original)) { 153 macroCalls.remove(original); 154 } else { 155 throw cantReplace(original, newElement); 156 } 157 addElement(newElement); 158 } 159}