From 69a84e4c2f794be6ac86fe2516065a8ed8b743d8 Mon Sep 17 00:00:00 2001
From: Xun Yang <x299yang@uwaterloo.ca>
Date: Fri, 6 Mar 2020 21:04:17 -0500
Subject: [PATCH] forward ref checks

---
 MemberNodes.py | 44 ++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 40 insertions(+), 4 deletions(-)

diff --git a/MemberNodes.py b/MemberNodes.py
index 4eeabd1..87caedc 100644
--- a/MemberNodes.py
+++ b/MemberNodes.py
@@ -37,6 +37,20 @@ class FieldNode(ASTNode):
 
     def checkType(self):
         self.variableDcl.checkType()
+        # check forward reference
+        if self.variableDcl.variableInit:
+            allNames = getForwardRefNames(self.variableDcl.variableInit)
+            from pprint import pprint
+
+            for n in allNames:
+                if n.prefixLink is self.variableDcl:
+                    raise Exception("ERROR: Forward reference of field {}  in itself is not allowed.".format(n.prefixLink.name))
+
+                if n.prefixLink.__class__.__name__ == 'FieldNode' \
+                and n.prefixLink.typeName == self.typeName \
+                and self.order <= n.prefixLink.order \
+                and "this" not in n.name:
+                    raise Exception("ERROR: Forward reference of field {} is not allowed.".format(n.prefixLink.name))
 
 ###########################################################
 
@@ -106,6 +120,12 @@ class MethodNode(ASTNode):
         self.env = env
         return env
 
+    def disambigName(self):
+        if self.body:
+            self.body.disambigName()
+        for p in self.params:
+            p.disambigName()
+
     def checkType(self):
         if self.methodType: # constructor would be None
             self.myType = self.methodType.myType
@@ -118,7 +138,7 @@ class MethodNode(ASTNode):
         # No method body: do not check type as function isn't implemented
         if not self.body:
             return
-        
+
         # With method body
         returnNodes = getASTNode(["ReturnNode"], self.body)
 
@@ -127,7 +147,7 @@ class MethodNode(ASTNode):
             # Either a constructor or the function has type Void
             if not self.methodType or self.myType.name == "void":
                 return
-            raise Exception("ERROR: no return statement at function {}".format(self.name)) 
+            raise Exception("ERROR: no return statement at function {}".format(self.name))
 
         # Checking for cases where there are return statements
         for n in returnNodes:
@@ -135,9 +155,25 @@ class MethodNode(ASTNode):
             # Only valid if either the function doesn't have a return statement(checked above), or the return statement is a semicolon (return;)
             if self.myType.name == "void":
                 if n.myType:
-                    raise Exception("ERROR: return type of function {} doesn't match with return statement.".format(self.name))  
+                    raise Exception("ERROR: return type of function {} doesn't match with return statement.".format(self.name))
 
             # Checking for non void cases
             if not self.myType.assignable(n.myType):
                 raise Exception("ERROR: return type of function {} doesn't match with return statement.".format(self.name))
-        return
\ No newline at end of file
+        return
+
+############# helper for forward ref checking ########
+# Input: AST Node
+# Output: A list of names to be check
+def getForwardRefNames(node):
+    if node.__class__.__name__ == 'NameNode':
+        return [node]
+
+    result = []
+    if node.__class__.__name__ == 'AssignNode':
+        result.extend(getForwardRefNames(node.right))
+    else:
+        for c in node.children:
+            result.extend(getForwardRefNames(c))
+
+    return result
-- 
GitLab