PageRenderTime 65ms CodeModel.GetById 22ms app.highlight 38ms RepoModel.GetById 1ms app.codeStats 1ms

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

http://github.com/nddrylliog/ooc
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}