From 101e58b8fe092d5c44cbca1fcfcd8413579f5118 Mon Sep 17 00:00:00 2001 From: Nicholas Robinson <nwrobins@edu.uwaterloo.ca> Date: Wed, 11 Mar 2020 01:52:22 -0400 Subject: [PATCH] reachability basics - change Test.py to run reachabilityChecking - basic ASTNode reachCheck - implemented reachability in: MethodNode, IfNode, WhileNode, ReturnNode - tiny bit of cleanup (whitespace) --- AST.py | 22 ++++++++++++++++++++++ AstBuilding.py | 13 ++++++++++--- LineNodes.py | 43 +++++++++++++++++++++++++++++++++++++++++++ MemberNodes.py | 14 ++++++++++++++ Test.py | 12 +++++++----- TypeNodes.py | 1 - 6 files changed, 96 insertions(+), 9 deletions(-) diff --git a/AST.py b/AST.py index 5e8ed05..fbb2702 100644 --- a/AST.py +++ b/AST.py @@ -14,6 +14,10 @@ class ASTNode(): self.children = [] self.myType = "" # either empty string or a TypeStruct + # reachability: None = not set, True = maybe, False = no + self.inMaybe = None # either None or True/False + self.outMaybe = None # either None or True/False + # Do certains actions on every node of the AST tree # call the same method in each class and its children recursively # the methods that represent an action would return arguments to be used in @@ -69,6 +73,24 @@ class ASTNode(): if c and hasattr(c, 'staticAnalysis'): c.staticAnalysis() + # return outMaybe + def reachCheck(self, inMaybe = True): + if inMaybe == False: + # error if in[s] = no for any s + # I don't think it should get to here... but maybe? + raise Exception("in[s] = no for a certain {}".format(type(self))) + + self.inMaybe = inMaybe + self.outMaybe = self.inMaybe + lastOut = self.inMaybe + + for c in self.children: + if c and hasattr(c, 'reachCheck'): + lastOut = c.reachCheck(lastOut) + self.outMaybe = self.outMaybe and lastOut + + return self.outMaybe + def printNodePretty(self, prefix=0): pp = pprint.PrettyPrinter(indent=prefix) pp.pprint(self.__class__.__name__) diff --git a/AstBuilding.py b/AstBuilding.py index 035a8f9..5563a7b 100644 --- a/AstBuilding.py +++ b/AstBuilding.py @@ -9,8 +9,6 @@ def astBuild(trees): ASTs.append((n, CompNode(t))) return ASTs - - def buildEnvAndLink(ASTs): # build env globalEnv = GlobalEnv() @@ -51,4 +49,13 @@ def disamiguateAndTypeChecking(ASTs): for t in ASTs: t[1].checkType() - # resolving the rest of the name \ No newline at end of file + # resolving the rest of the name + +####################################################### + +def reachabilityChecking(ASTs): + for t in ASTs: + t[1].reachCheck() + + # for t in ASTs: + # t[1].staticAnalysis() diff --git a/LineNodes.py b/LineNodes.py index 8a0b2a4..30058be 100644 --- a/LineNodes.py +++ b/LineNodes.py @@ -164,6 +164,27 @@ class IfNode(ASTNode): if self.elseBody: self.elseBody.checkType() + def reachCheck(self, inMaybe = True): + if inMaybe == False: + # error if in[s] = no for any s + raise Exception("in[s] = no for IfNode in class {}".format(self.typeName)) + + self.inMaybe = inMaybe + s1 = self.ifBody.reachCheck(self.inMaybe) + if not self.elseBody: + # L : if (E) S + # in[S] = in[L] + # out[L] = in[L] + self.outMaybe = self.inMaybe + else: + # L : if (E) S1 else S2 + # in[S1] = in[L] + # in[S2] = in[L] + # out[L] = out[S1] V out[S2] + s2 = self.elseBody.reachCheck(self.inMaybe) + self.outMaybe = s1 or s2 + return self.outMaybe + # whileStatement, whileStatementNoShortIf # Rules: # 1. whileStatement WHILE LPAREN expr RPAREN statement @@ -197,6 +218,17 @@ class WhileNode(ASTNode): if con != None: print(con, self.whileBound.typeName) + def reachCheck(self, inMaybe = True): + if inMaybe == False: + # error if in[s] = no for any s + raise Exception("in[s] = no for WhileNode in class {}".format(self.typeName)) + + # L : while (E) S + # in[S] = in[L] + # out[L] = in[L] + self.inMaybe = inMaybe + self.whileBound.reachCheck(self.inMaybe) + self.outMaybe = self.inMaybe # returnStatement # Rules: @@ -226,6 +258,17 @@ class ReturnNode(ASTNode): else: self.myType = None # this is None as returning a value of type Void is invalid even in a function with type Void + def reachCheck(self, inMaybe = True): + if inMaybe == False: + # error if in[s] = no for any s + raise Exception("in[s] = no for ReturnNode in class {}".format(self.typeName)) + + # L : return, L : return E + # out[L] = no + self.inMaybe = inMaybe + self.outMaybe = False + return self.outMaybe + # forStatement and forStatementNoShortIf # Rules: # 1. forStatement FOR LPAREN forInit SEMICO forExpr SEMICO forInit RPAREN statement diff --git a/MemberNodes.py b/MemberNodes.py index 7a0bb3e..cfafa1a 100644 --- a/MemberNodes.py +++ b/MemberNodes.py @@ -169,6 +169,20 @@ class MethodNode(ASTNode): raise Exception("ERROR: return type of function {} doesn't match with return statement.".format(self.name)) return + def reachCheck(self, inMaybe = True): + # self.inMaybe is always true for methods + self.inMaybe = True + self.outMaybe = False + + if self.body: + self.outMaybe = self.body.reachCheck() + + # error if out[(non-void) method body] = maybe + # self.methodType is an empty string if it's a constructor + if type(self.methodType) != str and self.methodType.myType.name != "void" and self.outMaybe == True: + raise Exception("Non-void method '{}' in class '{}' does not return".format(self.name, self.typeName)) + return self.outMaybe + ############# helper for forward ref checking ######## # Input: AST Node # Output: A list of names to be check diff --git a/Test.py b/Test.py index de43b30..a08be2a 100644 --- a/Test.py +++ b/Test.py @@ -6,7 +6,7 @@ import traceback from Scanning import scan from Parsing import parse -from AstBuilding import astBuild, buildEnvAndLink, disamiguateAndTypeChecking +from AstBuilding import astBuild, buildEnvAndLink, disamiguateAndTypeChecking, reachabilityChecking import Weeding @@ -48,7 +48,7 @@ def a2Multiple(): for c in testCases: # get all files from stdlib folder - testFiles = [join(dp, f) for dp, dn, filenames in walk('stdlib/3.0/java/') for f in filenames] + testFiles = [join(dp, f) for dp, dn, filenames in walk('stdlib/4.0/java/') for f in filenames] if '.java' in c: # add this one file @@ -155,9 +155,11 @@ def run(testFiles): disamiguateAndTypeChecking(ASTs) except Exception as e: return "disamiguateAndTypeChecking: " + e.args[0] - - for t in ASTs: - t[1].staticAnalysis() + + try: + reachabilityChecking(ASTs) + except Exception as e: + return "reachabilityChecking: " + e.args[0] return "" diff --git a/TypeNodes.py b/TypeNodes.py index 20cd7a5..87c79ad 100644 --- a/TypeNodes.py +++ b/TypeNodes.py @@ -261,7 +261,6 @@ class ClassNode(ClassInterNode): raise Exception("ERROR: Constructor {0} doesn't have the same name as class {1}".format(constructor.name, self.name)) return - ##################################################################### # interface class InterNode(ClassInterNode): -- GitLab