/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

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