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