From d5a4bcd8e40597af85a31fe830760d1f0791e35d Mon Sep 17 00:00:00 2001
From: pycsham <shampuiyanchloe@gmail.com>
Date: Fri, 6 Mar 2020 18:53:45 -0500
Subject: [PATCH] implemented method return type checking

---
 AST.py         | 18 ++++++++++++++++++
 LineNodes.py   |  2 +-
 MemberNodes.py | 32 ++++++++++++++++++++++++++++++--
 3 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/AST.py b/AST.py
index 7a67a49..885000e 100644
--- a/AST.py
+++ b/AST.py
@@ -108,3 +108,21 @@ def getParseTreeNodes(names, tree, terminateList = []):
         else:
             result.extend(getParseTreeNodes(names, n, terminateList))
     return result
+
+def getASTNode(names, AST):
+    result = []
+    if not AST:
+        return result
+    if AST.__class__.__name__ in names:
+        result.append(AST)
+        return result
+    if not AST.children:
+        return []
+    for n in AST.children:
+        if not n:
+            continue
+        if n.__class__.__name__ in names:
+            result.append(n)
+        else:
+            result.extend(getASTNode(names, n))
+    return result
diff --git a/LineNodes.py b/LineNodes.py
index 52f1a02..57d091e 100644
--- a/LineNodes.py
+++ b/LineNodes.py
@@ -209,7 +209,7 @@ class ReturnNode(ASTNode):
             self.expr.checkType()
             self.myType = self.expr.myType
         else:
-            self.myType = TypeStruct("void", None)
+            self.myType = None # this is None as returning a value of type Void is invalid even in a function with type Void
 
 # forStatement and forStatementNoShortIf
 # Rules:
diff --git a/MemberNodes.py b/MemberNodes.py
index 13ba951..4eeabd1 100644
--- a/MemberNodes.py
+++ b/MemberNodes.py
@@ -1,4 +1,4 @@
-from AST import ASTNode, getParseTreeNodes
+from AST import ASTNode, getParseTreeNodes, getASTNode
 from LineNodes import BlockNode, VarDclNode
 from ExprPrimaryNodes import makeNodeFromExpr
 from UnitNodes import ParamNode
@@ -107,9 +107,37 @@ class MethodNode(ASTNode):
         return env
 
     def checkType(self):
-        if self.methodType: # constructor
+        if self.methodType: # constructor would be None
             self.myType = self.methodType.myType
         for p in self.params:
             p.checkType()
         if self.body:
             self.body.checkType()
+
+        # Checking return types against the function type
+        # 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)
+
+        # Checking for cases where there are no return statements
+        if not returnNodes:
+            # 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)) 
+
+        # Checking for cases where there are return statements
+        for n in returnNodes:
+            # Checking for functions of type void
+            # 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))  
+
+            # 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
-- 
GitLab