PageRenderTime 286ms CodeModel.GetById 121ms app.highlight 66ms RepoModel.GetById 95ms app.codeStats 0ms

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

http://github.com/nddrylliog/ooc
Java | 260 lines | 212 code | 48 blank | 0 comment | 63 complexity | 4213a41cdb7e583881fa8a0b40810dfe MD5 | raw file
  1package org.ooc.frontend.model;
  2
  3import java.io.IOException;
  4
  5import org.ooc.frontend.Visitor;
  6import org.ooc.frontend.model.OpDecl.OpType;
  7import org.ooc.frontend.model.interfaces.MustBeResolved;
  8import org.ooc.frontend.model.tokens.Token;
  9import org.ooc.middle.OocCompilationError;
 10import org.ooc.middle.hobgoblins.Resolver;
 11
 12public class ArrayAccess extends Access implements MustBeResolved {
 13
 14	Type type;
 15	protected Expression variable;
 16	protected NodeList<Expression> indices;
 17
 18	public ArrayAccess(Expression variable, Token startToken) {
 19		super(startToken);
 20		this.variable = variable;
 21		this.indices =  new NodeList<Expression>(startToken);
 22	}
 23	
 24	@Override
 25	public Expression getGenericOperand() {
 26        if(getType().isGeneric() && getType().getPointerLevel() == 0) {
 27            MemberAccess sizeAcc = new MemberAccess(new VariableAccess(getType().getName(), startToken), "size", startToken);
 28            ArrayAccess arrAcc = new ArrayAccess(variable, startToken);
 29            arrAcc.indices.add(new Mul(indices.get(0), sizeAcc, arrAcc.startToken));
 30            return new AddressOf(arrAcc, arrAcc.startToken);
 31        }
 32        return super.getGenericOperand();
 33    }
 34	
 35	public Expression getVariable() {
 36		return variable;
 37	}
 38	
 39	public void setVariable(Expression variable) {
 40		this.variable = variable;
 41	}
 42	
 43	public NodeList<Expression> getIndices() {
 44		return indices;
 45	}
 46
 47	public Type getType() {
 48		if(type == null) {
 49			Type exprType = variable.getType();
 50			if(exprType != null) {
 51				Declaration ref = exprType.getRef();
 52				if(ref instanceof CoverDecl) {
 53					Type fromType = ((CoverDecl) ref).getFromType();
 54					if(fromType != null && fromType.getRef() instanceof CoverDecl) {
 55						Type clone = fromType.clone();
 56						clone.setPointerLevel(exprType.getPointerLevel() + fromType.getPointerLevel());
 57						exprType = clone;
 58					}
 59				}
 60				type = new Type(exprType.getName(), exprType.getPointerLevel() - 1, exprType.startToken);
 61				type.setRef(exprType.getRef());
 62			}
 63		}
 64		return type;
 65	}
 66	
 67	public void accept(Visitor visitor) throws IOException {
 68		visitor.visit(this);
 69	}
 70	
 71	public boolean hasChildren() {
 72		return true;
 73	}
 74	
 75	public void acceptChildren(Visitor visitor) throws IOException {
 76		variable.accept(visitor);
 77		indices.accept(visitor);
 78	}
 79	
 80	@SuppressWarnings("unchecked")
 81	@Override
 82	public boolean replace(Node oldie, Node kiddo) {
 83		
 84		if(oldie == variable) {
 85			variable = (Expression) kiddo;
 86			return true;
 87		}
 88		
 89		if(oldie == indices) {
 90			indices = (NodeList<Expression>) kiddo;
 91			return true;
 92		}
 93		
 94		return false;
 95		
 96	}
 97
 98	public boolean isResolved() {
 99		return false;
100	}
101
102	public Response resolve(NodeList<Node> stack, Resolver res, boolean fatal) {
103		
104		int assignIndex = -1;
105		
106		if(stack.peek() instanceof Assignment) {
107			Assignment ass = (Assignment) stack.peek();
108			if(ass.getLeft() == this) {
109				assignIndex = stack.size() - 1;
110			} else {
111				NodeList<Node> copy = new NodeList<Node>();
112				copy.addAll(stack);
113				copy.pop();
114				Response response = ass.resolve(copy, res, fatal);
115				if(response != Response.OK) {
116					return response;
117				}
118			}
119		}
120		
121		OpDecl bestOp = null;
122		int bestScore = 0;
123		try {
124			for(OpDecl op: res.module.getOps()) {
125				int score = getOpScore(stack, res, assignIndex, op);
126				if(bestScore < score) {
127					bestOp = op;
128					bestScore = score;
129				}
130			}
131			
132			for(Import imp: res.module.getAllImports()) {
133				for(OpDecl op: imp.getModule().getOps()) {
134					int score = getOpScore(stack, res, assignIndex, op);
135					if(bestScore < score) {
136						bestOp = op;
137						bestScore = score;
138					}
139				}
140			}
141		} catch(OocCompilationError ex) {
142			if(fatal) {
143				throw ex;
144			}
145			return Response.LOOP;
146		}
147		
148		if(bestOp != null) {
149			NodeList<Argument> args = bestOp.getFunc().getArguments();
150			FunctionCall call = new FunctionCall(bestOp.getFunc(), startToken);
151			
152			Argument arg = args.getFirst();
153			if(arg.getType().getReferenceLevel() == variable.getType().getReferenceLevel() + 1) {
154				variable = new AddressOf(variable, startToken);
155			}
156			
157			call.getArguments().add(variable);
158			call.getArguments().addAll(indices);
159			
160			if(assignIndex != -1) {
161				Assignment ass = (Assignment)stack.get(assignIndex);
162				call.getArguments().add(ass.getRight());
163				
164				if(!stack.get(assignIndex - 1).replace(ass, call)) {
165					System.out.println("stack = "+stack.toString(true));
166					Thread.dumpStack();
167					throw new OocCompilationError(this, stack, "Couldn't replace array-access-assign with a function call");
168				}
169			} else {
170				stack.peek().replace(this, call);
171			}
172			
173			return Response.LOOP;
174		}
175		
176		return Response.OK;
177		
178	}
179	
180	private int getOpScore(NodeList<Node> stack, Resolver res, int assignIndex, OpDecl op) throws OocCompilationError {
181		int score = 0;
182		
183		OpType opType = assignIndex == -1 ? OpType.IDX : OpType.IDX_ASS;
184		int numArgs = 1 + indices.size() + (opType == OpType.IDX ? 0 : 1);
185		
186		NodeList<Argument> args = op.getFunc().getArguments();
187		if(op.getOpType() != opType || args.size() != numArgs) {
188			return 0;
189		}
190		
191		Argument first = args.getFirst();
192		if(first.getType().softEquals(variable.getType(), res)) {
193			if(opType == OpType.IDX && args.size() < 2) {
194				throw new OocCompilationError(op, stack,
195						"To overload the indexing operator, you need at least two arguments, not "
196						+op.getFunc().getArgsRepr());
197			} else if(opType == OpType.IDX_ASS && args.size() < 3) {
198				throw new OocCompilationError(op, stack,
199						"To overload the indexed assign operator, you need exactly three arguments, not "
200						+op.getFunc().getArgsRepr());
201			}
202			
203			score += 10;
204			
205			if(first.getType().equals(variable.getType())) {
206				score += 20;
207			}
208			
209			if(variable.getType().getReferenceLevel() == first.getType().getReferenceLevel() + 1) {
210				score += 10;
211			}
212			
213			for(int idx = 0; idx < indices.size(); ++idx) {
214				Expression exp = indices.get(idx);
215				Argument arg = args.get(idx+1);
216				
217				if(exp.getType() == null) {
218					throw new OocCompilationError(exp, stack,
219							"Unable to determine the type of the expression being used as an index");
220				}
221				
222				if(exp.getType().softEquals(arg.getType(), res)) {
223					score += 10;
224					if(exp.getType().equals(arg.getType())) {
225						score += 10;
226					}
227				}
228			}
229			
230			if(assignIndex != -1) {
231				Argument last = args.getLast();
232				Assignment ass = (Assignment)stack.get(assignIndex);
233				if (ass.getRight().getType() == null) {
234					throw new OocCompilationError(ass.getRight(), stack,
235							"Unable to determine the type of the expression being assigned");
236				}
237				
238				if(ass.getRight().getType().softEquals(last.getType(), res)) {
239					score += 10;
240					if(ass.getRight().getType().equals(last.getType())) {
241						score += 20;
242					}
243				}
244			}
245		}
246		
247		return score;
248	}
249	
250	@Override
251	public String toString() {
252		return variable.toString() + indices;
253	}
254	
255	@Override
256	public boolean canBeReferenced() {
257		return true;
258	}
259	
260}