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

http://github.com/nddrylliog/ooc · Java · 238 lines · 184 code · 49 blank · 5 comment · 51 complexity · 3acefe5707b9d3464d68c2b5defb6f11 MD5 · raw file

  1. package org.ooc.frontend.model;
  2. import java.io.IOException;
  3. import org.ooc.frontend.Visitor;
  4. import org.ooc.frontend.model.VersionNodes.VersionName;
  5. import org.ooc.frontend.model.tokens.Token;
  6. import org.ooc.middle.OocCompilationError;
  7. import org.ooc.middle.hobgoblins.Resolver;
  8. import org.ubi.CompilationFailedError;
  9. public class ClassDecl extends TypeDecl {
  10. public static final String DESTROY_FUNC_NAME = "__destroy__";
  11. public static final String DEFAULTS_FUNC_NAME = "__defaults__";
  12. public static final String LOAD_FUNC_NAME = "__load__";
  13. protected boolean hasRegisteredFinalizer = false;
  14. protected boolean isAbstract;
  15. protected OocDocComment comment;
  16. protected FunctionDecl defaultInit = null;
  17. public ClassDecl(String name, Type superType, boolean isAbstract, Module module, Token startToken) {
  18. super(name, (superType == null && !name.equals("Object")) ?
  19. new Type("Object", Token.defaultToken) : superType, module, startToken);
  20. this.isAbstract = isAbstract;
  21. addFunction(new FunctionDecl(LOAD_FUNC_NAME, "", false, true, false, false, startToken, module));
  22. addFunction(new FunctionDecl(DEFAULTS_FUNC_NAME, "", false, false, false, false, startToken, module));
  23. addFunction(new FunctionDecl(DESTROY_FUNC_NAME, "", false, false, false, false, startToken, module));
  24. }
  25. @Override
  26. public ClassDecl getSuperRef() {
  27. TypeDecl ref = super.getSuperRef();
  28. if(ref != null && !(ref instanceof ClassDecl)) {
  29. throw new CompilationFailedError(null, "Huh your class '"+getName()
  30. +"' in '"+(module != null ? module.getFullName() : "<unknown module>")
  31. +"' extends "+ref.getName()+" which isn't a ClassDecl but a "
  32. +ref.getClass().getSimpleName());
  33. }
  34. return (ClassDecl) ref;
  35. }
  36. public boolean isObjectClass() {
  37. return name.equals("Object");
  38. }
  39. public boolean isClassClass() {
  40. return name.equals("Class");
  41. }
  42. public boolean isRootClass() {
  43. return isObjectClass() || isClassClass();
  44. }
  45. public OocDocComment getComment() {
  46. return comment;
  47. }
  48. public void setComment(OocDocComment comment) {
  49. this.comment = comment;
  50. }
  51. public boolean isAbstract() {
  52. return isAbstract;
  53. }
  54. public void setAbstract(boolean isAbstract) {
  55. this.isAbstract = isAbstract;
  56. }
  57. @Override
  58. public void addFunction(FunctionDecl decl) {
  59. if(decl.getName().equals("init")) {
  60. addInit(decl);
  61. } else if(decl.getName().equals("new")) {
  62. FunctionDecl already = getFunction(decl.getName(), decl.getSuffix(), null);
  63. if(already != null) { functions.remove(already); }
  64. }
  65. super.addFunction(decl);
  66. }
  67. public void addDefaultInit() {
  68. if(!isAbstract && defaultInit == null) {
  69. FunctionDecl init = new FunctionDecl("init", "", false, false, false, false, startToken, module);
  70. addFunction(init);
  71. defaultInit = init;
  72. }
  73. }
  74. private void addInit(FunctionDecl decl) {
  75. if(defaultInit != null) {
  76. FunctionDecl newFunc = getFunction("new", "", null);
  77. functions.remove(defaultInit);
  78. functions.remove(newFunc);
  79. defaultInit = null;
  80. }
  81. FunctionDecl constructor = new FunctionDecl("new", decl.getSuffix(), false, true, false, false, decl.startToken, module);
  82. Type retType = getType().clone();
  83. retType.getTypeParams().clear();
  84. constructor.getArguments().addAll(decl.getArguments());
  85. constructor.getTypeParams().putAll(getTypeParams());
  86. VariableAccess thisTypeAccess = new VariableAccess(name, decl.startToken);
  87. thisTypeAccess.setRef(this);
  88. VariableAccess classAccess = new MemberAccess(thisTypeAccess, "class", decl.startToken);
  89. MemberCall allocCall = new MemberCall(classAccess, "alloc", "", decl.startToken);
  90. Cast cast = new Cast(allocCall, getType(), decl.startToken);
  91. VariableDecl vdfe = new VariableDecl(null, "this", cast, decl.startToken, module);
  92. constructor.getBody().add(new Line(vdfe));
  93. for(TypeParam genType: typeParams.values()) {
  94. VariableAccess e = new VariableAccess(genType.getName(), constructor.startToken);
  95. retType.getTypeParams().add(e);
  96. MemberAccess membAcc = new MemberAccess(genType.getName(), startToken);
  97. constructor.getBody().add(new Line(new Assignment(
  98. membAcc, e, constructor.startToken))
  99. );
  100. }
  101. constructor.setReturnType(retType);
  102. VariableAccess thisAccess = new VariableAccess(vdfe, decl.startToken);
  103. thisAccess.setRef(vdfe);
  104. MemberCall defaultsCall = new MemberCall(thisAccess, "__defaults__", "", decl.startToken);
  105. constructor.getBody().add(new Line(defaultsCall));
  106. FunctionCall initCall = new FunctionCall(decl, decl.startToken);
  107. for(Argument arg: constructor.getArguments()) {
  108. initCall.getArguments().add(new VariableAccess(arg, decl.startToken));
  109. }
  110. constructor.getBody().add(new Line(new MemberCall(thisAccess, initCall, decl.startToken)));
  111. constructor.getBody().add(new Line(new ValuedReturn(thisAccess, decl.startToken)));
  112. addFunction(constructor);
  113. }
  114. public void accept(Visitor visitor) throws IOException {
  115. visitor.visit(this);
  116. }
  117. @Override
  118. public void getVariables(NodeList<VariableDecl> variables) {
  119. super.getVariables(variables);
  120. if(getSuperRef() != null) getSuperRef().getVariables(variables);
  121. }
  122. @Override
  123. public boolean isResolved() {
  124. return false;
  125. }
  126. @Override
  127. public Response resolve(NodeList<Node> stack, Resolver res, boolean fatal) {
  128. Response response = super.resolve(stack, res, fatal);
  129. if(response != Response.OK) return response;
  130. if(isResolved()) return Response.OK;
  131. if(getSuperType() != null && !(super.getSuperRef() instanceof ClassDecl)) {
  132. throw new OocCompilationError(this, stack, "Trying to extends a "
  133. +getSuperRef().getClass().getSimpleName()+". You can only extend classes.");
  134. }
  135. if (getSuperType() != null) {
  136. if(getSuperRef() == null) {
  137. if(fatal) throw new OocCompilationError(this, stack, "Super-type "
  138. +getSuperType()+" of class "+getType()+" couldn't be resolved");
  139. return Response.LOOP;
  140. }
  141. if(defaultInit == null) {
  142. FunctionDecl superInit = getSuperRef().getFunction("init", "", null);
  143. if(superInit != null && superInit == getSuperRef().defaultInit) {
  144. addDefaultInit();
  145. //return Response.RESTART;
  146. }
  147. }
  148. }
  149. if(!hasRegisteredFinalizer) {
  150. FunctionDecl finalizer = getFunction(DESTROY_FUNC_NAME, null, null);
  151. if(finalizer != null && !finalizer.getBody().isEmpty()) {
  152. FunctionDecl defaults = getFunction(DEFAULTS_FUNC_NAME, null, null);
  153. FunctionCall call = new FunctionCall("gc_register_finalizer", finalizer.startToken);
  154. NodeList<Expression> args = call.getArguments();
  155. /*
  156. * void GC_debug_register_finalizer (GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
  157. * GC_finalization_proc *ofn, GC_PTR *ocd);
  158. */
  159. VariableAccess thisAccess = new VariableAccess("this", finalizer.startToken);
  160. args.add(thisAccess); // for object "this"
  161. VariableAccess destroyAccess = new MemberAccess(thisAccess, "__destroy__", finalizer.startToken);
  162. args.add(destroyAccess); // call the finalizer
  163. NullLiteral nil = new NullLiteral(finalizer.startToken);
  164. args.add(nil); // cd (no argument to pass)
  165. args.add(nil); // ofn (we don't care)
  166. args.add(nil); // ocd (we don't care)
  167. VersionBlock vBlock = new VersionBlock(new VersionName("gc"), finalizer.startToken);
  168. vBlock.getBody().add(new Line(call));
  169. defaults.getBody().add(0, new Line(vBlock));
  170. hasRegisteredFinalizer = true;
  171. return Response.LOOP;
  172. }
  173. }
  174. return Response.OK;
  175. }
  176. public ClassDecl getBaseClass(FunctionDecl decl) {
  177. if(getSuperRef() != null) {
  178. ClassDecl base = getSuperRef().getBaseClass(decl);
  179. if(base != null) return base;
  180. }
  181. if(getFunction(decl.getName(), decl.getSuffix(), null, false) != null) return this;
  182. return null;
  183. }
  184. public boolean isChildOf(String candidate) {
  185. if(getName().equals(candidate)) return true;
  186. if(getSuperRef() != null) return getSuperRef().isChildOf(candidate);
  187. return false;
  188. }
  189. }