From ea1020292db7a8653d736ec2c4c91bee1caa45ca Mon Sep 17 00:00:00 2001 From: Nicholas Robinson <nwrobins@edu.uwaterloo.ca> Date: Thu, 27 Feb 2020 23:22:30 -0500 Subject: [PATCH] Hierarchy stuff - some more class stuff --- MemberNodes.py | 2 ++ TypeNodes.py | 57 ++++++++++++++++++++++++++++++++++++++++++-------- UnitNodes.py | 3 +++ 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/MemberNodes.py b/MemberNodes.py index 5571bbc..759f721 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 2af75cf..fb22369 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 65bd3c6..4764238 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 -- GitLab