From 0602fdebee4de4de4e82f3738365444ae0ebb937 Mon Sep 17 00:00:00 2001
From: Xun Yang <x299yang@uwaterloo.ca>
Date: Wed, 11 Mar 2020 01:38:33 -0400
Subject: [PATCH] calculate constant expr

---
 AST.py              |  5 +++++
 ExprPrimaryNodes.py | 53 +++++++++++++++++++++++++++++++++++++++++++++
 LineNodes.py        | 16 ++++++++++++++
 Test.py             |  7 ++++--
 UnitNodes.py        | 11 +++++++++-
 5 files changed, 89 insertions(+), 3 deletions(-)

diff --git a/AST.py b/AST.py
index 885000e..5e8ed05 100644
--- a/AST.py
+++ b/AST.py
@@ -64,6 +64,11 @@ class ASTNode():
             if c and hasattr(c, 'checkType'):
                 c.checkType()
 
+    def staticAnalysis(self):
+        for c in self.children:
+            if c and hasattr(c, 'staticAnalysis'):
+                c.staticAnalysis()
+
     def printNodePretty(self, prefix=0):
         pp = pprint.PrettyPrinter(indent=prefix)
         pp.pprint(self.__class__.__name__)
diff --git a/ExprPrimaryNodes.py b/ExprPrimaryNodes.py
index c00680a..d22d024 100644
--- a/ExprPrimaryNodes.py
+++ b/ExprPrimaryNodes.py
@@ -401,6 +401,59 @@ class ExprNode(ASTNode):
 
         raise Exception("ERROR: Incompatible types. Left of {} type can't be used with right of {} type on operation {}".format(self.left.myType.name, self.right.myType.name, self.op))
 
+    # returns True, False, Int or None (for non-constant expr)
+    # children of exprNode is either exprNode or literalNode
+    def getConstant(self):
+        if not hasattr(self.right, "getConstant"):
+            return None
+        cRight = self.right.getConstant()
+        if cRight == None:
+            return None
+
+        # Unary Ops
+        if not self.left:
+            if self.op == '-':
+                return -cRight
+            return not cRight # op = '!'
+
+        else:
+            if not hasattr(self.left, "getConstant"):
+                return None
+            cLeft = self.left.getConstant()
+            if cLeft == None:
+                return None
+
+            # arithmetic
+            if self.op == '+':
+                return cLeft + cRight
+            elif self.op == '-':
+                return cLeft - cRight
+            elif self.op == '*':
+                return cLeft * cRight
+            elif self.op == '/':
+                return cLeft // cRight
+            elif self.op == '%':
+                return cLeft % cRight
+            # Comparison
+            elif self.op == '==':
+                return cLeft == cRight
+            elif self.op == '!=':
+                return cLeft != cRight
+            elif self.op == '>':
+                return cLeft > cRight
+            elif self.op == '<':
+                return cLeft < cRight
+            elif self.op == '>=':
+                return cLeft >= cRight
+            elif self.op == '<=':
+                return cLeft <= cRight
+            # boolean Ops
+            elif self.op == '&&' or self.op == '&':
+                return cLeft and cRight
+            elif self.op == '||' or self.op == '|':
+                return cLeft or cRight
+            else:
+                return None
 
 ###################################################################################
 # fieldAccess primary PERIOD ID
diff --git a/LineNodes.py b/LineNodes.py
index 89cf118..8a0b2a4 100644
--- a/LineNodes.py
+++ b/LineNodes.py
@@ -189,6 +189,15 @@ class WhileNode(ASTNode):
             raise Exception("ERROR: Cannot use non-boolean type for whileBound.")
         self.whileBody.checkType()
 
+    def staticAnalysis(self):
+        # check constant expr
+        if hasattr(self.whileBound, "getConstant"):
+            con = self.whileBound.getConstant()
+
+            if con != None:
+                print(con, self.whileBound.typeName)
+
+
 # returnStatement
 # Rules:
 # 1. returnStatement RETURN expr SEMICO
@@ -279,3 +288,10 @@ class ForNode(ASTNode):
             raise Exception("ERROR: Cannot use non-boolean type for forBound.")
         self.forUpdate.checkType()
         self.bodyStatement.checkType()
+
+    def staticAnalysis(self):
+        # check constant expr
+        if hasattr(self.forBound, "getConstant"):
+            con = self.forBound.getConstant()
+            if con != None:
+                print(con, self.whileBound.typeNam)
diff --git a/Test.py b/Test.py
index 0dec390..de43b30 100644
--- a/Test.py
+++ b/Test.py
@@ -38,7 +38,7 @@ def a2Multiple():
         testCases = [f for f in sys.argv[1:]]
     else:
         # All files in the test directory
-        testDirectory = "./Tests/A3/"
+        testDirectory = "./Tests/A4/"
         testCases = [f.path for f in scandir(testDirectory) if f.is_dir()]
         testCases += [f.path for f in scandir(testDirectory) if not f.is_dir()]
 
@@ -97,7 +97,7 @@ def run(testFiles):
                 print("ERROR in Scanning: " + error)
                 print("**********************************************************")
             return "ERROR in scanning"
-        
+
         # s = "All Tokens: "
         # for token in tokens:
         #     if (token.name and token.lex):
@@ -156,6 +156,9 @@ def run(testFiles):
     except Exception as e:
         return "disamiguateAndTypeChecking: " + e.args[0]
 
+    for t in ASTs:
+        t[1].staticAnalysis()
+
     return ""
 
 main()
diff --git a/UnitNodes.py b/UnitNodes.py
index 5a19d39..c015457 100644
--- a/UnitNodes.py
+++ b/UnitNodes.py
@@ -34,12 +34,21 @@ class LiteralNode(ASTNode):
                 self.value = False
             else:
                 self.value = True
-    
+
     def linkType(self):
         if self.name == "java.lang.String":
             node = self.env.getNode(self.name, "type")
             self.myType = TypeStruct(self.name, node)
 
+    def getConstant(self):
+        if self.name == 'int':
+            return int(self.value)
+        elif self.name == 'boolean':
+            if self.value == 'true':
+                return True
+            return False
+        return self.value
+
 ##################################################################################
 # param type ID
 class ParamNode(ASTNode):
-- 
GitLab