diff --git a/AST.py b/AST.py index c5808276329f955c8c6dae273a0d755b2136651e..45489ad9d141677117ea8bd91094c31ed8b24aca 100644 --- a/AST.py +++ b/AST.py @@ -34,6 +34,9 @@ class ASTNode(): def linkType(self): pass + def checkHierarchy(self): + pass + def printNodePretty(self, prefix=0): pp = pprint.PrettyPrinter(indent=prefix) pp.pprint(self.__class__.__name__) diff --git a/AstBuilding.py b/AstBuilding.py index 4422a37b0574e3a3497f77ac4f4b2cbf9be3cbdc..e4c74cd012bc694e71e963f9ece80deacdb7c1e3 100644 --- a/AstBuilding.py +++ b/AstBuilding.py @@ -30,6 +30,12 @@ def buildEnvAndLink(ASTs): # t[1].buildEnvFromImports(globalEnv) t[1].recurseAction("linkType") + # hierarchy checking + print('--------->>> hierarchy checking time!') + for t in ASTs: + # t[1].buildEnvFromImports(globalEnv) + t[1].recurseAction("checkHierarchy") + ####################################################### # # ast: Node diff --git a/TypeNodes.py b/TypeNodes.py index c371e2952a88e5412d8e8ff07650762f1ab29f31..2af75cf24e5245ff016dcbd521a7d8dae331e9b9 100644 --- a/TypeNodes.py +++ b/TypeNodes.py @@ -66,14 +66,40 @@ class ClassNode(ASTNode): # 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 is not '': + if self.superClass: newSuperClass = self.env.getNode(self.superClass, 'type') self.superClass = newSuperClass - if self.superInter is not []: + if self.superInter: for (index, inter) in enumerate(self.superInter): newSuperInter = self.env.getNode(inter, 'type') self.superInter[index] = newSuperInter + def checkHierarchy(self): + if self.superClass: + # A class must not extend an interface. + if isinstance(self.superClass, InterNode): + 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. + if self.superInter: + for inter in self.superInter: + if isinstance(inter, ClassNode): + raise Exception("ERROR: Class {} implements class {}".format(self.name, inter.name)) + + # A class or interface must not declare two methods with the same signature (name and parameter types). + uniqueMethods = [] + for method in self.methods: + key = (method.name, method.paramTypes) + if key in uniqueMethods: + 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 + # A class must not declare two constructors with the same parameter types + + # A class that contains (declares or inherits) any abstract methods must be abstract. + def getConstructor(self, argTypes): for c in self.constructors: if c.paramTypes == argTypes: @@ -113,3 +139,11 @@ class InterNode(ASTNode): env.addtoEnv(c) self.env = env return env + + def linkType(self): + # link types to the actual nodes fom the environment (envs already created) + if self.env is not None: + if self.superInter: + for (index, inter) in enumerate(self.superInter): + newSuperInter = self.env.getNode(inter, 'type') + self.superInter[index] = newSuperInter