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

http://github.com/nddrylliog/ooc · Java · 345 lines · 272 code · 66 blank · 7 comment · 65 complexity · 318a1a10237d3ba03024f0c34313cf56 MD5 · raw file

  1. package org.ooc.frontend.model;
  2. import java.io.IOException;
  3. import java.util.Iterator;
  4. import java.util.LinkedHashMap;
  5. import org.ooc.frontend.Visitor;
  6. import org.ooc.frontend.model.interfaces.Versioned;
  7. import org.ooc.frontend.model.tokens.Token;
  8. import org.ooc.middle.hobgoblins.Resolver;
  9. public abstract class TypeDecl extends Declaration implements Scope, Generic, Versioned {
  10. private VersionBlock version = null;
  11. protected NodeList<VariableDecl> variables;
  12. protected NodeList<FunctionDecl> functions;
  13. protected Type superType;
  14. protected Type instanceType;
  15. protected LinkedHashMap<String, TypeParam> typeParams;
  16. protected VariableDecl thisDecl;
  17. private boolean finishedGhosting = false;
  18. public TypeDecl(String name, Type superType, Module module, Token startToken) {
  19. super(name, startToken, module);
  20. this.superType = superType;
  21. this.variables = new NodeList<VariableDecl>(startToken);
  22. this.functions = new NodeList<FunctionDecl>(startToken);
  23. this.instanceType = new Type(name, startToken);
  24. instanceType.setRef(this);
  25. this.typeParams = new LinkedHashMap<String, TypeParam>();
  26. this.thisDecl = new VariableDecl(instanceType, "this", startToken, module);
  27. }
  28. public VariableDecl getThisDecl() {
  29. return thisDecl;
  30. }
  31. public Type getInstanceType() {
  32. return instanceType;
  33. }
  34. public boolean hasVariables() {
  35. return !variables.isEmpty();
  36. }
  37. public boolean hasFunctions() {
  38. return !functions.isEmpty();
  39. }
  40. public Iterable<VariableDecl> getVariables() {
  41. return variables;
  42. }
  43. public void getVariables(NodeList<VariableDecl> variables) {
  44. variables.addAll(this.variables);
  45. }
  46. public void addVariable(VariableDecl decl) {
  47. decl.setTypeDecl(this);
  48. variables.add(decl);
  49. }
  50. public Iterable<FunctionDecl> getFunctions() {
  51. return functions;
  52. }
  53. public Type getSuperType() {
  54. return superType;
  55. }
  56. public String getSuperName() {
  57. return superType == null ? "" : superType.getName();
  58. }
  59. public void setSuperType(Type superType) {
  60. this.superType = superType;
  61. }
  62. public FunctionDecl getFunction(FunctionCall call) {
  63. return getFunction(call.getName(), call.getSuffix(), call);
  64. }
  65. public FunctionDecl getFunction(String name, String suffix, FunctionCall call, boolean recursive) {
  66. return getFunction(name, suffix,call, recursive, 0, null);
  67. }
  68. public FunctionDecl getFunction(String name, String suffix, FunctionCall call,
  69. boolean recursive, int bestScoreParam, FunctionDecl bestMatchParam) {
  70. int bestScore = bestScoreParam;
  71. FunctionDecl bestMatch = bestMatchParam;
  72. for(FunctionDecl func : functions) {
  73. if(func.getName().equals(name) && (suffix == null || func.getSuffix().equals(suffix))) {
  74. if(call == null) return func;
  75. int score = call.getScore(func);
  76. if(score == -1) return null;
  77. if(score > bestScore) {
  78. bestScore = score;
  79. bestMatch = func;
  80. }
  81. }
  82. }
  83. if(recursive && getSuperRef() != null) return getSuperRef().getFunction(name, suffix, call, true, bestScore, bestMatch);
  84. return bestMatch;
  85. }
  86. public TypeDecl getSuperRef() {
  87. if(superType == null || superType.getRef() == null) return null;
  88. return (TypeDecl) superType.getRef();
  89. }
  90. public FunctionDecl getFunction(String name, String suffix, FunctionCall call) {
  91. return getFunction(name, suffix, call, true, 0, null);
  92. }
  93. public void getFunctions(NodeList<FunctionDecl> functions) {
  94. functions.addAll(this.functions);
  95. }
  96. public void addFunction(FunctionDecl decl) {
  97. decl.setTypeDecl(this);
  98. if(!decl.isStatic()) {
  99. Token tok = decl.getArguments().isEmpty() ? startToken : decl.getArguments().getFirst().startToken;
  100. decl.getArguments().add(0, new RegularArgument(getInstanceType(), "this", tok));
  101. } else {
  102. // static functions must have the same type params as the class
  103. decl.getTypeParams().putAll(typeParams);
  104. }
  105. if(decl.isSpecialFunc()) {
  106. FunctionDecl already = getFunction(decl.getName(), decl.getSuffix(), null);
  107. if(already != null) functions.remove(already);
  108. }
  109. functions.add(decl);
  110. }
  111. public void getFunctionsRecursive(NodeList<FunctionDecl> functions) {
  112. for(FunctionDecl decl: this.functions) {
  113. boolean already = false;
  114. for(FunctionDecl decl2: functions) {
  115. if(decl != decl2 && decl.sameProto(decl2)) {
  116. already = true;
  117. break;
  118. }
  119. }
  120. if(!already) functions.add(decl);
  121. }
  122. if(getSuperRef() != null) getSuperRef().getFunctionsRecursive(functions);
  123. }
  124. public VariableDecl getVariable(String name) {
  125. if(!finishedGhosting) {
  126. return null;
  127. }
  128. String realTypeParam = translateTypeParam(name);
  129. if(realTypeParam != null) {
  130. return getVariable(realTypeParam);
  131. }
  132. for(VariableDecl decl: variables) {
  133. if(decl.getName().equals(name)) {
  134. return decl;
  135. }
  136. }
  137. if(getSuperRef() != null) return getSuperRef().getVariable(name);
  138. return null;
  139. }
  140. private String translateTypeParam(String name) {
  141. // Iterator: class <T>
  142. // HashMap: class <K, V> extends Iterator<V>
  143. // V needs to be written at T
  144. // If needle is contained in our typeParams, we need to figure out where it's used
  145. if(typeParams.containsKey(name)) {
  146. String result = null;
  147. Iterator<Access> iter1 = getSuperType().getTypeParams().iterator();
  148. Iterator<String> iter2 = getSuperRef().getTypeParams().keySet().iterator();
  149. while(iter1.hasNext()) {
  150. Access a = iter1.next();
  151. String candidate = iter2.next();
  152. if(a instanceof VariableAccess) {
  153. VariableAccess va = (VariableAccess) a;
  154. if(va.getName().equals(name) && !name.equals(candidate)) {
  155. result = candidate;
  156. break;
  157. }
  158. }
  159. }
  160. return result;
  161. }
  162. return null;
  163. }
  164. public void acceptChildren(Visitor visitor) throws IOException {
  165. if(superType != null) superType.accept(visitor);
  166. for(TypeParam genType: typeParams.values()) {
  167. genType.accept(visitor);
  168. }
  169. variables.accept(visitor);
  170. functions.accept(visitor);
  171. instanceType.accept(visitor);
  172. }
  173. public boolean hasChildren() {
  174. return true;
  175. }
  176. @Override
  177. public boolean replace(Node oldie, Node kiddo) {
  178. return false;
  179. }
  180. @Override
  181. public TypeDecl getTypeDecl() {
  182. return this;
  183. }
  184. public Type getType() {
  185. return getInstanceType();
  186. }
  187. public String getVariablesRepr() {
  188. return variables.toString();
  189. }
  190. public String getFunctionsRepr() {
  191. return functions.toString();
  192. }
  193. public LinkedHashMap<String, TypeParam> getTypeParams() {
  194. return typeParams;
  195. }
  196. public void addTypeParam(TypeParam genType) {
  197. typeParams.put(genType.getName(), genType);
  198. genType.getArgument().setTypeDecl(this);
  199. instanceType.getTypeParams().add(new VariableAccess(genType.getName(), genType.startToken));
  200. variables.add(0, genType.getArgument());
  201. }
  202. @Override
  203. public Response resolve(NodeList<Node> stack, Resolver res, boolean fatal) {
  204. stack.push(this);
  205. ghostTypeParams(stack, res, fatal);
  206. stack.pop(this);
  207. return super.resolve(stack, res, fatal);
  208. }
  209. private Response ghostTypeParams(NodeList<Node> stack, Resolver res, boolean fatal) {
  210. if(finishedGhosting) return Response.OK;
  211. // remove ghost type arguments
  212. if(superType != null) {
  213. Response response = superType.resolve(stack, res, fatal);
  214. if(response != Response.OK) {
  215. stack.pop(this);
  216. return response;
  217. }
  218. Type sType = this.superType;
  219. while(sType != null) {
  220. TypeDecl sTypeRef = (TypeDecl) sType.getRef();
  221. if(sTypeRef == null) {
  222. // Need super type ref
  223. stack.pop(this);
  224. return Response.LOOP;
  225. }
  226. for(TypeParam typeArg: typeParams.values()) {
  227. for(TypeParam candidate: sTypeRef.getTypeParams().values()) {
  228. if(typeArg.getName().equals(candidate.getName())) {
  229. for(int i = 0; i < variables.size(); i++) {
  230. if(variables.get(i).getName().equals(typeArg.getName())) {
  231. variables.removeAt(i);
  232. break;
  233. }
  234. }
  235. }
  236. }
  237. }
  238. sType = sTypeRef.superType;
  239. }
  240. }
  241. finishedGhosting = true;
  242. return Response.OK;
  243. }
  244. @Override
  245. public String toString() {
  246. StringBuilder sB = new StringBuilder(getClass().getSimpleName());
  247. sB.append(' ');
  248. sB.append(name);
  249. if(!typeParams.isEmpty()) {
  250. sB.append('<');
  251. boolean isFirst = true;
  252. for(String typeParam: typeParams.keySet()) {
  253. if(isFirst) isFirst = false;
  254. else sB.append(", ");
  255. sB.append(typeParam);
  256. }
  257. sB.append('>');
  258. }
  259. return sB.toString();
  260. }
  261. public String getUnderName() {
  262. if(module != null && !isExtern())
  263. return module.getMemberPrefix() + getName();
  264. return getName();
  265. }
  266. public Module getModule() {
  267. return module;
  268. }
  269. public VersionBlock getVersion() {
  270. return version;
  271. }
  272. public void setVersion(VersionBlock block) {
  273. this.version = block;
  274. }
  275. @Override
  276. public void addToModule(Module module) {
  277. module.addType(this);
  278. }
  279. }