From 9bc45ca0226fa5a62f102c1cc8ac1d8070e0cdb2 Mon Sep 17 00:00:00 2001 From: Nicholas Robinson <nwrobins@edu.uwaterloo.ca> Date: Wed, 26 Feb 2020 22:31:46 -0500 Subject: [PATCH] ClassNode Hierarchy Checks --- AST.py | 3 +++ AstBuilding.py | 6 ++++++ TypeNodes.py | 38 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/AST.py b/AST.py index c580827..45489ad 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 4422a37..e4c74cd 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 c371e29..2af75cf 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 -- GitLab