00001
00006 package edu.mit.csail.sdg.squander.spec;
00007 import java.lang.reflect.Array;
00008 import java.util.ArrayList;
00009 import java.util.Arrays;
00010 import java.util.Collections;
00011 import java.util.LinkedList;
00012 import java.util.List;
00013
00014 import edu.mit.csail.sdg.squander.parser.JFSLParserException;
00015 import edu.mit.csail.sdg.squander.utils.ReflectionUtils;
00016
00017
00018 public interface JType {
00019
00021 public boolean isUnary();
00022
00024 public int arity();
00025
00026 public String name();
00027 public String simpleName();
00028
00030 public JType.Unary domain();
00031
00033 public JType.Unary range();
00034
00036 public List<JType.Unary> tuple();
00037
00039 public JType projection(int... columns);
00040
00042 public JType.Unary projection(int column);
00043 public JType projectionFrom(int start);
00044 public JType projectionFromTo(int start, int end);
00045
00047 public JType transpose();
00048
00053 public JType union(JType type);
00054
00059 public JType difference(JType type);
00060
00065 public JType intersection(JType type);
00066
00071 public JType product(JType that);
00072
00077 public JType join(JType type);
00078
00083 public boolean isInteger();
00084 public boolean isBoolean();
00085 public boolean isSubtypeOf(JType that);
00086
00087
00088
00089
00090
00091 @SuppressWarnings("unchecked")
00092 public static final class Factory {
00093 public static final Factory instance = new Factory();
00094
00095 private Factory() {}
00096
00097 public JType newJType(List<JType.Unary> tuple) {
00098 assert tuple.size() > 0;
00099 if (tuple.size() == 1)
00100 return tuple.get(0);
00101 else
00102 return new JType.Tuple(tuple);
00103 }
00104
00105 public JType newJType(Class<?> ... classes) {
00106 List<JType.Unary> tuple = new LinkedList<Unary>();
00107 for (Class<?> cls : classes)
00108 tuple.add(newJType(cls));
00109 return newJType(tuple);
00110 }
00111
00112 public JType.Unary newJType(Class cls) {
00113 Unary[] typeParams = new Unary[cls.getTypeParameters().length];
00114 for (int i = 0; i < typeParams.length; i++)
00115 typeParams[i] = JType.Factory.instance.newJType(Object.class);
00116 return newJType(cls, typeParams);
00117 }
00118
00119 public JType.Unary newJType(Class cls, Class[] typeParams) {
00120 if (typeParams == null || typeParams.length == 0)
00121 return newJType(cls);
00122 JType.Unary[] jtypeParams = new JType.Unary[typeParams.length];
00123 for (int i = 0; i < typeParams.length; i++)
00124 jtypeParams[i] = JField.convertToJType(typeParams[i]);
00125 return newJType(cls, jtypeParams);
00126 }
00127
00128 public JType.Unary newJType(Class cls, JType.Unary[] typeParams) {
00129 if (typeParams == null || typeParams.length != cls.getTypeParameters().length)
00130 return newJType(cls);
00131 else
00132 return new JType.Unary(cls, typeParams);
00133 }
00134
00135 public JType.Unary integerType() { return newJType(int.class); }
00136 public JType.Unary booleanType() { return newJType(boolean.class); }
00137 public JType.Unary stringType() { return newJType(String.class); }
00138 public JType.Unary throwableType() { return newJType(Throwable.class); }
00139 public JType.Unary objectType() { return newJType(Object.class); }
00140
00141 }
00142
00143
00144
00145
00146
00147 @SuppressWarnings("unchecked")
00148 public static abstract class AbstractJType implements JType {
00149 protected static final JType.Factory factory = Factory.instance;
00150
00151 @Override public final JType difference(JType type) { return difference(this, type); }
00152 @Override public final JType intersection(JType type) { return intersection(this, type); }
00153 @Override public final JType join(JType type) { return join(this, type); }
00154 @Override public final JType product(JType that) { return product(this, that); }
00155 @Override public final JType union(JType type) { return union(this, type); }
00156 @Override public final boolean isSubtypeOf(JType that) { return isSubtypeof(this, that); }
00157
00158 @Override
00159 public String name() {
00160 String name = "[";
00161 for (int i = 0; i < arity(); i++) {
00162 if (i > 0)
00163 name += ", ";
00164 name += tuple().get(i).name();
00165 }
00166 name += "]";
00167 return name;
00168 }
00169
00170 @Override
00171 public String simpleName() {
00172 String name = "[";
00173 for (int i = 0; i < arity(); i++) {
00174 if (i > 0)
00175 name += ", ";
00176 name += tuple().get(i).simpleName();
00177 }
00178 name += "]";
00179 return name;
00180 }
00181
00182 @Override
00183 public String toString() {
00184 return simpleName();
00185 }
00186
00187 @Override
00188 public final boolean equals(Object obj) {
00189 if (!(obj instanceof JType))
00190 return false;
00191 JType that = (JType) obj;
00192 return this.name().equals(that.name());
00193 }
00194
00195 @Override
00196 public final int hashCode() {
00197 return name().hashCode();
00198 }
00199
00200 private static JType difference(JType lhs, JType rhs) {
00201 checkArity(lhs, rhs);
00202 return lhs;
00203 }
00204
00205 private static JType intersection(JType lhs, JType rhs) {
00206 return lhs;
00207 }
00208
00209 private static JType join(JType lhs, JType rhs) {
00210 if (lhs.arity() == 0 || rhs.arity() == 0)
00211 throw new JFSLParserException("empty type join not allowed");
00212
00213 List<JType.Unary> result = new ArrayList<JType.Unary>();
00214 for (int i = 0; i < lhs.arity() - 1; i++)
00215 result.add(lhs.projection(i));
00216 for (int i = 1; i < rhs.arity(); i++)
00217 result.add(rhs.projection(i));
00218
00219 String msg = String.format("invalid join: %s . %s", lhs, rhs);
00220 Unary lhsJoinType = lhs.projection(lhs.arity() - 1);
00221 Unary rhsJoinType = rhs.projection(0);
00222 assert lhsJoinType.isSubtypeOf(rhsJoinType) || rhsJoinType.isSubtypeOf(lhsJoinType) : msg;
00223
00224 return factory.newJType(result);
00225 }
00226
00227 private static JType product(JType lhs, JType rhs) {
00228 List<JType.Unary> result = new ArrayList<Unary>(lhs.arity() + rhs.arity());
00229 result.addAll(lhs.tuple());
00230 result.addAll(rhs.tuple());
00231 return factory.newJType(result);
00232 }
00233
00234 private static JType union(JType lhs, JType rhs) {
00235 return lca(lhs, rhs);
00236 }
00237
00238 private static boolean isSubtypeof(JType lhs, JType rhs) {
00239 if (lhs.arity() != rhs.arity())
00240 return false;
00241 for (int i = 0; i < rhs.arity(); i++) {
00242 Class thisCls = lhs.projection(i).clazz();
00243 Class thatCls = rhs.projection(i).clazz();
00244 if (!thatCls.isAssignableFrom(thisCls))
00245 return false;
00246 }
00247 return true;
00248 }
00249
00250 private static JType lca(JType a, JType b) {
00251 checkArity(a, b);
00252 List<JType.Unary> result = new ArrayList<JType.Unary>(a.arity());
00253 for (int i = 0; i < a.arity(); i++) {
00254 Class lcaCls = ReflectionUtils.lca(a.projection(i).clazz(), b.projection(i).clazz());
00255 result.add(factory.newJType(lcaCls, a.projection(i).typeParams()));
00256 }
00257 return factory.newJType(result);
00258 }
00259
00260 private static void checkArity(JType a, JType b) {
00261 assert a != null && b != null;
00262 if (a.arity() != b.arity())
00263 throw new ArityMismatchException(a.arity(), b.arity(), "arities don't match in: \"" + a + "\" and \"" + b + "\"");
00264 }
00265
00266 }
00267
00268
00269
00270
00271
00272 @SuppressWarnings("unchecked")
00273 public static final class Unary extends AbstractJType {
00274 private final Class<?> clz;
00275 private JType.Unary[] typeParams = new JType.Unary[0];
00276
00277 private Unary(Class type, JType.Unary[] jTypes) {
00278 if (type == Integer.class)
00279 type = int.class;
00280 else if (type == Boolean.class)
00281 type = boolean.class;
00282 this.clz = type;
00283 this.typeParams = jTypes;
00284 }
00285
00286 private Unary(Class type) {
00287 this(type, new JType.Unary[0]);
00288 }
00289
00290 public Class clazz() { return clz; }
00291 public Unary[] typeParams() { return Arrays.copyOf(typeParams, typeParams.length); }
00292 void setTypeParams(Unary[] typeParams) { this.typeParams = typeParams; }
00293
00294 public Unary mkArray() {
00295 Class<?> arrCls = Array.newInstance(clz, 0).getClass();
00296 return JType.Factory.instance.newJType(arrCls);
00297 }
00298
00299 @Override public List<Unary> tuple() { return Collections.singletonList(this); }
00300 @Override public int arity() { return 1; }
00301 @Override public boolean isUnary() { return true; }
00302 @Override public JType transpose() { return this; }
00303 @Override public JType.Unary range() { return this; }
00304 @Override public JType.Unary domain() { return this; }
00305
00306 @Override public boolean isBoolean() { return clz == boolean.class; }
00307 @Override public boolean isInteger() { return clz == int.class; }
00308
00309 @Override
00310 public JType projection(int... columns) {
00311 assert columns.length == 1 && columns[0] == 0;
00312 return this;
00313 }
00314
00315 @Override
00316 public Unary projection(int column) {
00317 assert column == 0;
00318 return this;
00319 }
00320
00321 @Override
00322 public JType projectionFrom(int start) {
00323 assert start == 0;
00324 return this;
00325 }
00326
00327 @Override
00328 public JType projectionFromTo(int start, int end) {
00329 assert start == 0;
00330 assert end == 0;
00331 return this;
00332 }
00333
00334 public boolean isAssignableFrom(JType.Unary that) {
00335 if (that.clz == Null.class)
00336 return true;
00337 Class<?> c1 = ReflectionUtils.box(clz);
00338 Class<?> c2 = ReflectionUtils.box(that.clz);
00339 if (!c1.isAssignableFrom(c2))
00340 return false;
00341 if (typeParams.length != that.typeParams.length)
00342 return true;
00343 for (int i = 0; i < typeParams.length; i++)
00344 if (!typeParams[i].isAssignableFrom(that.typeParams[i]))
00345 return false;
00346 return true;
00347 }
00348
00349 public String name() {
00350 String name = clz.getName();
00351 if (typeParams.length > 0) {
00352 name += "<";
00353 for (int i = 0; i < typeParams.length; i++) {
00354 if (i > 0)
00355 name += ", ";
00356 name += typeParams[i].name();
00357 }
00358 name += ">";
00359 }
00360 return name;
00361 }
00362
00363 public String simpleName() {
00364 String name = clz.getSimpleName();
00365 if (typeParams.length > 0) {
00366 name += "<";
00367 for (int i = 0; i < typeParams.length; i++) {
00368 if (i > 0)
00369 name += ", ";
00370 name += typeParams[i].simpleName();
00371 }
00372 name += ">";
00373 }
00374 return name;
00375 }
00376
00377 @Override
00378 public String toString() {
00379 return simpleName();
00380 }
00381
00382 }
00383
00384
00385
00386
00387
00388 public static final class Tuple extends AbstractJType {
00389
00390 private final JType.Unary[] tuple;
00391
00392 private Tuple(List<JType.Unary> tuple) {
00393 assert tuple.size() > 1;
00394 this.tuple = new JType.Unary[tuple.size()];
00395 for (int i = 0; i < tuple.size(); i++)
00396 this.tuple[i] = tuple.get(i);
00397 }
00398
00399 @Override public List<Unary> tuple() { return Arrays.asList(tuple); }
00400 @Override public int arity() { return tuple.length; }
00401 @Override public boolean isUnary() { return false; }
00402 @Override public JType transpose() {
00403 List<Unary> lst = Arrays.asList(tuple);
00404 Collections.reverse(lst);
00405 return factory.newJType(lst);
00406 }
00407 @Override public JType.Unary range() { return tuple[arity() - 1]; }
00408 @Override public JType.Unary domain() { return tuple[0]; }
00409
00410 @Override public boolean isBoolean() { return false; }
00411 @Override public boolean isInteger() { return false; }
00412
00413 @Override
00414 public JType projection(int... columns) {
00415 List<Unary> result = new ArrayList<Unary>(columns.length);
00416 for (int col : columns) {
00417 result.add(projection(col));
00418 }
00419 return factory.newJType(result);
00420 }
00421
00422 @Override
00423 public Unary projection(int column) {
00424 assert column >=0 && column < arity();
00425 return tuple[column];
00426 }
00427
00428 @Override
00429 public JType projectionFrom(int start) {
00430 return projectionFromTo(start, arity() - 1);
00431 }
00432
00433 @Override
00434 public JType projectionFromTo(int start, int end) {
00435 int[] cols = new int[end - start + 1];
00436 for (int i = start; i <= end; i++)
00437 cols[i - start] = i;
00438 return projection(cols);
00439 }
00440
00441
00442
00443 }
00444
00445 }