PageRenderTime 388ms CodeModel.GetById 91ms app.highlight 187ms RepoModel.GetById 104ms app.codeStats 1ms

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

http://github.com/nddrylliog/ooc
Java | 525 lines | 396 code | 107 blank | 22 comment | 88 complexity | 8578881fbbc48f7b030ffbc54698989d MD5 | raw file
  1package org.ooc.frontend.model;
  2
  3import java.io.IOException;
  4import java.util.Iterator;
  5import java.util.LinkedHashMap;
  6import java.util.Map;
  7
  8import org.ooc.frontend.BuildParams;
  9import org.ooc.frontend.Visitor;
 10import org.ooc.frontend.model.IntLiteral.Format;
 11import org.ooc.frontend.model.NodeList.AddListener;
 12import org.ooc.frontend.model.interfaces.MustBeUnwrapped;
 13import org.ooc.frontend.model.interfaces.Versioned;
 14import org.ooc.frontend.model.tokens.Token;
 15import org.ooc.middle.OocCompilationError;
 16import org.ooc.middle.hobgoblins.Resolver;
 17
 18public class FunctionDecl extends Declaration implements Scope, Generic, MustBeUnwrapped, PotentiallyStatic, Versioned {
 19
 20	public Type type;
 21
 22	protected OocDocComment comment;
 23
 24	protected boolean isFinal;
 25	protected boolean isStatic;
 26	protected boolean isAbstract;
 27	protected boolean isProto = false;
 28	protected boolean isInline = false;
 29	protected boolean fromPointer = false;
 30
 31	protected TypeDecl typeDecl;
 32
 33	protected String suffix;
 34	private final NodeList<Line> body;
 35
 36	protected Type returnType;
 37	// when the return type is generic, the returnArg is a pointer.
 38	protected Argument returnArg;
 39
 40	protected final LinkedHashMap<String, TypeParam> typeParams;
 41	private final NodeList<Argument> arguments;
 42
 43	private VersionBlock version = null;
 44
 45	public FunctionDecl(String name, String suffix, boolean isFinal,
 46			boolean isStatic, boolean isAbstract, boolean isExtern, Token startToken, Module module) {
 47		this(name, suffix, isFinal, isStatic, isAbstract, isExtern ? "" : null, startToken, module);
 48	}
 49
 50	public FunctionDecl(String name, String suffix, boolean isFinal,
 51			boolean isStatic, boolean isAbstract, String externName, Token startToken, Module module) {
 52		super(name, externName, startToken, module);
 53		this.suffix = suffix;
 54		this.isFinal = isFinal;
 55		this.isStatic = isStatic;
 56		this.isAbstract = isAbstract;
 57		this.body = new NodeList<Line>(startToken);
 58		this.returnType = name.equals("main") ? IntLiteral.type : Type.getVoid();
 59		this.arguments = new NodeList<Argument>(startToken);
 60		this.arguments.addAddListener(new AddListener<Argument>() {
 61			public void onAdd(NodeList<Argument> list, Argument arg) {
 62				TypeParam typeParam = typeParams.get(arg.getName());
 63				if(typeParam != null) {
 64					typeParam.setGhost(true);
 65				}
 66			}
 67		});
 68		this.typeParams = new LinkedHashMap<String, TypeParam>();
 69		this.type = new FuncType(Token.defaultToken, this);
 70	}
 71
 72	public LinkedHashMap<String, TypeParam> getTypeParams() {
 73		return typeParams;
 74	}
 75
 76	public void setComment(OocDocComment comment) {
 77		this.comment = comment;
 78	}
 79
 80	public OocDocComment getComment() {
 81		return comment;
 82	}
 83
 84	public String getSuffix() {
 85		return suffix;
 86	}
 87
 88	public void setSuffix(String suffix) {
 89		this.suffix = suffix;
 90	}
 91
 92	public boolean isFromPointer() {
 93		return fromPointer;
 94	}
 95
 96	public void setFromPointer(boolean fromPointer) {
 97		this.fromPointer = fromPointer;
 98	}
 99
100	public boolean isProto() {
101		return isProto;
102	}
103
104	public void setProto(boolean isProto) {
105		this.isProto = isProto;
106	}
107
108	public boolean isAbstract() {
109		return isAbstract;
110	}
111
112	public void setAbstract(boolean isAbstract) {
113		this.isAbstract = isAbstract;
114	}
115
116	public boolean isStatic() {
117		return isStatic;
118	}
119
120	public void setStatic(boolean isStatic) {
121		this.isStatic = isStatic;
122	}
123
124	public boolean isFinal() {
125		return isFinal;
126	}
127
128	public void setFinal(boolean isFinal) {
129		this.isFinal = isFinal;
130	}
131
132	@Override
133	public TypeDecl getTypeDecl() {
134		return typeDecl;
135	}
136
137	public boolean isInline() {
138		return isInline;
139	}
140
141	public void setInline(boolean isInline) {
142		this.isInline = isInline;
143	}
144
145	public void setTypeDecl(TypeDecl typeDecl) {
146		this.typeDecl = typeDecl;
147	}
148
149	/**
150	 * @return true if it's a member function
151	 */
152	public boolean isMember() {
153		return typeDecl != null;
154	}
155
156	public boolean hasThis() {
157		return !isStatic() && isMember() && !isFromPointer();
158	}
159
160	public NodeList<Line> getBody() {
161		return body;
162	}
163
164	public Type getReturnType() {
165		return returnType;
166	}
167
168	public void setReturnType(Type returnType) {
169		this.returnType = returnType;
170		// FIXME this will bite us in the ass later. Ohh yes it will
171		// you see, nothing guarantees that "__returnArg" isn't in the scope already
172		// we should create returnArg in resolve instead, using generateTempName()
173		this.returnArg = new RegularArgument(returnType, "__returnArg", startToken);
174	}
175
176	public NodeList<Argument> getArguments() {
177		return arguments;
178	}
179
180	public Type getType() {
181		return type;
182	}
183
184	public void accept(Visitor visitor) throws IOException {
185		visitor.visit(this);
186	}
187
188	public boolean hasChildren() {
189		return true;
190	}
191
192	public void acceptChildren(Visitor visitor) throws IOException {
193		if (typeParams.size() > 0) for (TypeParam typeParam: typeParams.values()) {
194			typeParam.getType().accept(visitor);
195		}
196		arguments.accept(visitor);
197		returnType.accept(visitor);
198		body.accept(visitor);
199	}
200
201	@Override
202	public boolean replace(Node oldie, Node kiddo) {
203
204		if(oldie == returnType) {
205			returnType = (Type) kiddo;
206			return true;
207		}
208
209		return false;
210
211	}
212
213	public String getArgsRepr() {
214		return getArgsRepr(hasThis());
215	}
216
217	public String getArgsRepr(boolean skipThis) {
218
219		StringBuilder sB = new StringBuilder();
220		sB.append('(');
221		Iterator<Argument> iter = arguments.iterator();
222		if(skipThis && hasThis() && iter.hasNext()) iter.next();
223		while(iter.hasNext()) {
224			Argument arg = iter.next();
225			if(arg instanceof VarArg) sB.append("...");
226			else sB.append(arg.getType());
227
228			if(iter.hasNext()) sB.append(", ");
229		}
230		sB.append(')');
231
232		return sB.toString();
233
234	}
235
236	@Override
237	public String toString() {
238
239		String name = isMember() ? typeDecl.getType() + "." + getSuffixedName() : getSuffixedName();
240		String repr = /*getClass().getSimpleName()+" : "+*/name+getArgsRepr();
241		return repr;
242
243	}
244
245	public String getFullName() {
246
247		StringBuilder sB = new StringBuilder();
248		try {
249			writeFullName(sB);
250		} catch (IOException e) {
251			e.printStackTrace();
252		}
253		return sB.toString();
254
255	}
256
257	public void writeFullName(Appendable dst) throws IOException {
258
259		if(isUnmangled()) {
260			dst.append(getUnmangledName());
261		} else {
262			dst.append(module.getMemberPrefix());
263			if(isMember()) {
264				dst.append(typeDecl.getExternName()).append('_');
265			}
266			writeSuffixedName(dst);
267		}
268
269	}
270
271	public void writeSuffixedName(Appendable dst) throws IOException {
272
273		//dst.append(getExternName());
274		dst.append(getName());
275		if(suffix.length() > 0) {
276			dst.append('_').append(suffix);
277		}
278
279	}
280
281	public String getProtoRepr() {
282		return getProtoRepr(hasThis());
283	}
284
285	public String getProtoRepr(boolean skipThis) {
286		if(typeDecl != null) return typeDecl.getName()+"."+name+getArgsRepr(skipThis);
287		return name+getArgsRepr(skipThis);
288	}
289
290	public boolean sameProto(FunctionDecl decl2) {
291		return name.equals(decl2.getName()) && (suffix.equals(decl2.getSuffix()));
292	}
293
294	public boolean isEntryPoint(BuildParams params) {
295		return !isMember() && name.equals(params.entryPoint);
296	}
297
298	public VariableDecl getVariable(String name) {
299		if(arguments.size() > 0) for(Argument argument: arguments) {
300			if(argument.getName().equals(name)) return argument;
301		}
302		return getVariable(body, name);
303	}
304
305	public void getVariables(NodeList<VariableDecl> variables) {
306		if(arguments.size() > 0) for(Argument argument: arguments) {
307			variables.add(argument);
308		}
309		getVariables(body, variables);
310	}
311
312	public FunctionDecl getFunction(String name, String suffix, FunctionCall call) {
313		return null;
314	}
315
316	public void getFunctions(NodeList<FunctionDecl> functions) {}
317
318	public String getSuffixedName() {
319		if(suffix.length() == 0) return name;
320		return name+"_"+suffix;
321	}
322
323	public boolean unwrap(NodeList<Node> stack) throws IOException {
324		if(name.length() == 0) {
325			Module module = stack.getModule();
326			name = stack.get(0).generateTempName(module.getUnderName()+"_closure", stack);
327			this.module = module;
328			VariableAccess varAcc = new VariableAccess(name, startToken);
329			varAcc.setRef(this);
330			stack.peek().replace(this, varAcc);
331			module.getBody().add(this);
332
333			return true;
334		}
335
336		if(name.equals("main")) {
337			if(arguments.size() == 1 && arguments.getFirst().getType().getName().equals("ArrayList")) {
338				Argument arg = arguments.getFirst();
339				arguments.clear();
340				Argument argc = new RegularArgument(IntLiteral.type, "argc", arg.startToken);
341				Argument argv = new RegularArgument(new Type("String", 1, arg.startToken), "argv", arg.startToken);
342				arguments.add(argc);
343				arguments.add(argv);
344
345				MemberCall constructCall = new MemberCall(new TypeAccess(arg.getType(), arg.startToken),
346						"new", "withData", arg.startToken);
347				constructCall.getTypeParams().add(new TypeAccess(NullLiteral.type, constructCall.startToken));
348				constructCall.getArguments().add(new VariableAccess(argv, startToken));
349				constructCall.getArguments().add(new VariableAccess(argc, startToken));
350
351				VariableDecl vdfe = new VariableDecl(null, arg.getName(),
352						constructCall, arg.startToken, module);
353
354				body.add(0, new Line(vdfe));
355			}
356		}
357
358		return false;
359	}
360
361	public Argument getReturnArg() {
362		return returnArg;
363	}
364
365	public boolean isNamed(String name, String suffix) {
366		return this.name.equals(name) && (suffix == null || this.suffix.equals(suffix));
367	}
368
369	public boolean isSpecialFunc() {
370		return name.equals(ClassDecl.DEFAULTS_FUNC_NAME)
371			|| name.equals(ClassDecl.DESTROY_FUNC_NAME)
372			|| name.equals(ClassDecl.LOAD_FUNC_NAME);
373	}
374
375	public Iterator<Argument> getThisLessArgsIter() {
376		Iterator<Argument> iter = getArguments().iterator();
377		if(hasThis()) iter.next();
378		return iter;
379	}
380
381	public boolean hasReturn() {
382		return !getReturnType().isVoid() && !(getReturnType().isGeneric());
383	}
384
385	public TypeParam getGenericType(String name) {
386		TypeParam genericType = typeParams.get(name);
387		if(genericType == null && typeDecl != null) {
388			Map<String, TypeParam> classGenerics = typeDecl.getTypeParams();
389			genericType = classGenerics.get(name);
390			return genericType;
391		}
392		return genericType;
393	}
394
395	public boolean isGeneric() {
396		if(typeParams.size() > 0) return true;
397		if(typeDecl != null && typeDecl.getTypeParams().size() > 0) return true;
398		return false;
399	}
400
401	@Override
402	public boolean isResolved() {
403		return false;
404	}
405
406	@Override
407	public Response resolve(NodeList<Node> stack, Resolver res, boolean fatal) {
408
409		if(isEntryPoint(res.params))
410			setUnmangledName(""); // the entry point should not be mangled.
411
412
413		for(Argument arg: arguments) {
414			if(getTypeDecl() != null) {
415				TypeDecl tDecl = getTypeDecl();
416				TypeParam typeParam = tDecl.getTypeParams().get(arg.getName());
417				if(typeParam != null) typeParam.setGhost(true);
418			}
419
420			Type argType = arg.getType();
421			if(argType != null && !argType.isResolved()) {
422				stack.push(arguments);
423				stack.push(arg);
424				while(argType.getRef() == null) {
425					argType.resolve(stack, res, true);
426				}
427				stack.pop(arg);
428				stack.pop(arguments);
429			}
430		}
431
432		Response response = super.resolve(stack, res, fatal);
433		if(response != Response.OK) return response;
434
435		if(isMember() && typeDecl.getSuperRef() != null) {
436			FunctionDecl sup = typeDecl.getSuperRef().getFunction(name, suffix, null);
437			if(sup != null && (sup.getArguments().size() != getArguments().size())) {
438				if(name.equals("new") || name.equals("init")) {
439					throw new OocCompilationError(this, stack, "There's no no-argument constructor in super-type "
440							+typeDecl.getSuperRef().getName()+", you should add a constructor to "
441							+typeDecl.getName()+" with a suffix, e.g. init: func ~mySuffix () {}");
442				}
443				throw new OocCompilationError(this, stack, "Definition of "
444						+this+" conflicts with definition in super-type "
445						+typeDecl.getSuperRef().getName()+", you should add a suffix to this one or make it have the same arguments.");
446			}
447		}
448
449		if(!getReturnType().isVoid() && !isExtern() && !isAbstract()) {
450
451			if(getBody().isEmpty()) {
452				if(getName().equals("main")) {
453					getBody().add(new Line(new ValuedReturn(
454							new IntLiteral(0, Format.DEC, startToken), startToken)));
455					//return Response.RESTART;
456				} /*else {
457
458					throw new OocCompilationError(node, stack,
459							"Returning nothing in function "+getProtoRepr()
460								+" that should return a "+getReturnType());
461
462				}*/
463			} else {
464
465				Line line = getBody().getLast();
466				if(!(line.getStatement() instanceof Return)) {
467					if(name.equals("main")) {
468						getBody().add(new Line(new ValuedReturn(
469								new IntLiteral(0, Format.DEC, startToken), startToken)));
470						//return Response.RESTART;
471					} else if(line.getStatement() instanceof Expression) {
472						line.setStatement(new ValuedReturn((Expression) line.getStatement(),
473								line.getStatement().startToken));
474						//return Response.RESTART;
475					} /*else {
476
477						throw new OocCompilationError(node, stack,
478								"Returning nothing in function "+getProtoRepr()
479									+" that should return a "+getReturnType());
480					}*/
481				}
482
483			}
484		}
485
486		return Response.OK;
487	}
488
489	public String getStub() {
490
491		StringBuffer buff = new StringBuffer(name);
492		buff.append(": func ");
493		int numArgs = arguments.size();
494		if(hasThis()) numArgs--;
495		if(numArgs > 0) {
496			buff.append("(");
497			Iterator<Argument> iter = arguments.iterator();
498			if(iter.hasNext() && hasThis()) iter.next(); // skip this
499			while(iter.hasNext()) {
500				Argument arg = iter.next();
501				buff.append(arg.getName());
502				buff.append(": ");
503				buff.append(arg.getType());
504				if(iter.hasNext()) buff.append(", ");
505			}
506			buff.append(")");
507		}
508		if(hasReturn()) {
509			buff.append(" -> ").append(getReturnType());
510		}
511		buff.append(" {}");
512
513		return buff.toString();
514
515	}
516
517	public void setVersion(VersionBlock version) {
518		this.version = version;
519	}
520
521	public VersionBlock getVersion() {
522		return version;
523	}
524
525}