/src/org/ooc/frontend/model/ArrayLiteral.java
Java | 229 lines | 181 code | 41 blank | 7 comment | 57 complexity | 57a860c5147ed4fa3f2d4c90730d63eb MD5 | raw file
1package org.ooc.frontend.model; 2 3import java.io.IOException; 4import java.util.Iterator; 5 6import org.ooc.frontend.Visitor; 7import org.ooc.frontend.model.interfaces.MustBeUnwrapped; 8import org.ooc.frontend.model.tokens.Token; 9import org.ooc.middle.OocCompilationError; 10import org.ooc.middle.hobgoblins.Resolver; 11 12public class ArrayLiteral extends Literal implements MustBeUnwrapped { 13 14 private FunctionCall outerCall = null; 15 private int outerArgIndex = -1; 16 17 //private static Type defaultType = NullLiteral.type; 18 private static Type defaultType = null; 19 private Type innerType = null; 20 private Type type = defaultType; 21 22 protected NodeList<Expression> elements; 23 24 public ArrayLiteral(Token startToken) { 25 super(startToken); 26 elements = new NodeList<Expression>(startToken); 27 } 28 29 @Override 30 public Expression getGenericOperand() { 31 System.out.println("Should get genericOperand of arrlit "+this); 32 return super.getGenericOperand(); 33 } 34 35 public int getDepth() { 36 if(elements.isEmpty() || !(elements.getFirst() instanceof ArrayLiteral)) return 1; 37 return 1 + ((ArrayLiteral) elements.getFirst()).getDepth(); 38 } 39 40 @Override 41 public boolean replace(Node oldie, Node kiddo) { 42 if(oldie == type) { 43 type = (Type) kiddo; 44 return true; 45 } else if(oldie == innerType) { 46 innerType = (Type) kiddo; 47 return true; 48 } 49 50 return false; 51 } 52 53 public Type getType() { 54 return type; 55 } 56 57 public Type getInnerType() { 58 return innerType; 59 } 60 61 public NodeList<Expression> getElements() { 62 return elements; 63 } 64 65 public void accept(Visitor visitor) throws IOException { 66 visitor.visit(this); 67 } 68 69 public void acceptChildren(Visitor visitor) throws IOException { 70 if(type != null) type.accept(visitor); 71 elements.accept(visitor); 72 } 73 74 public boolean hasChildren() { 75 return true; 76 } 77 78 @Override 79 public boolean isResolved() { 80 return type != defaultType && super.isResolved(); 81 } 82 83 @Override 84 public Response resolve(NodeList<Node> stack, Resolver res, boolean fatal) { 85 86 if(type != defaultType) return Response.OK; 87 88 if(!elements.isEmpty()) { 89 90 Iterator<Expression> iter = elements.iterator(); 91 92 // try to determine the innerType from an outer call 93 if(outerCall != null && outerArgIndex != -1) { 94 FunctionDecl impl = outerCall.getImpl(); 95 if(impl == null) { 96 if(fatal) { 97 throw new OocCompilationError(this, stack, "Couldn't resolve type of an array literal because" + 98 " the function call it's in hasn't been resolved."); 99 } 100 return Response.LOOP; 101 } 102 Argument arg = impl.getArguments().get(outerArgIndex); 103 104 ArrayLiteral lit = this; 105 int pointerLevel = 0; 106 while(lit != null) { 107 Node first = lit.getElements().getFirst(); 108 if(first instanceof ArrayLiteral) { 109 lit = (ArrayLiteral) first; 110 pointerLevel++; 111 } else { 112 lit = null; 113 } 114 } 115 innerType = new Type(arg.getType().getName(), arg.getType().startToken); 116 innerType.setPointerLevel(pointerLevel); 117 } 118 119 // try to determine the innerType from the first element 120 if(innerType == null) { 121 Expression first = iter.next(); 122 innerType = first.getType(); 123 } 124 125 // if we didn't resolve it && fatal, we're screwed :/ 126 if(innerType == null) { 127 if(fatal) { 128 throw new OocCompilationError(this, stack, "Couldn't resolve type of an array literal"); 129 } 130 return Response.LOOP; 131 } 132 133 while(iter.hasNext()) { 134 Expression element = iter.next(); 135 if(element.getType() == null) { 136 if(fatal) { 137 throw new OocCompilationError(element, stack, "Couldn't resolve type of " 138 +element+" in an "+innerType+" array literal"); 139 } 140 return Response.LOOP; 141 } 142 if(!element.getType().fitsIn(innerType)) { 143 throw new OocCompilationError(element, stack, "Encountered a " 144 +element.getType()+" in a "+innerType+"[] array literal."); 145 } 146 } 147 148 this.type = new Type(innerType.name.equals("Func") ? "Pointer" : innerType.name, innerType.pointerLevel + 1, startToken); 149 type.getTypeParams().addAll(innerType.getTypeParams()); 150 type.setArray(true); 151 stack.push(this); 152 type.resolve(stack, res, fatal); 153 innerType.resolve(stack, res, fatal); 154 stack.pop(this); 155 } 156 157 if(type == defaultType && fatal) { 158 throw new OocCompilationError(this, stack, "Couldn't figure out type of ArrayLiteral with elements "+elements); 159 } 160 return (type == defaultType) ? Response.LOOP : super.resolve(stack, res, fatal); 161 162 } 163 164 @SuppressWarnings("unchecked") 165 public boolean unwrap(NodeList<Node> stack) throws IOException { 166 167 // try to determine the innerType from the outer requirements 168 if(outerCall == null || outerArgIndex == -1) { 169 ArrayLiteral lit = this; 170 int litIndex = stack.find(ArrayLiteral.class); 171 int callIndex = stack.find(FunctionCall.class); 172 if(callIndex != -1) { 173 if(litIndex != -1 && litIndex > callIndex) { 174 lit = (ArrayLiteral) stack.get(litIndex); 175 } 176 outerCall = (FunctionCall) stack.get(callIndex); 177 outerArgIndex = ((NodeList<Node>) stack.get(callIndex + 1)).indexOf(lit); 178 } 179 } 180 181 if(stack.peek() instanceof Cast || stack.peek() instanceof Foreach) { 182 return false; 183 } 184 185 if(stack.peek(2) instanceof ArrayLiteral) { 186 return false; 187 } 188 189 int varDeclIndex = stack.find(VariableDecl.class); 190 191 // if stack.size() - varDeclIndex > 3, we're nested in another varDecl 192 //, thus we need to unwrap 193 if(varDeclIndex == -1 || (stack.size() - varDeclIndex) > 3) { 194 stack.peek().replace(this, new VariableDecl( 195 null, generateTempName("array", stack), this, startToken, stack.getModule())); 196 return true; 197 } 198 199 return false; 200 201 } 202 203 @Override 204 public String toString() { 205 StringBuilder sb = new StringBuilder(); 206 sb.append('['); 207 boolean isFirst = true; 208 for(Statement element : elements) { 209 if(isFirst) isFirst = false; 210 else sb.append(", "); 211 sb.append(element.toString()); 212 } 213 sb.append(']'); 214 return sb.toString(); 215 } 216 217 @Override 218 public boolean isConstant() { 219 boolean isConstant = true; 220 for(Expression element : elements) { 221 if(!element.isConstant()) { 222 isConstant = false; 223 break; 224 } 225 } 226 return isConstant; 227 } 228 229}