diff --git a/MemberNodes.py b/MemberNodes.py index 5571bbc4f83ee72f9598a8073125ce757ae4ea86..759f7216c3969debdb76d204ba6357ff57020530 100644 --- a/MemberNodes.py +++ b/MemberNodes.py @@ -77,6 +77,8 @@ class MethodNode(ASTNode): if self.body: self.children.append(self.body) + def __eq__(self, other): + return self.name == other.name and self.paramTypes == other.paramTypes def buildEnv(self, parentEnv): env = Env(parentEnv) diff --git a/TypeNodes.py b/TypeNodes.py index 2af75cf24e5245ff016dcbd521a7d8dae331e9b9..fb22369e534fb6c4aec8f27a952fce629faf1985 100644 --- a/TypeNodes.py +++ b/TypeNodes.py @@ -63,8 +63,6 @@ class ClassNode(ASTNode): def linkType(self): # link types to the actual nodes fom the environment (envs already created) - # to use: self.env.getNode(name, namespace) - # print('hello here we go we are in classNode {}'.format(self.name)) if self.env is not None: if self.superClass: newSuperClass = self.env.getNode(self.superClass, 'type') @@ -77,28 +75,66 @@ class ClassNode(ASTNode): def checkHierarchy(self): if self.superClass: # A class must not extend an interface. - if isinstance(self.superClass, InterNode): + if not isinstance(self.superClass, ClassNode): raise Exception("ERROR: Class {} extends interface {}".format(self.name, self.superClass.name)) # A class must not extend a final class. if 'final' in self.superClass.mods: raise Exception("ERROR: Class {} extends final class {}".format(self.name, self.superClass.name)) - # A class must not implement a class. + # A class must not implement a class. No duplicate interfaces. if self.superInter: + unique = [] for inter in self.superInter: - if isinstance(inter, ClassNode): + if not isinstance(inter, InterNode): raise Exception("ERROR: Class {} implements class {}".format(self.name, inter.name)) + if inter.name in unique: + raise Exception("ERROR: Class {} implements duplicate interfaces {}".format(self.name, inter.name)) + unique.append(inter.name) # A class or interface must not declare two methods with the same signature (name and parameter types). - uniqueMethods = [] + unique = [] for method in self.methods: key = (method.name, method.paramTypes) - if key in uniqueMethods: + if key in unique: raise Exception("ERROR: Class {} declares 2 methods with the same signature {}".format(self.name, key[0])) - uniqueMethods.append(key) - # A class or interface must not contain (declare or inherit) two methods with the same signature but different return types + unique.append(key) + # A class must not declare two constructors with the same parameter types + unique = [] + for cons in self.constructors: + key = (cons.name, cons.paramTypes) + if key in unique: + raise Exception("ERROR: Class {} declares 2 constructors with the same parameter types".format(self.name)) + unique.append(key) + # A class or interface must not contain (declare or inherit) two methods with the same signature but different return types + # The hierarchy must be acyclic + contains = self.getContains([]) # A class that contains (declares or inherits) any abstract methods must be abstract. + for con in contains: + if 'abstract' in con.mods and 'abstract' not in self.mods: + raise Exception("ERROR: Non-abstract Class {} contains an abstract method".format(self.name)) + + # hierarchy: string[] + def getContains(self, hierarchy): + # check if not acyclic + if self.name in hierarchy: + raise Exception("ERROR: The hierarchy is not acyclic {}".format(hierarchy)) + hierarchy.append(self.name) + # get contains + contains = self.methods + if self.superClass: + superContains = self.superClass.getContains(hierarchy) + for con in superContains: + conOverwritten = False + for method in self.methods: + if (method == con): + if (method.methodType != con.methodType): + raise Exception("ERROR: Class {} contains 2 methods {} with the same signature but different return types".format(self.name, method.name)) + conOverwritten = True + break + if not conOverwritten: + contains.append(con) + return contains def getConstructor(self, argTypes): for c in self.constructors: @@ -147,3 +183,6 @@ class InterNode(ASTNode): for (index, inter) in enumerate(self.superInter): newSuperInter = self.env.getNode(inter, 'type') self.superInter[index] = newSuperInter + + def checkHierarchy(self): + pass diff --git a/UnitNodes.py b/UnitNodes.py index 65bd3c61c8c7c29f9274c4599b22b18725d616ca..476423887f6838e0279a85c938ce82ea1feb45f3 100644 --- a/UnitNodes.py +++ b/UnitNodes.py @@ -69,3 +69,6 @@ class TypeNode(ASTNode): nameNodes = getParseTreeNodes(['LSQRBRACK'], parseTree) if nameNodes: self.isArray = True + + def __eq__(self, other): + return self.name == other.name \ No newline at end of file