PageRenderTime 477ms CodeModel.GetById 151ms app.highlight 130ms RepoModel.GetById 192ms app.codeStats 0ms

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

http://github.com/nddrylliog/ooc
Java | 345 lines | 272 code | 66 blank | 7 comment | 65 complexity | 318a1a10237d3ba03024f0c34313cf56 MD5 | raw file
  1package org.ooc.frontend.model;
  2
  3import java.io.IOException;
  4import java.util.Iterator;
  5import java.util.LinkedHashMap;
  6
  7import org.ooc.frontend.Visitor;
  8import org.ooc.frontend.model.interfaces.Versioned;
  9import org.ooc.frontend.model.tokens.Token;
 10import org.ooc.middle.hobgoblins.Resolver;
 11
 12
 13public abstract class TypeDecl extends Declaration implements Scope, Generic, Versioned {
 14
 15	private VersionBlock version = null;
 16	
 17	protected NodeList<VariableDecl> variables;
 18	protected NodeList<FunctionDecl> functions;
 19	
 20	protected Type superType;
 21	
 22	protected Type instanceType;
 23	protected LinkedHashMap<String, TypeParam> typeParams;
 24	
 25	protected VariableDecl thisDecl;
 26	
 27	private boolean finishedGhosting = false;
 28	
 29	public TypeDecl(String name, Type superType, Module module, Token startToken) {
 30		super(name, startToken, module);
 31		this.superType = superType;
 32		this.variables = new NodeList<VariableDecl>(startToken);
 33		this.functions = new NodeList<FunctionDecl>(startToken);
 34		this.instanceType = new Type(name, startToken);
 35		instanceType.setRef(this);
 36		this.typeParams = new LinkedHashMap<String, TypeParam>();
 37		this.thisDecl = new VariableDecl(instanceType, "this", startToken, module);
 38	}
 39	
 40	public VariableDecl getThisDecl() {
 41		return thisDecl;
 42	}
 43	
 44	public Type getInstanceType() {
 45		return instanceType;
 46	}
 47	
 48	public boolean hasVariables() {
 49		return !variables.isEmpty();
 50	}
 51	
 52	public boolean hasFunctions() {
 53		return !functions.isEmpty();
 54	}
 55	
 56	public Iterable<VariableDecl> getVariables() {
 57		return variables;
 58	}
 59	
 60	public void getVariables(NodeList<VariableDecl> variables) {
 61		variables.addAll(this.variables);
 62	}
 63	
 64	public void addVariable(VariableDecl decl) {
 65		decl.setTypeDecl(this);
 66		variables.add(decl);
 67	}
 68	
 69	public Iterable<FunctionDecl> getFunctions() {
 70		return functions;
 71	}
 72	
 73	public Type getSuperType() {
 74		return superType;
 75	}
 76	
 77	public String getSuperName() {
 78		return superType == null ? "" : superType.getName();
 79	}
 80	
 81	public void setSuperType(Type superType) {
 82		this.superType = superType;
 83	}
 84	
 85	public FunctionDecl getFunction(FunctionCall call) {
 86		return getFunction(call.getName(), call.getSuffix(), call);
 87	}
 88	
 89	public FunctionDecl getFunction(String name, String suffix, FunctionCall call, boolean recursive) {
 90		return getFunction(name, suffix,call, recursive, 0, null);
 91	}
 92	
 93	public FunctionDecl getFunction(String name, String suffix, FunctionCall call,
 94			boolean recursive, int bestScoreParam, FunctionDecl bestMatchParam) {
 95		
 96		int bestScore = bestScoreParam;
 97		FunctionDecl bestMatch = bestMatchParam;
 98		for(FunctionDecl func : functions) {
 99			if(func.getName().equals(name) && (suffix == null || func.getSuffix().equals(suffix))) {
100				if(call == null) return func;
101				int score = call.getScore(func);
102				if(score == -1) return null;
103				if(score > bestScore) {
104					bestScore = score;
105					bestMatch = func;
106				}
107			}
108		}
109		
110		if(recursive && getSuperRef() != null) return getSuperRef().getFunction(name, suffix, call, true, bestScore, bestMatch);
111		return bestMatch;
112	}
113	
114	public TypeDecl getSuperRef() {
115		if(superType == null || superType.getRef() == null) return null;
116		return (TypeDecl) superType.getRef();
117	}
118
119	public FunctionDecl getFunction(String name, String suffix, FunctionCall call) {
120		return getFunction(name, suffix, call, true, 0, null);
121	}
122	
123	public void getFunctions(NodeList<FunctionDecl> functions) {
124		functions.addAll(this.functions);
125	}
126	
127	public void addFunction(FunctionDecl decl) {
128		decl.setTypeDecl(this);
129		
130		if(!decl.isStatic()) {
131			Token tok = decl.getArguments().isEmpty() ? startToken : decl.getArguments().getFirst().startToken;
132			decl.getArguments().add(0, new RegularArgument(getInstanceType(), "this", tok));
133		} else {
134			// static functions must have the same type params as the class
135			decl.getTypeParams().putAll(typeParams);
136		}
137		
138		if(decl.isSpecialFunc()) {
139			FunctionDecl already = getFunction(decl.getName(), decl.getSuffix(), null);
140			if(already != null) functions.remove(already);
141		}
142		functions.add(decl);
143	}
144	
145	public void getFunctionsRecursive(NodeList<FunctionDecl> functions) {
146		for(FunctionDecl decl: this.functions) {
147			boolean already = false;
148			for(FunctionDecl decl2: functions) {
149				if(decl != decl2 && decl.sameProto(decl2)) {
150					already = true;
151					break;
152				}
153			}
154			if(!already) functions.add(decl);
155		}
156		if(getSuperRef() != null) getSuperRef().getFunctionsRecursive(functions);
157	}
158	
159	public VariableDecl getVariable(String name) {
160		if(!finishedGhosting) {
161			return null;
162		}
163		
164		String realTypeParam = translateTypeParam(name);
165		
166		if(realTypeParam != null) {
167			return getVariable(realTypeParam);
168		}
169		
170		for(VariableDecl decl: variables) {
171			if(decl.getName().equals(name)) {
172				return decl;
173			}
174		}
175		if(getSuperRef() != null) return getSuperRef().getVariable(name);
176		return null;
177	}
178	
179	private String translateTypeParam(String name) {
180		
181		// Iterator: class <T>
182		// HashMap: class <K, V> extends Iterator<V>
183		// V needs to be written at T
184		// If needle is contained in our typeParams, we need to figure out where it's used
185		if(typeParams.containsKey(name)) {
186			String result = null;
187			
188			Iterator<Access> iter1 = getSuperType().getTypeParams().iterator();
189			Iterator<String> iter2 = getSuperRef().getTypeParams().keySet().iterator();
190			while(iter1.hasNext()) {
191				Access a = iter1.next();
192				String candidate = iter2.next();
193				if(a instanceof VariableAccess) {
194					VariableAccess va = (VariableAccess) a;
195					if(va.getName().equals(name) && !name.equals(candidate)) {
196						result = candidate;
197						break;
198					}
199				}
200			}
201			
202			return result;
203		}
204		return null;
205	}
206
207	public void acceptChildren(Visitor visitor) throws IOException {
208		if(superType != null) superType.accept(visitor);
209		for(TypeParam genType: typeParams.values()) {
210			genType.accept(visitor);
211		}
212		variables.accept(visitor);
213		functions.accept(visitor);
214		instanceType.accept(visitor);
215	}
216	
217	public boolean hasChildren() {
218		return true;
219	}
220	
221	@Override
222	public boolean replace(Node oldie, Node kiddo) {
223		return false;
224	}
225	
226	@Override
227	public TypeDecl getTypeDecl() {
228		return this;
229	}
230	
231	public Type getType() {
232		return getInstanceType();
233	}
234
235	public String getVariablesRepr() {
236		return variables.toString();
237	}
238	
239	public String getFunctionsRepr() {
240		return functions.toString();
241	}
242	
243	public LinkedHashMap<String, TypeParam> getTypeParams() {
244		return typeParams;
245	}
246	
247	public void addTypeParam(TypeParam genType) {
248		typeParams.put(genType.getName(), genType);
249		genType.getArgument().setTypeDecl(this);
250		instanceType.getTypeParams().add(new VariableAccess(genType.getName(), genType.startToken));
251		variables.add(0, genType.getArgument());
252	}
253	
254	@Override
255	public Response resolve(NodeList<Node> stack, Resolver res, boolean fatal) {
256		stack.push(this);
257		ghostTypeParams(stack, res, fatal);
258        stack.pop(this);
259		
260		return super.resolve(stack, res, fatal);
261	}
262
263	private Response ghostTypeParams(NodeList<Node> stack, Resolver res, boolean fatal) {
264		if(finishedGhosting) return Response.OK;
265		
266		// remove ghost type arguments
267        if(superType != null) {
268            Response response = superType.resolve(stack, res, fatal);
269            if(response != Response.OK) {
270                stack.pop(this);
271                return response;
272            }
273            
274            Type sType = this.superType;
275            while(sType != null) {
276                TypeDecl sTypeRef = (TypeDecl) sType.getRef();
277                if(sTypeRef == null) {
278                	// Need super type ref
279                	stack.pop(this);
280                	return Response.LOOP;
281                }
282                for(TypeParam typeArg: typeParams.values()) {
283                    for(TypeParam candidate: sTypeRef.getTypeParams().values()) {
284                        if(typeArg.getName().equals(candidate.getName())) {
285                        	for(int i = 0; i < variables.size(); i++) {
286                        		if(variables.get(i).getName().equals(typeArg.getName())) {
287                        			variables.removeAt(i);
288                        			break;
289                        		}
290                        	}
291                        }
292                    }
293                }
294                sType = sTypeRef.superType;
295            }
296        }
297        
298        finishedGhosting = true;
299        return Response.OK;
300        
301	}
302	
303	@Override
304	public String toString() {
305		StringBuilder sB = new StringBuilder(getClass().getSimpleName());
306		sB.append(' ');
307		sB.append(name);
308		if(!typeParams.isEmpty()) {
309			sB.append('<');
310			boolean isFirst = true;
311			for(String typeParam: typeParams.keySet()) {
312				if(isFirst) isFirst = false;
313				else        sB.append(", ");
314				sB.append(typeParam);
315			}
316			sB.append('>');
317		}
318		
319		return sB.toString();
320	}
321	
322	public String getUnderName() {
323		if(module != null && !isExtern())
324			return module.getMemberPrefix() + getName();
325		return getName();
326	}
327	
328	public Module getModule() {
329		return module;
330	}
331	
332	public VersionBlock getVersion() {
333		return version;
334	}
335	
336	public void setVersion(VersionBlock block) {
337		this.version = block;
338	}
339
340	@Override
341	public void addToModule(Module module) {
342		module.addType(this);
343	}
344
345}