PageRenderTime 69ms CodeModel.GetById 18ms app.highlight 44ms RepoModel.GetById 1ms app.codeStats 0ms

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

http://github.com/nddrylliog/ooc
Java | 494 lines | 392 code | 90 blank | 12 comment | 137 complexity | 452e678a1c3402fc94ebaf0d8f33923f 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.MustBeResolved;
  8import org.ooc.frontend.model.tokens.Token;
  9import org.ooc.middle.OocCompilationError;
 10import org.ooc.middle.hobgoblins.Resolver;
 11
 12public class Type extends Node implements MustBeResolved {
 13
 14	public static class Classification {
 15		public static final int POINTER = 1;
 16		public static final int NUMBER = 2;
 17		public static final int CLASS = 4;
 18	}
 19
 20	private boolean groundTypeChecked = false;
 21	
 22	protected String name, namespace;
 23	protected int pointerLevel;
 24	protected int referenceLevel;
 25	private Declaration ref;
 26	
 27	private boolean isArray = false;
 28	private Expression arraySize = null;
 29	
 30	protected NodeList<Access> typeParams;
 31	private boolean isConst = false;
 32	//private String origin;
 33	
 34	private static Type voidType = null;
 35	
 36	public static Type getVoid() {
 37		if(voidType == null) {
 38			voidType = new Type("Void", Token.defaultToken);
 39		}
 40		return voidType;
 41	}
 42	
 43	public Type(String name, Token startToken) {
 44		this(name, 0, startToken);
 45	}
 46	
 47	public Type(String name, int pointerLevel, Token startToken) {
 48		this(name, pointerLevel, 0, startToken);
 49	}
 50	
 51	public Type(String name, int pointerLevel, int referenceLevel, Token startToken) {
 52		super(startToken);
 53		this.name = name;
 54		this.pointerLevel = pointerLevel;
 55		this.referenceLevel = referenceLevel;
 56		this.typeParams = new NodeList<Access>(startToken);
 57		this.namespace = null;
 58		
 59		//StringWriter sw = new StringWriter();
 60		//new Exception().printStackTrace(new PrintWriter(sw));
 61		//this.origin = sw.toString();
 62	}
 63
 64	public String getNamespace() {
 65		return namespace;
 66	}
 67
 68	public void setNamespace(String namespace) {
 69		this.namespace = namespace;
 70	}
 71	
 72	public NodeList<Access> getTypeParams() {
 73		return typeParams;
 74	}
 75
 76	public String getName() {
 77		return name;
 78	}
 79	
 80	public void setName(String name) {
 81		this.name = name;
 82	}
 83
 84	public void setPointerLevel(int pointerLevel) {
 85		this.pointerLevel = pointerLevel;
 86	}
 87
 88	public int getPointerLevel() {
 89		return pointerLevel;
 90	}
 91	
 92	public void setReferenceLevel(int referenceLevel) {
 93		this.referenceLevel = referenceLevel;
 94	}
 95	
 96	public int getReferenceLevel() {
 97		return referenceLevel;
 98	}
 99	
100	public Declaration getRef() {
101		return ref;
102	}
103	
104	public void setRef(Declaration ref) {
105		this.ref = ref;
106	}
107	
108	public boolean isConst() {
109		return isConst;
110	}
111	
112	public void setConst(boolean isConst) {
113		this.isConst = isConst;
114	}
115
116	public void accept(Visitor visitor) throws IOException {
117		visitor.visit(this);
118	}
119	
120	public boolean hasChildren() {
121		return true;
122	}
123
124	public void acceptChildren(Visitor visitor) throws IOException {
125		if(arraySize != null) arraySize.accept(visitor);
126		typeParams.accept(visitor);
127	}
128	
129	@Override
130	public String toString() {
131		
132		StringBuilder sb = new StringBuilder();
133		if(isConst) sb.append("const ");
134		if(namespace != null) sb.append(namespace + " ");
135		sb.append(name);
136		
137		for(int i = 0; i < pointerLevel; i++) {
138			if(isArray) sb.append("[]");
139			else sb.append('*');
140		}
141		for(int i = 0; i < referenceLevel; i++) {
142			sb.append('@');
143		}
144		if(!typeParams.isEmpty()) {
145			sb.append('<');
146			Iterator<Access> iter = typeParams.iterator();
147			while(iter.hasNext()) {
148				Access element = iter.next();
149				if(element instanceof TypeAccess) {
150					sb.append(element.toString());
151				} else if(element instanceof VariableAccess) {
152					sb.append(((VariableAccess) element).getName());
153				} else if(element instanceof FunctionCall) {
154					sb.append(((FunctionCall) element).getName());
155				}
156				if(iter.hasNext()) sb.append(", ");
157			}
158			sb.append('>');
159		}
160		
161		return sb.toString();
162		
163	}
164	
165	public String getMangledName() {
166		
167		if(pointerLevel == 0) {
168			return name;
169		}
170		
171		StringBuilder sb = new StringBuilder();
172		sb.append(name);
173		for(int i = 0; i < pointerLevel + referenceLevel; i++) {
174			sb.append("__star");
175		}
176		return sb.toString();
177		
178	}
179
180	public boolean isVoid() {
181		return (name.equals("void") || name.equals("Void")) && isFlat();
182	}
183
184	public boolean isFlat() {
185		return pointerLevel == 0 && referenceLevel == 0 && !(ref instanceof ClassDecl);
186	}
187	
188	@Override
189	public boolean replace(Node oldie, Node kiddo) {
190		if(oldie == ref) {
191			ref = (Declaration) kiddo;
192			return true;
193		}
194		
195		return false;
196	}
197	
198	@Override
199	public boolean equals(Object obj) {
200		if(obj instanceof Type) {
201			Type type = (Type) obj;
202			boolean result = name.equals(type.name) && pointerLevel == type.getPointerLevel();
203			return result;
204		}
205		return super.equals(obj);
206	}
207	
208	public Response resolve(NodeList<Node> stack, Resolver res, boolean fatal) {
209		
210		if(ref != null) return Response.OK;
211		
212		if(namespace == null) {
213			// no namespace? global namespace.
214			ref = stack.getModule().getType(name);
215		} else {
216			// look for this namespace.
217			NamespaceDecl ns = stack.getModule().getNamespace(namespace);
218			if(ns == null) {
219				throw new OocCompilationError(this, stack, namespace + ": This Namespace Does Not Exist.");
220			}
221			ref = ns.resolveType(name);
222			if(ref == null) {
223				throw new OocCompilationError(this, stack, "Couldn't resolve type " + name + " in namespace " + namespace + "!");
224			}
225		}
226
227		if(ref == null && name.equals("This")) {
228			int index = stack.find(TypeDecl.class);
229			if(index == -1) {
230				throw new OocCompilationError(this, stack, "Using 'This' outside a type definition is meaningless.");
231			}
232			TypeDecl typeDecl = (TypeDecl) stack.get(index);
233			name = typeDecl.getName();
234			ref = typeDecl;
235			return Response.OK;
236		}
237		
238		if(ref == null) {
239			TypeParam param = getTypeParam(stack, name);
240			if(param != null) {
241				ref = param;
242				return Response.OK;
243			}
244		}
245		
246		if(ref == null && fatal) {
247			if(res.params.veryVerbose) {
248				Thread.dumpStack();
249				throw new OocCompilationError(this, stack, "Couldn't resolve type "
250					+getName()+". btw, stack = "+stack.toString(true));
251			}
252			throw new OocCompilationError(this, stack, "Couldn't resolve type "
253					+getName());
254		}
255		
256		if(ref != null) {
257			if(ref instanceof TypeDecl) {
258				TypeDecl tDecl = (TypeDecl) ref;
259				if(!tDecl.getTypeParams().isEmpty()) {
260					if(getTypeParams().size() != tDecl.getTypeParams().size()) {
261						throw new OocCompilationError(this, stack, 
262								"Missing type parameters for "+this+". " +
263								"It should match "+tDecl.getInstanceType());
264					}
265				}
266			}
267		}
268		
269		if(ref == null) {
270			// not resolved? loop.
271			return Response.LOOP;
272		} else if(!groundTypeChecked) {
273			// not checked for ground type? loop.
274			checkGroundType(stack, res, fatal);
275			if(!groundTypeChecked) return Response.LOOP;
276		}
277		return Response.OK;
278		
279	}
280
281	public boolean isResolved() {
282		return ref != null || name.length() == 0; // empty name = any type.
283	}
284	
285	public void setArray(boolean isArray) {
286		this.isArray = isArray;
287	}
288	
289	public boolean isArray() {
290		return isArray;
291	}
292	
293	public Type getGroundType() {
294		return getGroundType(null);
295	}
296	
297	public void checkGroundType(NodeList<Node> stack, Resolver res, boolean fatal) {
298		if(!(this.ref instanceof CoverDecl)) {
299			groundTypeChecked = true;
300		} else {
301			Declaration fromRef = this.ref;
302			CoverDecl coverDecl = (CoverDecl) fromRef;
303			Type fromType = coverDecl.getFromType();
304			
305			while(fromType != null) {
306				if(this == fromType) {
307					throw new OocCompilationError(this, stack, "Type defined in terms of itself: "+this);
308				}
309				
310				fromRef = fromType.getRef();
311				if(fromRef == null) {
312					fromType.resolve(stack, res, false); // Don't ask me why, but this `false` is VERY important!
313				}
314				if(fromRef instanceof CoverDecl) {
315					coverDecl = (CoverDecl) fromRef;
316					fromType = coverDecl.getFromType();
317					continue;
318				}
319				break;
320			}
321		}
322		groundTypeChecked = true;
323	}
324	
325	public Type getGroundType(Resolver res) {
326		if(ref instanceof CoverDecl) {
327			CoverDecl coverDecl = (CoverDecl) ref;
328			Type fromType = coverDecl.getFromType();
329			if(fromType != null && !name.equals(fromType.getName())) {
330				Type rawType = coverDecl.getFromType().getGroundType(res);
331				Type groundType = new Type(
332					rawType.name,
333					rawType.getPointerLevel() + pointerLevel,
334					rawType.getReferenceLevel() + referenceLevel,
335					startToken
336				);
337				groundType.setArray(isArray);
338				if(res == null) {
339					groundType.ref = ref;
340				} else {
341					groundType.resolve(res);
342				}
343				return groundType;
344			}
345		}
346		return this;
347	}
348	
349	public Type getFlatType(Resolver res) {
350		Type returnType = this;
351		while(returnType.ref instanceof CoverDecl) {
352			CoverDecl coverDecl = (CoverDecl) returnType.ref;
353			Type fromType = coverDecl.getFromType();
354			if(fromType == null) break;
355			if(fromType.referenceLevel <= 0) break;
356			
357			returnType = new Type(fromType.name, fromType.pointerLevel - 1,
358					returnType.referenceLevel - 1, fromType.startToken);
359			returnType.resolve(res);
360		}
361		
362		return returnType;
363	}
364
365	public boolean fitsIn(Type innerType) {
366		if (equals(innerType)) return true;
367		if (getClassification() == innerType.getClassification()) return true;
368		return false;
369	}
370	
371	public int getClassification() {
372		if(!isFlat()) return Classification.POINTER;
373		
374		if(name.equals("Int")   || name.equals("UInt")  || name.equals("Short")
375		|| name.equals("UShort")|| name.equals("Long")  || name.equals("ULong")
376		|| name.equals("LLong") || name.equals("ULLong")|| name.equals("Char")
377		|| name.equals("UChar") || name.equals("Int8")  || name.equals("Int16")
378		|| name.equals("Int32") || name.equals("Int64") || name.equals("UInt8")
379		|| name.equals("UInt16")|| name.equals("UInt32")|| name.equals("UInt64")
380		|| name.equals("SizeT") || name.equals("Float") || name.equals("Double")
381		) return Classification.NUMBER;
382		
383		return Classification.CLASS;
384	}
385
386	public void resolve(Resolver res) {
387		ref = res.module.getType(name);
388	}
389
390	public boolean isSuperOf(Type type) {
391		if(type == null) return false;
392		if(this.equals(type)) return false;
393		if(name.length() == 0 || type.name.length() == 0) return false;
394		
395		if(type.getRef() instanceof TypeDecl) {
396			TypeDecl typeDecl = (TypeDecl) type.getRef();
397			if(typeDecl.getSuperRef() != null) {
398				Type superType = typeDecl.getSuperRef().getType();
399				if(superType.getName().equals(this.getName())) {
400					return true;
401				}
402				return isSuperOf(superType);
403			}
404		}
405		return false;
406	}
407
408	public String getHierarchyRepr() {
409		String repr = name;
410		Type t = this;
411		while(t.ref != null) {
412			if(!(t.ref instanceof TypeDecl)) break;
413			TypeDecl typeDecl = (TypeDecl) t.ref;
414			if(typeDecl.getSuperRef() == null) break;
415			t = typeDecl.getSuperRef().getType();
416			repr += ":" + t;
417		}
418		return repr;
419	}
420
421	@Override
422	public Type clone() {
423		Type clone = new Type(name, pointerLevel, referenceLevel, startToken);
424		clone.ref = ref;
425		clone.isArray = isArray;
426		clone.arraySize = arraySize;
427		clone.isConst = isConst;
428		clone.typeParams.addAll(typeParams);
429		return clone;
430	}
431
432	public boolean isGeneric() {
433		return ref instanceof TypeParam;
434	}
435	
436	public boolean isGenericRecursive() {
437		return isGeneric() || !typeParams.isEmpty();
438	}
439
440	public Expression getArraySize() {
441		return arraySize;
442	}
443
444	public void setArraySize(Expression arraySize) {
445		this.arraySize = arraySize;
446	}
447
448	public boolean softEquals(Type type, Resolver res) {
449		if(type == null) return false;
450		
451		// that's a ugly hack - but on the other hand, we can't expect generics
452		// to work properly on opeartor overloads, for example
453		if(name.equals("uint8_t")) return false;
454		//if(isGenericRecursive()) return false;
455		//resolve(res);
456		if(equals(type)) {
457			return true;
458		}
459		
460		Declaration ref = type.getRef();
461		if(ref instanceof TypeDecl) {
462			TypeDecl typeDecl = (TypeDecl) ref;
463			if(typeDecl.getSuperType() != null) {
464				Type subType = typeDecl.getSuperType();
465				return softEquals(subType, res);
466			}
467		}
468		
469		if(		getClassification() == Classification.NUMBER
470		&& type.getClassification() == Classification.NUMBER) return true;
471		return false;
472	}
473	
474	public boolean isPrefixed() {
475	
476		return (ref instanceof ClassDecl || (ref instanceof CoverDecl && !((CoverDecl) ref).isExtern()));
477		
478	}
479
480	public String getUnderName() {
481		
482		if(isPrefixed()) return ((TypeDecl) ref).getUnderName();
483		return getName();
484		
485	}
486
487	public Type dereference() {
488		Type clone = clone();
489		clone.setPointerLevel(getPointerLevel() - 1);
490		return clone;
491	}
492	
493}
494