PageRenderTime 684ms CodeModel.GetById 232ms app.highlight 95ms RepoModel.GetById 253ms app.codeStats 101ms

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

http://github.com/nddrylliog/ooc
Java | 265 lines | 213 code | 48 blank | 4 comment | 78 complexity | 9acc105d6c661a45b7da778d3b62d7a6 MD5 | raw file
  1package org.ooc.frontend.model;
  2
  3import java.io.IOException;
  4
  5import org.ooc.frontend.Levenshtein;
  6import org.ooc.frontend.Visitor;
  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 MemberAccess extends VariableAccess {
 13
 14	protected Expression expression;
 15
 16	public MemberAccess(String variable, Token startToken) {
 17		this(new VariableAccess("this", startToken), variable, startToken);
 18	}
 19	
 20	public MemberAccess(Expression expression, String variable, Token startToken) {
 21		super(variable, startToken);
 22		this.expression = expression;
 23	}
 24	
 25	public MemberAccess(Expression expression, VariableAccess variableAccess, Token startToken) {
 26		super(variableAccess.getName(), startToken);
 27		this.expression = expression;
 28	}
 29
 30	public Expression getExpression() {
 31		return expression;
 32	}
 33	
 34	public void setExpression(Expression expression) {
 35		this.expression = expression;
 36	}
 37	
 38	@Override
 39	public void accept(Visitor visitor) throws IOException {
 40		visitor.visit(this);
 41	}
 42	
 43	@Override
 44	public void acceptChildren(Visitor visitor) throws IOException {
 45		expression.accept(visitor);
 46		super.acceptChildren(visitor);
 47	}
 48	
 49	@Override
 50	public boolean replace(Node oldie, Node kiddo) {
 51	
 52		if(super.replace(oldie, kiddo)) return true;
 53		
 54		if(oldie == expression) {
 55			expression = (Expression) kiddo;
 56			return true;
 57		}
 58		
 59		return false;
 60		
 61	}
 62	
 63	@Override
 64	public Response resolve(NodeList<Node> stack, Resolver res, boolean fatal) {
 65
 66		Type exprType = expression.getType();
 67
 68		if(exprType == null) {
 69			int typeIndex = stack.find(TypeDecl.class);
 70			if(typeIndex != -1) {
 71				TypeDecl typeDecl = (TypeDecl) stack.get(typeIndex);
 72				VariableDecl var = typeDecl.getVariable(getName());
 73				if(var != null && var.isStatic()) {
 74					ref = var;
 75					if(expression instanceof VariableAccess) {
 76						VariableAccess varAcc = (VariableAccess) expression;
 77						if(((VariableAccess) expression).getName().equals("this")) {
 78							varAcc = new VariableAccess(typeDecl.getName(), expression.startToken);
 79							expression = varAcc;
 80							varAcc.resolve(stack, res, fatal);
 81						}
 82					}
 83					return Response.OK;
 84				}
 85			}
 86			
 87			if(expression instanceof VariableAccess && ((VariableAccess) expression).getRef() instanceof NamespaceDecl) {
 88				NamespaceDecl ns = ((NamespaceDecl) ((VariableAccess) expression).getRef());
 89				// push imported modules ...
 90				for(Import imp: ns.getImports()) {
 91					stack.push(imp.getModule());
 92				}
 93				// push the namespace as a "sentinel".
 94				stack.push(ns);
 95				VariableAccess varAcc = new VariableAccess(getName(), expression.startToken);
 96				varAcc.resolve(stack, res, fatal);
 97				ref = varAcc.getRef();
 98				stack.pop();
 99				for(int i = 0; i < ns.getImports().size(); i++) {
100					stack.pop();
101				}
102				stack.peek().replace(this, varAcc);
103				return Response.OK;
104			}
105
106			if(fatal) {
107				throw new OocCompilationError(this, stack, "Couldn't resolve type of "+expression);
108			}
109			return Response.LOOP;
110		}
111
112		exprType = exprType.getFlatType(res);
113		if(exprType.getRef() == null) exprType.resolve(res);
114
115		if(!tryResolve(stack, exprType, res)) {
116			tryResolve(stack, exprType.getFlatType(res), res);
117		}
118		
119		if(ref != null && ref.getType() == null) {
120			MustBeResolved must = ref;
121			must.resolve(stack, res, fatal);
122		}
123		
124		if(ref != null) {
125			if(expression instanceof VariableAccess) {
126				VariableAccess varAcc = (VariableAccess) expression;
127				if(varAcc.getRef() instanceof TypeDecl && !(varAcc.getRef() instanceof TypeParam)) {
128					if(ref instanceof VariableDecl) {
129						VariableDecl varDecl = (VariableDecl) ref;
130						if(!varDecl.isStatic() && !varDecl.getName().equals("class")) {
131							throw new OocCompilationError(this, stack, 
132									"Trying to access member variable "+exprType
133									+"."+getName()+" as if it were static. But it's not.");
134						}
135					}
136				}
137			}
138			if(ref instanceof FunctionDecl && !expression.getType().getName().equals("Class")) {
139				MemberAccess membAcc = new MemberAccess(expression, "class", startToken);
140				this.expression = membAcc;
141				stack.push(this);
142				membAcc.resolve(stack, res, fatal);
143				stack.pop(this);
144			}
145		}
146		
147		if(fatal && ref == null && !dead) {
148			String message = "Can't resolve access to member "+exprType+"."+getName();
149			String guess = guessCorrectName((TypeDecl) exprType.getRef());
150			if(guess != null) {
151				message += " Did you mean "+exprType+"."+guess+" ?";
152			}
153			throw new OocCompilationError(this, stack, message);
154		}
155		
156		return (ref == null && !dead) ? Response.LOOP : Response.OK;
157	}
158
159	private String guessCorrectName(final TypeDecl typeDeclaration) {
160		
161		if(typeDeclaration == null) {
162			return null;
163		}
164		
165		int bestDistance = Integer.MAX_VALUE;
166		String bestMatch = null;
167		
168		for(VariableDecl decl: typeDeclaration.getVariables()) {
169			int distance = Levenshtein.distance(getName(), decl.getName());
170			if(distance < bestDistance) {
171				bestDistance = distance;
172				bestMatch = decl.getName();
173			}
174		}
175		
176		if(bestDistance > 3) return null;
177		return bestMatch;
178		
179	}
180
181	private boolean tryResolve(NodeList<Node> stack, Type exprType, Resolver res) {
182		
183		if(dead) return true;
184		if(exprType == null) return false;
185		
186		Declaration decl = exprType.getRef();
187		if(decl == null) {
188			return false;
189		}
190		
191		if(!(decl instanceof TypeDecl)) {
192			throw new OocCompilationError(this, stack,
193					"Trying to access to a member of not a TypeDecl, but a "+decl);
194		}
195		
196		TypeDecl typeDecl = (TypeDecl) decl;
197		if(ref == null) {
198			ref = typeDecl.getVariable(getName());
199		}
200		
201		if(ref == null && getName().equals("size") && exprType.getPointerLevel() > 0) {
202			FunctionCall sizeofArray = new FunctionCall("sizeof", startToken);
203			sizeofArray.getArguments().add(expression);
204			FunctionCall sizeofType = new FunctionCall("sizeof", startToken);
205			sizeofType.getArguments().add(new TypeAccess(expression.getType().dereference(), expression.startToken));
206			
207			Div div = new Div(sizeofArray, sizeofType, startToken);
208			stack.peek().replace(this, new Parenthesis(div, startToken));
209			dead = true;
210			return false;
211		}
212
213		if(ref == null && exprType.getRef() instanceof CoverDecl && getName().equals("class")) {
214			MemberCall membCall = new MemberCall(expression, "class", "", startToken);
215			if(!stack.peek().replace(this, membCall)) {
216				throw new OocCompilationError(this, stack, "Couldn't replace class access with member call");
217			}
218			membCall.resolve(stack, res, true);
219			dead = true;
220			return false;
221		}
222
223		if(expression instanceof VariableAccess
224				&& ((VariableAccess) expression).getRef() instanceof TypeDecl
225				&& (getName().equals("size") || getName().equals("instanceSize")
226				 || getName().equals("super") || getName().equals("name"))) {
227			if(!exprType.getName().equals("Class")) {
228				MemberAccess membAcc = new MemberAccess(expression, "class", startToken);
229				this.expression = membAcc;
230				stack.push(this);
231				membAcc.resolve(stack, res, true);
232				stack.pop(this);
233				tryResolve(stack, expression.getType(), res);
234				return true;
235			}
236		}
237		
238		if(ref == null) {
239			ref = typeDecl.getFunction(getName(), "", null);
240			if(ref != null) {
241				FunctionDecl fDecl = (FunctionDecl) ref;
242				if(fDecl.getTypeDecl() instanceof ClassDecl) {
243					ClassDecl baseClass = ((ClassDecl) fDecl.getTypeDecl()).getBaseClass(fDecl);
244					ref = baseClass.getFunction(fDecl.getName(), fDecl.getSuffix(), null);
245				}
246			}
247		}
248		
249		return ref != null;
250		
251	}
252	
253	@Override
254	public String toString() {
255		if(expression instanceof VariableAccess) {
256			VariableAccess varAcc = (VariableAccess) expression;
257			//return getClass().getSimpleName()+" "+varAcc.getName()+":"+varAcc.getType()+"->"+getName()+":"+getType();
258			return varAcc.getName()+"->"+getName();
259		}
260		
261		//return "MemberAccess|"+expression+"->"+getName()+":"+getType();
262		return expression+"->"+getName();
263	}
264
265}