PageRenderTime 386ms CodeModel.GetById 181ms app.highlight 19ms RepoModel.GetById 182ms app.codeStats 0ms

/src/org/ooc/middle/hobgoblins/Checker.java

http://github.com/nddrylliog/ooc
Java | 199 lines | 138 code | 29 blank | 32 comment | 52 complexity | f7a0139f732cee3fae2de9e0b77e6e29 MD5 | raw file
  1package org.ooc.middle.hobgoblins;
  2
  3import java.io.IOException;
  4import java.util.HashMap;
  5
  6import org.ooc.frontend.BuildParams;
  7import org.ooc.frontend.model.ClassDecl;
  8import org.ooc.frontend.model.CoverDecl;
  9import org.ooc.frontend.model.FunctionCall;
 10import org.ooc.frontend.model.FunctionDecl;
 11import org.ooc.frontend.model.Module;
 12import org.ooc.frontend.model.Node;
 13import org.ooc.frontend.model.NodeList;
 14import org.ooc.frontend.model.Type;
 15import org.ooc.frontend.model.TypeDecl;
 16import org.ooc.frontend.model.ValuedReturn;
 17import org.ooc.frontend.model.VariableAccess;
 18import org.ooc.frontend.model.VariableDecl;
 19import org.ooc.middle.Hobgoblin;
 20import org.ooc.middle.OocCompilationError;
 21import org.ooc.middle.walkers.Opportunist;
 22import org.ooc.middle.walkers.SketchyNosy;
 23
 24/**
 25 * The Checker makes sure everything has been resolved properly. It also makes
 26 * sure type names are CamelCase and func/vars camelCase
 27 * 
 28 * @author Amos Wenger
 29 */
 30public class Checker implements Hobgoblin {
 31
 32	final HashMap<String, FunctionDecl> funcNames = new HashMap<String, FunctionDecl>();
 33	final HashMap<TypeDecl, HashMap<String, FunctionDecl>> classFuncNames = new HashMap<TypeDecl, HashMap<String, FunctionDecl>>();
 34	
 35	public boolean process(Module module, BuildParams params) throws IOException {
 36		
 37		SketchyNosy.get(new Opportunist<Node>() {
 38
 39			public boolean take(Node node, NodeList<Node> stack) throws IOException {
 40				if(node instanceof FunctionCall) checkFunctionCall((FunctionCall) node, stack);
 41				else if(node instanceof VariableAccess) checkVariableAccess((VariableAccess) node, stack);
 42				else if(node instanceof FunctionDecl) checkFunctionDecl((FunctionDecl) node, stack);
 43				else if(node instanceof VariableDecl) checkVariableDecl((VariableDecl) node, stack);
 44				else if(node instanceof TypeDecl) checkTypeDecl((TypeDecl) node, stack);
 45				else if(node instanceof ValuedReturn) checkValuedReturn((ValuedReturn) node, stack);
 46				return true;
 47			}
 48			
 49			private void checkFunctionCall(FunctionCall node, NodeList<Node> stack) {
 50				if(node.getImpl() == null) {
 51					throw new OocCompilationError(node, stack,
 52							node.getClass().getSimpleName()+" to "+node.getName()
 53							+" hasn't been resolved :/");
 54				}
 55			}
 56			
 57			private void checkVariableAccess(VariableAccess node, NodeList<Node> stack) {
 58				if(node.getRef() == null) {
 59					throw new OocCompilationError(node, stack,
 60							node.getClass().getSimpleName()+" to "+node.getName()
 61							+" hasn't been resolved :S stack = "+stack.toString(true));
 62				}
 63			}
 64			
 65			private void checkFunctionDecl(FunctionDecl node, NodeList<Node> stack) {
 66				if(node.getName().length() > 0) {
 67					if(Character.isUpperCase(node.getName().charAt(0)) && !node.isExtern()) {
 68						// turned it into a warning
 69						new OocCompilationError(node, stack,
 70								"Upper-case function name '"+node.getProtoRepr()
 71								+"'. Function should always begin with a lowercase letter, e.g. camelCase").printStackTrace();
 72					}
 73				}
 74				
 75				if(!node.isFromPointer()) { 
 76					String name = node.getName();
 77					if(node.getTypeDecl() != null) {
 78						name = node.getTypeDecl().toString() + "." + name;
 79					}
 80					
 81					String suffixedName = node.getName()+"_"+node.getSuffix();
 82					FunctionDecl other;
 83					if(node.isMember()) {
 84						HashMap<String, FunctionDecl> set = classFuncNames.get(node.getTypeDecl());
 85						if(set == null) {
 86							set = new HashMap<String, FunctionDecl>();
 87							classFuncNames.put(node.getTypeDecl(), set);
 88						}
 89						other = set.put(suffixedName, node);
 90					} else {
 91						other = funcNames.put(suffixedName, node);
 92					}
 93					if(other != null) {
 94						// if either are unversioned, it's an immediate lose
 95						if(node.getVersion() == null || other.getVersion() == null) {
 96							throwError(node, other, stack, name);
 97						}
 98						// if their version is the same, it's a lose too.
 99						if(node.getVersion().equals(other.getVersion())) {
100							throwError(node, other, stack, name);
101						}
102					}
103				}
104			}
105			
106			void throwError(FunctionDecl node, FunctionDecl other, NodeList<Node> stack, String name)
107			throws OocCompilationError {
108				if(name.equals("class") && stack.find(CoverDecl.class) != -1) return;
109				// FIXME debug
110				new OocCompilationError(node, stack,
111						"Two functions have the same name '"+name
112							+"', add suffix to one of them! (even if they have different signatures). e.g. "
113							+name+": func ~suffix "+node.getArgsRepr()+" -> "+node.getReturnType()).printStackTrace();
114				throw new OocCompilationError(other, stack, "The other definition is here:");
115			}
116			
117			
118			private void checkVariableDecl(VariableDecl node, NodeList<Node> stack) {
119				Type varDeclType = node.getType();
120				if(varDeclType != null && varDeclType.getRef() != null && !varDeclType.getRef().isExtern()
121						&& varDeclType.getName().length() > 0
122						&& !(varDeclType.isGeneric())
123						&& Character.isLowerCase(varDeclType.getName().charAt(0))) {
124					throw new OocCompilationError(varDeclType, stack,
125							"Variable declaration has type '"+varDeclType.getName()+
126							"', which begins with a lowercase letter."+
127							" Types should always begin with an uppercase letter, e.g. CamelCase");
128				}
129				/*
130				for(VariableDeclAtom atom: node.getAtoms()) {
131					if(atom.getName().length() == 0) continue;
132					if(Character.isUpperCase(atom.getName().charAt(0)) && !node.getType().isConst()
133							&& node.shouldBeLowerCase()) {
134						throw new OocCompilationError(atom, stack,
135								"Upper-case variable name '"+atom.getName()+": "+node.getType()
136								+"'. Variables should always begin with a lowercase letter, e.g. camelCase");
137					}
138				}
139				*/
140			}
141			
142			private void checkTypeDecl(TypeDecl node, NodeList<Node> stack)
143				throws OocCompilationError {
144				if(node.isExtern() || node.getName().length() == 0) return;
145				if(Character.isLowerCase(node.getName().charAt(0))) {
146					throw new OocCompilationError(node, stack,
147						"Lower-case type name '"+node.getName()
148						+"'. Types should always begin with a capital letter, e.g. CamelCase (stack = "+stack);
149				
150				}
151				
152				if(!(node instanceof ClassDecl)) return;
153				ClassDecl classDecl = (ClassDecl) node;
154				
155				if(classDecl.isAbstract()) return;
156				
157				NodeList<FunctionDecl> functions = new NodeList<FunctionDecl>();
158				classDecl.getFunctionsRecursive(functions);
159				
160				for(FunctionDecl decl: functions) {
161					FunctionDecl realDecl = classDecl.getFunction(decl.getName(), decl.getSuffix(), null);
162					if(realDecl.isAbstract()) {
163						throw new OocCompilationError(classDecl, stack, "Class "+classDecl.getName()
164								+" must implement "+decl.getProtoRepr()+", or be declared abstract. Little help: "+decl.getStub());
165					}
166					
167					//ClassDecl baseClass = classDecl.getBaseClass(decl);
168					//FunctionDecl baseDecl = baseClass.getFunction(realDecl.getName(), realDecl.getSuffix(), null);
169					// TODO check arg types and return type also
170					/*
171					if(baseDecl != null && realDecl.getArguments().size() != baseDecl.getArguments().size()) {
172						throw new OocCompilationError(decl, stack, "Class "+classDecl.getName()
173							+" must implement "+decl.getProtoRepr()+" with the same arguments & return type as "
174							+baseDecl.getArguments()+". realArgs = "+realDecl.getArguments()
175							+", baseArgs = "+baseDecl.getArguments());
176					}
177					*/
178				}
179			}
180			
181			private void checkValuedReturn(ValuedReturn node,
182					NodeList<Node> stack) {
183
184				FunctionDecl decl = (FunctionDecl) stack.get(stack.find(FunctionDecl.class));
185				if(decl.getReturnType().isVoid()) {
186					throw new OocCompilationError(node, stack,
187							"Returning a value in function "+decl.getProtoRepr()
188								+" which is declared as returning nothing");
189				}
190				
191			}
192
193		}).visit(module);
194		
195		return false;
196		
197	}
198
199}