PageRenderTime 32ms CodeModel.GetById 2ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 0ms

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