PageRenderTime 59ms CodeModel.GetById 28ms app.highlight 27ms RepoModel.GetById 1ms app.codeStats 0ms

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

http://github.com/nddrylliog/ooc
Java | 307 lines | 247 code | 55 blank | 5 comment | 59 complexity | cbc7ee8c3ddada27115bf082a86c433b MD5 | raw file
  1package org.ooc.frontend.model;
  2
  3import java.io.IOException;
  4import java.util.LinkedHashMap;
  5
  6import org.ooc.frontend.Visitor;
  7import org.ooc.frontend.model.OpDecl.OpType;
  8import org.ooc.frontend.model.interfaces.MustBeResolved;
  9import org.ooc.frontend.model.tokens.Token;
 10import org.ooc.middle.OocCompilationError;
 11import org.ooc.middle.hobgoblins.Resolver;
 12
 13public class Cast extends Expression implements MustBeResolved {
 14
 15	static enum CastMode {
 16		REGULAR,
 17		ARRAY, // for array literals
 18		MAP, // for map literal
 19	}
 20	
 21	protected Expression inner;
 22	protected Type type;
 23	
 24	public Cast(Expression expression, Type targetType, Token startToken) {
 25		super(startToken);
 26		this.inner = expression;
 27		setType(targetType);
 28	}
 29	
 30	@Override
 31	public Expression getGenericOperand() {
 32		// FIXME: hmm not really correct but fixes more thing than it breaks atm.
 33		return inner.getGenericOperand();
 34	}
 35
 36	@Override
 37	public boolean replace(Node oldie, Node kiddo) {
 38		if(oldie == inner) {
 39			inner = (Expression) kiddo;
 40			return true;
 41		}
 42		
 43		if(oldie == type) {
 44			type = (Type) kiddo;
 45			return true;
 46		}
 47		
 48		return false;
 49	}
 50
 51	public Type getType() {
 52		return type;
 53	}
 54
 55	public void accept(Visitor visitor) throws IOException {
 56		visitor.visit(this);
 57	}
 58
 59	public void acceptChildren(Visitor visitor) throws IOException {
 60		type.accept(visitor);
 61		inner.accept(visitor);
 62	}
 63
 64	public boolean hasChildren() {
 65		return true;
 66	}
 67
 68	@Override
 69	public Expression getInner() {
 70		return inner;
 71	}
 72
 73	public void setInner(Expression expression) {
 74		this.inner = expression;
 75	}
 76
 77	public void setType(Type newType) {
 78		this.type = newType;
 79	}
 80	
 81	@Override
 82	public String toString() {
 83		return "["+inner+" as "+type+"]";
 84	}
 85	
 86	@Override
 87	public boolean canBeReferenced() {
 88		return inner.canBeReferenced();
 89	}
 90
 91	public boolean isResolved() {
 92		return false;
 93	}
 94
 95	public Response resolve(NodeList<Node> stack, Resolver res, boolean fatal) {
 96		
 97		Response response;
 98		
 99		Expression realExpr = inner.bitchJumpCasts();
100		
101		if(realExpr.getType() == null) {
102			if(fatal) {
103				throw new OocCompilationError(this, stack, "Couldn't resolve type of expression in a cast");
104			}
105			return Response.LOOP;
106		}
107		
108		//if(realExpr instanceof ArrayLiteral) {
109		if(realExpr.getType().getPointerLevel() > 0) {
110			response = tryArrayOverload(stack, res, fatal);
111			if(response != Response.OK) return response;
112		}
113		
114		response = tryRegularOverload(stack, res, fatal);
115		if(response != Response.OK) return response;
116		
117		return Response.OK;
118		
119	}
120	
121	private Response tryRegularOverload(NodeList<Node> stack, Resolver res, boolean fatal) {
122		
123		Type leftType = inner.getType();
124		Type rightType = getType();
125		if(!leftType.isResolved() || !rightType.isResolved()) {
126			//System.out.println("Bitch-looping because either "+leftType+" or "+rightType+" isn't resolved");
127			return Response.LOOP;
128		}
129		
130		OpDecl bestOp = null;
131		int bestScore = 0;
132		for(OpDecl op: res.module.getOps()) {
133			int score = getRegularOpScore(stack, OpType.AS, op, res, leftType, rightType);
134			if(score > bestScore) {
135				bestScore = score;
136				bestOp = op;
137			}
138		}
139		for(Import imp: res.module.getAllImports()) { // TODO: really all imports?
140			for(OpDecl op: imp.getModule().getOps()) {
141				int score = getRegularOpScore(stack, OpType.AS, op, res, leftType, rightType);
142				if(score > bestScore) {
143					bestScore = score;
144					bestOp = op;
145				}
146			}
147		}
148		
149		if(bestOp != null) {
150			FunctionCall call = new FunctionCall(bestOp.getFunc(), startToken);
151			call.getArguments().add(inner);
152			Node parent = stack.peek();
153			parent.replace(this, call);
154			call.resolve(stack, res, true);
155			return Response.LOOP;
156		}
157		
158		return Response.OK;
159		
160	}
161
162	private int getRegularOpScore(NodeList<Node> stack, OpType opType, OpDecl op, Resolver res, Type leftType, Type rightType) {
163		
164		int score = 0;
165		if(op.getOpType() == opType) {
166			NodeList<Argument> args = op.getFunc().getArguments();
167			if(args.size() == 2) return score; // not for us
168			if(args.size() != 1) {
169				throw new OocCompilationError(op, stack,
170						"To overload the "+opType.toPrettyString()+" operator, you need exactly one arguments, not "
171						+op.getFunc().getArgsRepr());
172			}
173			Type firstType = args.get(0).getType();
174			Type secondType = op.getFunc().getReturnType();
175			if(firstType.softEquals(leftType, res)) {
176				if(secondType.softEquals(rightType, res) || isGeneric(secondType, op.getFunc().getTypeParams())) {
177					score += 10;
178					if(firstType.equals(leftType)) {
179						score += 20;
180					}
181					if(secondType.equals(rightType)) {
182						score += 20;
183					}
184				}
185			}
186		}
187		
188		return score;
189		
190	}
191	
192	private Response tryArrayOverload(NodeList<Node> stack, Resolver res, boolean fatal) {
193		
194		Type leftType = inner.getType();
195		Type rightType = getType();
196		if(!leftType.isResolved() || !rightType.isResolved()) {
197			//System.out.println("Bitch-looping because either "+leftType+" or "+rightType+" isn't resolved");
198			return Response.LOOP;
199		}
200		
201		OpDecl bestOp = null;
202		int bestScore = 0;
203		for(OpDecl op: res.module.getOps()) {
204			int score = getArrayOpScore(stack, OpType.AS, op, res, leftType, rightType);
205			if(score > bestScore) {
206				bestScore = score;
207				bestOp = op;
208			}
209		}
210		for(Import imp: res.module.getAllImports()) { // TODO: all imports?
211			for(OpDecl op: imp.getModule().getOps()) {
212				int score = getArrayOpScore(stack, OpType.AS, op, res, leftType, rightType);
213				if(score > bestScore) {
214					bestScore = score;
215					bestOp = op;
216				}
217			}
218		}
219		
220		if(bestOp != null) {
221			Type innerType = inner.getType().dereference();
222			int numElements = -1;
223			
224			if(inner instanceof VariableAccess) {
225				inner = ((VariableAccess) inner).getRef();
226				if(inner instanceof VariableDecl) {
227					// TODO: this code looks suspicious.
228					VariableDecl vdfe = (VariableDecl) inner;
229					inner = vdfe.getExpression();
230				}
231			}
232			
233			if(inner instanceof ArrayLiteral) {
234				ArrayLiteral lit = (ArrayLiteral) inner;
235				if(lit.getInnerType() == null) {
236					if(fatal) {
237						throw new OocCompilationError(lit, stack,
238								"Couldn't resolve inner type of ArrayLiteral, can't correctly call the overloaded cast!");
239					}
240					return Response.LOOP;
241				}
242				numElements = lit.getElements().size();
243			} else {
244				throw new OocCompilationError(inner, stack, "Trying to array-cast to " + getType() 
245						+ " an array of which we don't know the size! Try a constructor instead, passing the" +
246						  " size explicitly as an argument.");
247			}
248			
249			FunctionCall call = new FunctionCall(bestOp.getFunc(), startToken);
250			call.getArguments().add(inner);
251			call.getArguments().add(new IntLiteral(numElements, IntLiteral.Format.DEC, inner.startToken));
252			TypeAccess typeAccess = new TypeAccess(innerType, inner.startToken);
253			call.getTypeParams().add(typeAccess);
254			typeAccess.resolve(stack, res, true);
255			Node parent = stack.peek();
256			parent.replace(this, call);
257			Response resp2 = Response.RESTART;
258			while(resp2 == Response.RESTART) {
259				resp2 = call.resolve(stack, res, true);
260			}
261			return Response.LOOP;
262		}
263		
264		return Response.OK;
265		
266	}
267	
268	private int getArrayOpScore(NodeList<Node> stack, OpType opType, OpDecl op, Resolver res, Type leftType, Type rightType) {
269		
270		int score = 0;
271		if(op.getOpType() == opType) {
272			NodeList<Argument> args = op.getFunc().getArguments();
273			if(args.size() == 1) return score; // not for us
274			if(args.size() > 2 || args.size() < 1) {
275				throw new OocCompilationError(op, stack,
276						"To overload the "+opType.toPrettyString()+" operator from arrays, you need exactly two arguments (T* and size), not "
277						+op.getFunc().getArgsRepr());
278			}
279			
280			Type firstType = args.get(0).getType();
281			Type secondType = op.getFunc().getReturnType();
282			if(secondType.softEquals(rightType, res) || isGeneric(secondType, op.getFunc().getTypeParams())) {
283				score += 10;
284				if(firstType.equals(leftType)) {
285					score += 20;
286				}
287				if(secondType.equals(rightType)) {
288					score += 20;
289				}
290			}
291		}
292		
293		return score;
294		
295	}
296	
297	private boolean isGeneric(Type type, LinkedHashMap<String, TypeParam> linkedHashMap) {
298		return linkedHashMap.containsKey(type.getName());
299	}
300
301	@SuppressWarnings("unchecked")
302	@Override
303	public <T extends Node> T bitchJumpCasts() {
304		return (T) inner;
305	}
306
307}