Skip to content
Snippets Groups Projects
Commit 101e58b8 authored by Nicholas Robinson's avatar Nicholas Robinson
Browse files

reachability basics

- change Test.py to run reachabilityChecking
- basic ASTNode reachCheck
- implemented reachability in: MethodNode, IfNode, WhileNode, ReturnNode
- tiny bit of cleanup (whitespace)
parent 0602fdeb
No related branches found
No related tags found
No related merge requests found
......@@ -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__)
......
......@@ -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()
......@@ -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
......
......@@ -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
......
......@@ -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 ""
......
......@@ -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):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment