001package org.clafer.ast; 002 003import java.util.ArrayList; 004import java.util.Collections; 005import java.util.List; 006import org.clafer.common.Check; 007 008/** 009 * A Clafer in the model. A Clafer represents both the set and the type. A 010 * concrete is either abstract, concrete, or primitive. 011 * 012 * @author jimmy 013 */ 014public abstract class AstClafer implements AstVar { 015 016 private final String name; 017 // The topmost Clafer in the type hierarchy. 018 protected final AstAbstractClafer claferClafer; 019 private AstAbstractClafer superClafer; 020 private AstRef ref; 021 private Card groupCard = new Card(); 022 private final List<AstConcreteClafer> children = new ArrayList<>(); 023 private final List<AstConstraint> constraints = new ArrayList<>(); 024 025 AstClafer(String name, AstAbstractClafer claferClafer) { 026 this.name = Check.notNull(name); 027 this.claferClafer = claferClafer; 028 } 029 030 /** 031 * Returns the name of the Clafer. 032 * 033 * @return the name of the Clafer 034 */ 035 @Override 036 public String getName() { 037 return name; 038 } 039 040 /** 041 * Check if this Clafer has a supertype. Every Clafer has a supertype except 042 * for the special Clafer at the root of the type hierarchy. 043 * 044 * @return {@code true} if and only if this Clafer has a supertype, 045 * {@code false} otherwise 046 */ 047 public boolean hasSuperClafer() { 048 return superClafer != null; 049 } 050 051 /** 052 * Returns the supertype of this Clafer. 053 * 054 * @return the supertype of this Clafer 055 */ 056 public AstAbstractClafer getSuperClafer() { 057 return superClafer; 058 } 059 060 /** 061 * Set the supertype of this Clafer. 062 * 063 * @param superClafer the supertype 064 * @return this Clafer 065 */ 066 public AstClafer extending(AstAbstractClafer superClafer) { 067 Check.notNull(superClafer); 068 if (hasSuperClafer()) { 069 // Allowed to specialize. 070 if (!AstUtil.getSupers(superClafer).contains(getSuperClafer())) { 071 throw new IllegalArgumentException(this + " already has a super clafer"); 072 } 073 getSuperClafer().removeSub(this); 074 } 075 superClafer.addSub(this); 076 this.superClafer = superClafer; 077 return this; 078 } 079 080 /** 081 * Check if this Clafer references another Clafer. 082 * 083 * @return {@code true} if and only if this Clafer references another 084 * Clafer, {@code false} otherwise 085 */ 086 public boolean hasRef() { 087 return ref != null; 088 } 089 090 /** 091 * Returns this Clafer's reference 092 * 093 * @return this Clafer's reference 094 */ 095 public AstRef getRef() { 096 return ref; 097 } 098 099 /** 100 * Set this Clafer's reference to target type. 101 * 102 * @param targetType the type to refer to 103 * @return this Clafer 104 */ 105 public AstClafer refTo(AstClafer targetType) { 106 if (hasRef()) { 107 throw new IllegalArgumentException(this + " already has a ref"); 108 } 109 this.ref = new AstRef(this, targetType, false); 110 return this; 111 } 112 113 /** 114 * Set this Clafer's reference to target type along with a uniqueness 115 * constraint. 116 * 117 * @param targetType the type to refer to 118 * @return this Clafer 119 */ 120 public AstClafer refToUnique(AstClafer targetType) { 121 if (hasRef()) { 122 throw new IllegalArgumentException(this + " already has a ref"); 123 } 124 this.ref = new AstRef(this, targetType, true); 125 return this; 126 } 127 128 /** 129 * Returns this Clafer's group cardinality. 130 * 131 * @return this Clafer's group cardinality 132 */ 133 public Card getGroupCard() { 134 return groupCard; 135 } 136 137 /** 138 * Set this Clafer's group cardinality. 139 * 140 * @param groupCard the group cardinality 141 * @return this Clafer 142 */ 143 public AstClafer withGroupCard(Card groupCard) { 144 this.groupCard = Check.notNull(groupCard); 145 return this; 146 } 147 148 /** 149 * Set this Clafer's low group cardinality and set the high group 150 * cardinality to unbounded. 151 * 152 * @param low the low group cardinality 153 * @return this Clafer 154 */ 155 public AstClafer withGroupCard(int low) { 156 return withGroupCard(new Card(low)); 157 } 158 159 /** 160 * Set this Clafer's group cardinality. 161 * 162 * @param low the low group cardinality 163 * @param high the high group cardinality 164 * @return this Clafer 165 */ 166 public AstClafer withGroupCard(int low, int high) { 167 return withGroupCard(new Card(low, high)); 168 } 169 170 /** 171 * Checks if this Clafer has any concrete children. 172 * 173 * @return {@code true} if and only if this Clafer has children, 174 * {@code false} otherwise 175 */ 176 public boolean hasChildren() { 177 return !children.isEmpty(); 178 } 179 180 /** 181 * Returns this Clafer's concrete children 182 * 183 * @return this Clafer's concrete children 184 */ 185 public List<AstConcreteClafer> getChildren() { 186 return Collections.unmodifiableList(children); 187 } 188 189 /** 190 * Add a new concrete child under this Clafer. 191 * 192 * @param name the name of the child 193 * @return the new child 194 */ 195 public AstConcreteClafer addChild(String name) { 196 AstConcreteClafer child = new AstConcreteClafer(name, this, claferClafer); 197 children.add(child); 198 return child.extending(claferClafer); 199 } 200 201 /** 202 * Checks if this Clafer has any constraints. 203 * 204 * @return {@code true} if and only if this Clafer has constraints, 205 * {@code false} otherwise 206 */ 207 public boolean hasConstraints() { 208 return !constraints.isEmpty(); 209 } 210 211 /** 212 * Returns this Clafer's constraints. 213 * 214 * @return this Clafer's constraints 215 */ 216 public List<AstConstraint> getConstraints() { 217 return Collections.unmodifiableList(constraints); 218 } 219 220 /** 221 * Add a new constraint under this Clafer. 222 * 223 * @param expr a tautology 224 * @return the constraint 225 */ 226 public AstConstraint addConstraint(AstBoolExpr expr) { 227 AstConstraint constraint = new AstConstraint(this, expr); 228 constraints.add(constraint); 229 return constraint; 230 } 231 232 /** 233 * {@inheritDoc} 234 */ 235 @Override 236 public boolean equals(Object obj) { 237 return this == obj; 238 } 239 240 /** 241 * {@inheritDoc} 242 */ 243 @Override 244 public int hashCode() { 245 return getName().hashCode(); 246 } 247 248 /** 249 * {@inheritDoc} 250 */ 251 @Override 252 public String toString() { 253 return getName(); 254 } 255}