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