File indexing completed on 2024-12-15 04:19:54
0001 package mso.generator.utils; 0002 0003 import java.util.ArrayList; 0004 import java.util.List; 0005 0006 import org.eclipse.jdt.annotation.Nullable; 0007 0008 public class Choice extends Type { 0009 0010 public final @Nullable Type commonType; 0011 public final List<Option> options = new ArrayList<Option>(); 0012 0013 public String[] getChoiceNames() { 0014 String n[] = new String[options.size()]; 0015 for (int i = 0; i < options.size(); ++i) { 0016 n[i] = options.get(i).type.name; 0017 } 0018 return n; 0019 } 0020 0021 Choice(TypeRegistry registry, String name, List<Struct> choices, 0022 boolean optional) { 0023 super(registry, name, getSize(choices)); 0024 Type common = null; 0025 for (Struct s : choices) { 0026 Option o = Option.parseOption(s, common); 0027 if (common != null && o.limitsType != common 0028 && !compareTypes(common, o.limitsType)) { 0029 throw new Error("Conflicting common type: " + common.name 0030 + " vs " + o.limitsType.name); 0031 } 0032 common = o.limitsType; 0033 options.add(o); 0034 } 0035 // check if the common type is the same 0036 for (Option o : options) { 0037 if (!compareTypes(common, o.limitsType)) { 0038 String types = ""; 0039 for (Option op : options) { 0040 types = types + " " + op.type.name; 0041 } 0042 System.err.println("The choice " + name 0043 + " has no common options for types" + types); 0044 common = null; 0045 break; 0046 } 0047 } 0048 if (common == null) { 0049 commonType = null; 0050 return; 0051 } 0052 // Check if the limitations are distinctive 0053 // if limitation on an earlier option are a subset of a later 0054 // limitation, 0055 // then then the limitations cannot be used for making the choice 0056 // so must make sure that earlier sets of limitations are not 0057 // subsets of later limitations. 0058 for (int i = 0; i < options.size(); ++i) { 0059 int last = (optional) ? options.size() : options.size() - 1; 0060 for (int j = i + 1; j < last; ++j) { 0061 // the double negation is important: we cannot be sure that it 0062 // is a subset 0063 // we must be sure that it is not a subset 0064 Option a = options.get(i); 0065 Option b = options.get(j); 0066 if (!noOverlap(a.lim, b.lim)) { 0067 System.err.println("Options " + a.type.name + " and " 0068 + b.type.name + " have overlap."); 0069 common = null; 0070 } 0071 } 0072 } 0073 0074 // if the options are distinctive we can use them 0075 commonType = common; 0076 0077 if (!optional && common != null) { 0078 // remove options that are present in all options 0079 removeNonDistinctiveLimitations(options); 0080 } 0081 } 0082 0083 // if all choices have equal size, return that sizes, else return -1 0084 private static int getSize(List<Struct> choices) { 0085 int size = -1; 0086 for (Struct s : choices) { 0087 if (size == -1) { 0088 size = s.size; 0089 } 0090 if (s.size != size) { 0091 return -1; 0092 } 0093 } 0094 return size; 0095 } 0096 0097 /** 0098 * Return true if not all of the limitations in a are sure to be present in 0099 * b. Err on the side of safety: if unsure return false; 0100 */ 0101 private static boolean noOverlap(Lim a, Lim b) { 0102 if (a.limitations == null && a.lims == null) 0103 return false; 0104 if (a.limitations != null) { 0105 if (!noOverlap(a.limitations, b)) { 0106 return false; 0107 } 0108 } 0109 if (a.lims != null) { 0110 for (Lim sa : a.lims) { 0111 if (!noOverlap(sa, b)) { 0112 return false; 0113 } 0114 } 0115 } 0116 return true; 0117 } 0118 0119 private static boolean noOverlap(Limitation a[], Lim b) { 0120 if (b.limitations == null && b.lims == null) 0121 return false; 0122 if (b.limitations != null) { 0123 if (!noOverlap(a, b.limitations)) { 0124 return false; 0125 } 0126 } 0127 if (b.lims != null) { 0128 for (Lim sb : b.lims) { 0129 if (!noOverlap(a, sb)) { 0130 return false; 0131 } 0132 } 0133 } 0134 return true; 0135 } 0136 0137 /** 0138 * Return true if sure that a and b define value spaces with no overlap 0139 */ 0140 private static boolean noOverlap(Limitation a[], Limitation b[]) { 0141 for (int i = 0; i < a.length; ++i) { 0142 for (int j = 0; j < b.length; ++j) { 0143 if (a[i].name.equals(b[j].name) 0144 && noOverlap(a[i].value, b[j].value)) { 0145 return true; 0146 } 0147 } 0148 } 0149 return false; 0150 } 0151 0152 private static boolean noOverlap(@Nullable String a, @Nullable String b) { 0153 if (a == null || b == null) 0154 return false; 0155 String[] avalues = a.split("\\|"); 0156 String[] bvalues = b.split("\\|"); 0157 for (int i = 0; i < avalues.length; ++i) { 0158 for (int j = 0; j < bvalues.length; ++j) { 0159 if (avalues[i].equals(bvalues[j])) { 0160 return false; 0161 } 0162 } 0163 } 0164 return true; 0165 } 0166 0167 private static boolean compareMembers(Member a, Member b) { 0168 if (a.isArray != b.isArray) 0169 return false; 0170 if (a.type() != b.type()) 0171 return false; 0172 if (a.isOptional != b.isOptional) 0173 return false; 0174 return true; 0175 } 0176 0177 private static boolean structsWithSameMembers(@Nullable Type a, Type b) { 0178 if (a instanceof Struct && b instanceof Struct) { 0179 Struct as = (Struct) a; 0180 Struct bs = (Struct) b; 0181 if (as.members.size() != bs.members.size()) { 0182 return false; 0183 } 0184 for (int i = 0; i < as.members.size(); ++i) { 0185 if (!compareMembers(as.members.get(i), bs.members.get(i))) { 0186 return false; 0187 } 0188 } 0189 return true; 0190 } 0191 return false; 0192 } 0193 0194 private static boolean compareTypes(@Nullable Type a, Type b) { 0195 return a == b || structsWithSameMembers(a, b); 0196 } 0197 0198 private static void removeNonDistinctiveLimitations(List<Option> options) { 0199 final Lim a = options.get(0).lim; 0200 final Limitation limitations[] = a.limitations; 0201 if (limitations != null) { 0202 for (int i = 0; i < limitations.length; ++i) { 0203 Limitation l = limitations[i]; 0204 boolean common = true; 0205 for (int j = 1; j < options.size(); ++j) { 0206 common = common 0207 && options.get(j).lim.containsCommonLimitation(l); 0208 } 0209 if (common) { 0210 for (int j = 0; j < options.size(); ++j) { 0211 options.get(j).lim.removeLimitation(l); 0212 } 0213 i = 0; 0214 } 0215 } 0216 } 0217 } 0218 }