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

http://github.com/nddrylliog/ooc · Java · 177 lines · 140 code · 35 blank · 2 comment · 31 complexity · 442bac649caf95497d02cd373f7026a3 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.interfaces.MustBeResolved;
  5. import org.ooc.frontend.model.tokens.Token;
  6. import org.ooc.middle.OocCompilationError;
  7. import org.ooc.middle.hobgoblins.Resolver;
  8. public class Foreach extends ControlStatement implements MustBeResolved {
  9. protected Expression variable;
  10. protected Expression collection; // must be of type Range or Iterable
  11. public Foreach(Expression variable, Expression collection, Token startToken) {
  12. super(startToken);
  13. this.variable = variable;
  14. this.collection = collection;
  15. }
  16. public Expression getVariable() {
  17. return variable;
  18. }
  19. public void setVariable(VariableDecl variable) {
  20. this.variable = variable;
  21. }
  22. public Expression getCollection() {
  23. return collection;
  24. }
  25. public void setCollection(Expression range) {
  26. this.collection = range;
  27. }
  28. public void accept(Visitor visitor) throws IOException {
  29. visitor.visit(this);
  30. }
  31. public boolean hasChildren() {
  32. return true;
  33. }
  34. public void acceptChildren(Visitor visitor) throws IOException {
  35. // we don't want to resolve VariableAccesses - they should create new
  36. // variables, this fixes #64 http://github.com/nddrylliog/ooc/issues#issue/64
  37. if(variable instanceof VariableDecl) {
  38. variable.accept(visitor);
  39. }
  40. collection.accept(visitor);
  41. body.accept(visitor);
  42. }
  43. @Override
  44. public boolean replace(Node oldie, Node kiddo) {
  45. if(oldie == variable) {
  46. variable = (Expression) kiddo;
  47. return true;
  48. }
  49. if(oldie == collection) {
  50. collection = (Expression) kiddo;
  51. return true;
  52. }
  53. return false;
  54. }
  55. @Override
  56. public VariableDecl getVariable(String name) {
  57. if(variable instanceof VariableDecl) {
  58. VariableDecl varDecl = (VariableDecl) variable;
  59. if(varDecl.getName().equals(name)) return varDecl;
  60. } else if(variable instanceof VariableAccess) {
  61. VariableAccess varAcc = (VariableAccess) variable;
  62. if(varAcc.getName().equals(name)) return (VariableDecl) varAcc.getRef();
  63. }
  64. return super.getVariable(name);
  65. }
  66. @Override
  67. public void getVariables(NodeList<VariableDecl> variables) {
  68. if(variable instanceof VariableDecl) {
  69. VariableDecl varDecl = (VariableDecl) variable;
  70. variables.add(varDecl);
  71. } else if(variable instanceof VariableAccess) {
  72. VariableAccess varAcc = (VariableAccess) variable;
  73. if(varAcc.getRef() != null)
  74. variables.add((VariableDecl) varAcc.getRef());
  75. }
  76. super.getVariables(variables);
  77. }
  78. public boolean isResolved() {
  79. return false;
  80. }
  81. @SuppressWarnings("unchecked")
  82. public Response resolve(NodeList<Node> stack, Resolver res, boolean fatal) {
  83. if(collection.getType() == null ||
  84. (!collection.getType().getName().equals("Range") && collection.getType().getRef() == null)) {
  85. if(fatal) {
  86. throw new OocCompilationError(collection, stack, "Couldn't resolve type "
  87. +collection.getType()+" of foreach's collection "+collection+" (ref = "
  88. +(collection.getType() == null ? "null" : collection.getType().getRef()));
  89. }
  90. return Response.LOOP;
  91. }
  92. if(collection.getType().getPointerLevel() > 0) {
  93. Type targetType = new Type("ArrayList", collection.startToken);
  94. targetType.getTypeParams().add(new TypeAccess(collection.getType().dereference(), collection.startToken));
  95. collection = new Cast(collection, targetType, collection.startToken);
  96. return Response.LOOP;
  97. }
  98. if(collection instanceof RangeLiteral) {
  99. return Response.OK;
  100. }
  101. MemberCall iterCall = new MemberCall(collection, "iterator", "", startToken);
  102. Response resp = Response.LOOP;
  103. int gardeFou = 10;
  104. while(resp == Response.LOOP) {
  105. resp = iterCall.resolve(stack, res, true);
  106. gardeFou--;
  107. if(gardeFou <= 0) return Response.LOOP;
  108. }
  109. Type iterType = iterCall.getType();
  110. iterType.resolve(stack, res, false);
  111. if(iterType.getRef() == null) {
  112. if(fatal) throw new OocCompilationError(this, stack, "couldn't resolve iterType "+iterType);
  113. return Response.LOOP;
  114. }
  115. int lineIndex = stack.find(Line.class);
  116. Line line = (Line) stack.get(lineIndex);
  117. NodeList<Line> list = (NodeList<Line>) stack.get(lineIndex - 1);
  118. Block block = new Block(startToken);
  119. VariableDecl vdfe = new VariableDecl(iterType, generateTempName("iter", stack), iterCall, startToken, null);
  120. VariableAccess iterAcc = new VariableAccess(vdfe, startToken);
  121. iterAcc.setRef(vdfe);
  122. MemberCall hasNextCall = new MemberCall(iterAcc, "hasNext", "", startToken);
  123. hasNextCall.resolve(stack, res, true);
  124. While while1 = new While(hasNextCall, startToken);
  125. MemberCall nextCall = new MemberCall(iterAcc, "next", "", startToken);
  126. nextCall.resolve(stack, res, true);
  127. if(variable instanceof VariableAccess) {
  128. VariableAccess varAcc = (VariableAccess) variable;
  129. if(varAcc.getRef() == null) {
  130. Type innerType = iterCall.getType().getTypeParams().getFirst().getType();
  131. VariableDecl varDecl = new VariableDecl(innerType, varAcc.getName(), varAcc.startToken, null);
  132. block.getBody().add(0, new Line(varDecl));
  133. }
  134. }
  135. while1.getBody().add(new Line(new Assignment(variable, nextCall, startToken)));
  136. while1.getBody().addAll(getBody());
  137. list.replace(line, new Line(block));
  138. block.getBody().add(new Line(vdfe));
  139. block.getBody().add(new Line(while1));
  140. return Response.LOOP;
  141. }
  142. }