/src/org/ooc/frontend/model/Type.java

http://github.com/nddrylliog/ooc · Java · 494 lines · 392 code · 90 blank · 12 comment · 137 complexity · 452e678a1c3402fc94ebaf0d8f33923f MD5 · raw file

  1. package org.ooc.frontend.model;
  2. import java.io.IOException;
  3. import java.util.Iterator;
  4. import org.ooc.frontend.Visitor;
  5. import org.ooc.frontend.model.interfaces.MustBeResolved;
  6. import org.ooc.frontend.model.tokens.Token;
  7. import org.ooc.middle.OocCompilationError;
  8. import org.ooc.middle.hobgoblins.Resolver;
  9. public class Type extends Node implements MustBeResolved {
  10. public static class Classification {
  11. public static final int POINTER = 1;
  12. public static final int NUMBER = 2;
  13. public static final int CLASS = 4;
  14. }
  15. private boolean groundTypeChecked = false;
  16. protected String name, namespace;
  17. protected int pointerLevel;
  18. protected int referenceLevel;
  19. private Declaration ref;
  20. private boolean isArray = false;
  21. private Expression arraySize = null;
  22. protected NodeList<Access> typeParams;
  23. private boolean isConst = false;
  24. //private String origin;
  25. private static Type voidType = null;
  26. public static Type getVoid() {
  27. if(voidType == null) {
  28. voidType = new Type("Void", Token.defaultToken);
  29. }
  30. return voidType;
  31. }
  32. public Type(String name, Token startToken) {
  33. this(name, 0, startToken);
  34. }
  35. public Type(String name, int pointerLevel, Token startToken) {
  36. this(name, pointerLevel, 0, startToken);
  37. }
  38. public Type(String name, int pointerLevel, int referenceLevel, Token startToken) {
  39. super(startToken);
  40. this.name = name;
  41. this.pointerLevel = pointerLevel;
  42. this.referenceLevel = referenceLevel;
  43. this.typeParams = new NodeList<Access>(startToken);
  44. this.namespace = null;
  45. //StringWriter sw = new StringWriter();
  46. //new Exception().printStackTrace(new PrintWriter(sw));
  47. //this.origin = sw.toString();
  48. }
  49. public String getNamespace() {
  50. return namespace;
  51. }
  52. public void setNamespace(String namespace) {
  53. this.namespace = namespace;
  54. }
  55. public NodeList<Access> getTypeParams() {
  56. return typeParams;
  57. }
  58. public String getName() {
  59. return name;
  60. }
  61. public void setName(String name) {
  62. this.name = name;
  63. }
  64. public void setPointerLevel(int pointerLevel) {
  65. this.pointerLevel = pointerLevel;
  66. }
  67. public int getPointerLevel() {
  68. return pointerLevel;
  69. }
  70. public void setReferenceLevel(int referenceLevel) {
  71. this.referenceLevel = referenceLevel;
  72. }
  73. public int getReferenceLevel() {
  74. return referenceLevel;
  75. }
  76. public Declaration getRef() {
  77. return ref;
  78. }
  79. public void setRef(Declaration ref) {
  80. this.ref = ref;
  81. }
  82. public boolean isConst() {
  83. return isConst;
  84. }
  85. public void setConst(boolean isConst) {
  86. this.isConst = isConst;
  87. }
  88. public void accept(Visitor visitor) throws IOException {
  89. visitor.visit(this);
  90. }
  91. public boolean hasChildren() {
  92. return true;
  93. }
  94. public void acceptChildren(Visitor visitor) throws IOException {
  95. if(arraySize != null) arraySize.accept(visitor);
  96. typeParams.accept(visitor);
  97. }
  98. @Override
  99. public String toString() {
  100. StringBuilder sb = new StringBuilder();
  101. if(isConst) sb.append("const ");
  102. if(namespace != null) sb.append(namespace + " ");
  103. sb.append(name);
  104. for(int i = 0; i < pointerLevel; i++) {
  105. if(isArray) sb.append("[]");
  106. else sb.append('*');
  107. }
  108. for(int i = 0; i < referenceLevel; i++) {
  109. sb.append('@');
  110. }
  111. if(!typeParams.isEmpty()) {
  112. sb.append('<');
  113. Iterator<Access> iter = typeParams.iterator();
  114. while(iter.hasNext()) {
  115. Access element = iter.next();
  116. if(element instanceof TypeAccess) {
  117. sb.append(element.toString());
  118. } else if(element instanceof VariableAccess) {
  119. sb.append(((VariableAccess) element).getName());
  120. } else if(element instanceof FunctionCall) {
  121. sb.append(((FunctionCall) element).getName());
  122. }
  123. if(iter.hasNext()) sb.append(", ");
  124. }
  125. sb.append('>');
  126. }
  127. return sb.toString();
  128. }
  129. public String getMangledName() {
  130. if(pointerLevel == 0) {
  131. return name;
  132. }
  133. StringBuilder sb = new StringBuilder();
  134. sb.append(name);
  135. for(int i = 0; i < pointerLevel + referenceLevel; i++) {
  136. sb.append("__star");
  137. }
  138. return sb.toString();
  139. }
  140. public boolean isVoid() {
  141. return (name.equals("void") || name.equals("Void")) && isFlat();
  142. }
  143. public boolean isFlat() {
  144. return pointerLevel == 0 && referenceLevel == 0 && !(ref instanceof ClassDecl);
  145. }
  146. @Override
  147. public boolean replace(Node oldie, Node kiddo) {
  148. if(oldie == ref) {
  149. ref = (Declaration) kiddo;
  150. return true;
  151. }
  152. return false;
  153. }
  154. @Override
  155. public boolean equals(Object obj) {
  156. if(obj instanceof Type) {
  157. Type type = (Type) obj;
  158. boolean result = name.equals(type.name) && pointerLevel == type.getPointerLevel();
  159. return result;
  160. }
  161. return super.equals(obj);
  162. }
  163. public Response resolve(NodeList<Node> stack, Resolver res, boolean fatal) {
  164. if(ref != null) return Response.OK;
  165. if(namespace == null) {
  166. // no namespace? global namespace.
  167. ref = stack.getModule().getType(name);
  168. } else {
  169. // look for this namespace.
  170. NamespaceDecl ns = stack.getModule().getNamespace(namespace);
  171. if(ns == null) {
  172. throw new OocCompilationError(this, stack, namespace + ": This Namespace Does Not Exist.");
  173. }
  174. ref = ns.resolveType(name);
  175. if(ref == null) {
  176. throw new OocCompilationError(this, stack, "Couldn't resolve type " + name + " in namespace " + namespace + "!");
  177. }
  178. }
  179. if(ref == null && name.equals("This")) {
  180. int index = stack.find(TypeDecl.class);
  181. if(index == -1) {
  182. throw new OocCompilationError(this, stack, "Using 'This' outside a type definition is meaningless.");
  183. }
  184. TypeDecl typeDecl = (TypeDecl) stack.get(index);
  185. name = typeDecl.getName();
  186. ref = typeDecl;
  187. return Response.OK;
  188. }
  189. if(ref == null) {
  190. TypeParam param = getTypeParam(stack, name);
  191. if(param != null) {
  192. ref = param;
  193. return Response.OK;
  194. }
  195. }
  196. if(ref == null && fatal) {
  197. if(res.params.veryVerbose) {
  198. Thread.dumpStack();
  199. throw new OocCompilationError(this, stack, "Couldn't resolve type "
  200. +getName()+". btw, stack = "+stack.toString(true));
  201. }
  202. throw new OocCompilationError(this, stack, "Couldn't resolve type "
  203. +getName());
  204. }
  205. if(ref != null) {
  206. if(ref instanceof TypeDecl) {
  207. TypeDecl tDecl = (TypeDecl) ref;
  208. if(!tDecl.getTypeParams().isEmpty()) {
  209. if(getTypeParams().size() != tDecl.getTypeParams().size()) {
  210. throw new OocCompilationError(this, stack,
  211. "Missing type parameters for "+this+". " +
  212. "It should match "+tDecl.getInstanceType());
  213. }
  214. }
  215. }
  216. }
  217. if(ref == null) {
  218. // not resolved? loop.
  219. return Response.LOOP;
  220. } else if(!groundTypeChecked) {
  221. // not checked for ground type? loop.
  222. checkGroundType(stack, res, fatal);
  223. if(!groundTypeChecked) return Response.LOOP;
  224. }
  225. return Response.OK;
  226. }
  227. public boolean isResolved() {
  228. return ref != null || name.length() == 0; // empty name = any type.
  229. }
  230. public void setArray(boolean isArray) {
  231. this.isArray = isArray;
  232. }
  233. public boolean isArray() {
  234. return isArray;
  235. }
  236. public Type getGroundType() {
  237. return getGroundType(null);
  238. }
  239. public void checkGroundType(NodeList<Node> stack, Resolver res, boolean fatal) {
  240. if(!(this.ref instanceof CoverDecl)) {
  241. groundTypeChecked = true;
  242. } else {
  243. Declaration fromRef = this.ref;
  244. CoverDecl coverDecl = (CoverDecl) fromRef;
  245. Type fromType = coverDecl.getFromType();
  246. while(fromType != null) {
  247. if(this == fromType) {
  248. throw new OocCompilationError(this, stack, "Type defined in terms of itself: "+this);
  249. }
  250. fromRef = fromType.getRef();
  251. if(fromRef == null) {
  252. fromType.resolve(stack, res, false); // Don't ask me why, but this `false` is VERY important!
  253. }
  254. if(fromRef instanceof CoverDecl) {
  255. coverDecl = (CoverDecl) fromRef;
  256. fromType = coverDecl.getFromType();
  257. continue;
  258. }
  259. break;
  260. }
  261. }
  262. groundTypeChecked = true;
  263. }
  264. public Type getGroundType(Resolver res) {
  265. if(ref instanceof CoverDecl) {
  266. CoverDecl coverDecl = (CoverDecl) ref;
  267. Type fromType = coverDecl.getFromType();
  268. if(fromType != null && !name.equals(fromType.getName())) {
  269. Type rawType = coverDecl.getFromType().getGroundType(res);
  270. Type groundType = new Type(
  271. rawType.name,
  272. rawType.getPointerLevel() + pointerLevel,
  273. rawType.getReferenceLevel() + referenceLevel,
  274. startToken
  275. );
  276. groundType.setArray(isArray);
  277. if(res == null) {
  278. groundType.ref = ref;
  279. } else {
  280. groundType.resolve(res);
  281. }
  282. return groundType;
  283. }
  284. }
  285. return this;
  286. }
  287. public Type getFlatType(Resolver res) {
  288. Type returnType = this;
  289. while(returnType.ref instanceof CoverDecl) {
  290. CoverDecl coverDecl = (CoverDecl) returnType.ref;
  291. Type fromType = coverDecl.getFromType();
  292. if(fromType == null) break;
  293. if(fromType.referenceLevel <= 0) break;
  294. returnType = new Type(fromType.name, fromType.pointerLevel - 1,
  295. returnType.referenceLevel - 1, fromType.startToken);
  296. returnType.resolve(res);
  297. }
  298. return returnType;
  299. }
  300. public boolean fitsIn(Type innerType) {
  301. if (equals(innerType)) return true;
  302. if (getClassification() == innerType.getClassification()) return true;
  303. return false;
  304. }
  305. public int getClassification() {
  306. if(!isFlat()) return Classification.POINTER;
  307. if(name.equals("Int") || name.equals("UInt") || name.equals("Short")
  308. || name.equals("UShort")|| name.equals("Long") || name.equals("ULong")
  309. || name.equals("LLong") || name.equals("ULLong")|| name.equals("Char")
  310. || name.equals("UChar") || name.equals("Int8") || name.equals("Int16")
  311. || name.equals("Int32") || name.equals("Int64") || name.equals("UInt8")
  312. || name.equals("UInt16")|| name.equals("UInt32")|| name.equals("UInt64")
  313. || name.equals("SizeT") || name.equals("Float") || name.equals("Double")
  314. ) return Classification.NUMBER;
  315. return Classification.CLASS;
  316. }
  317. public void resolve(Resolver res) {
  318. ref = res.module.getType(name);
  319. }
  320. public boolean isSuperOf(Type type) {
  321. if(type == null) return false;
  322. if(this.equals(type)) return false;
  323. if(name.length() == 0 || type.name.length() == 0) return false;
  324. if(type.getRef() instanceof TypeDecl) {
  325. TypeDecl typeDecl = (TypeDecl) type.getRef();
  326. if(typeDecl.getSuperRef() != null) {
  327. Type superType = typeDecl.getSuperRef().getType();
  328. if(superType.getName().equals(this.getName())) {
  329. return true;
  330. }
  331. return isSuperOf(superType);
  332. }
  333. }
  334. return false;
  335. }
  336. public String getHierarchyRepr() {
  337. String repr = name;
  338. Type t = this;
  339. while(t.ref != null) {
  340. if(!(t.ref instanceof TypeDecl)) break;
  341. TypeDecl typeDecl = (TypeDecl) t.ref;
  342. if(typeDecl.getSuperRef() == null) break;
  343. t = typeDecl.getSuperRef().getType();
  344. repr += ":" + t;
  345. }
  346. return repr;
  347. }
  348. @Override
  349. public Type clone() {
  350. Type clone = new Type(name, pointerLevel, referenceLevel, startToken);
  351. clone.ref = ref;
  352. clone.isArray = isArray;
  353. clone.arraySize = arraySize;
  354. clone.isConst = isConst;
  355. clone.typeParams.addAll(typeParams);
  356. return clone;
  357. }
  358. public boolean isGeneric() {
  359. return ref instanceof TypeParam;
  360. }
  361. public boolean isGenericRecursive() {
  362. return isGeneric() || !typeParams.isEmpty();
  363. }
  364. public Expression getArraySize() {
  365. return arraySize;
  366. }
  367. public void setArraySize(Expression arraySize) {
  368. this.arraySize = arraySize;
  369. }
  370. public boolean softEquals(Type type, Resolver res) {
  371. if(type == null) return false;
  372. // that's a ugly hack - but on the other hand, we can't expect generics
  373. // to work properly on opeartor overloads, for example
  374. if(name.equals("uint8_t")) return false;
  375. //if(isGenericRecursive()) return false;
  376. //resolve(res);
  377. if(equals(type)) {
  378. return true;
  379. }
  380. Declaration ref = type.getRef();
  381. if(ref instanceof TypeDecl) {
  382. TypeDecl typeDecl = (TypeDecl) ref;
  383. if(typeDecl.getSuperType() != null) {
  384. Type subType = typeDecl.getSuperType();
  385. return softEquals(subType, res);
  386. }
  387. }
  388. if( getClassification() == Classification.NUMBER
  389. && type.getClassification() == Classification.NUMBER) return true;
  390. return false;
  391. }
  392. public boolean isPrefixed() {
  393. return (ref instanceof ClassDecl || (ref instanceof CoverDecl && !((CoverDecl) ref).isExtern()));
  394. }
  395. public String getUnderName() {
  396. if(isPrefixed()) return ((TypeDecl) ref).getUnderName();
  397. return getName();
  398. }
  399. public Type dereference() {
  400. Type clone = clone();
  401. clone.setPointerLevel(getPointerLevel() - 1);
  402. return clone;
  403. }
  404. }