diff --git a/AST.py b/AST.py index 75aedd1839012adf5a2fea88f251d8ab222d9a84..b7c55c7b543c9b97230cf5bcd31626a7e6b40ea8 100644 --- a/AST.py +++ b/AST.py @@ -54,7 +54,9 @@ class ASTNode(): pass def disambigName(self): - pass + for c in self.children: + if c and hasattr(c, 'disambigName'): + c.disambigName() def checkType(self): # self is type correct if all its children are type correct (no exception raised) diff --git a/AstBuilding.py b/AstBuilding.py index 4ac9259bf026a7dc791112d140437782bc7e1da7..5a8bb3907d098af1390a9a56351f7e5f4414fcc0 100644 --- a/AstBuilding.py +++ b/AstBuilding.py @@ -42,9 +42,6 @@ def buildEnvAndLink(ASTs): for t in ASTs: t[1].recurseAction("checkHierarchy") - for t in ASTs: - t[1].checkType() - ####################################################### def disamiguateAndTypeChecking(ASTs): @@ -58,5 +55,7 @@ def disamiguateAndTypeChecking(ASTs): t[1].disambigName() # type checking + for t in ASTs: + t[1].checkType() # resolving the rest of the name \ No newline at end of file diff --git a/Environment.py b/Environment.py index c99dc594b8e640f79231c640be4ac51f18cacbf8..41a0e3262b1080752d67fe6705b04a83c78c406b 100644 --- a/Environment.py +++ b/Environment.py @@ -170,7 +170,6 @@ class CompEnv(Env): def getNode(self, name, namespace): key = (name, namespace) - if key in self.map: return self.map.get(key) elif self.parentEnv: # globalEnv diff --git a/ExprPrimaryNodes.py b/ExprPrimaryNodes.py index 2db92b06da8fde4c88298dd43ddb934273a46917..54cf3bb1ff7dbbcd9c4e0374539dd55550eb1205 100644 --- a/ExprPrimaryNodes.py +++ b/ExprPrimaryNodes.py @@ -29,7 +29,7 @@ def makeNodeFromExpr(parseTree, typeName): if c.name == 'primaryAndArray': return makeNodeFromAllPrimary(c, typeName) elif c.name == 'ID' or c.name == 'COMPID': - return NameNode(c, typeName, typeName) + return NameNode(c, False, typeName) # TODO is this always False?? elif c.name == 'assignment': return AssignNode(c, typeName) elif c.name == 'refType': @@ -357,6 +357,7 @@ class FieldAccessNode(ASTNode): self.ID = NameNode(parseTree.children[2], False, typeName) self.children.append(self.primary) + self.children.append(self.ID) def disambigName(self): if not self.primary: # this implies that the ID has nothing that comes before it @@ -386,10 +387,11 @@ class MethodInvNode(ASTNode): self.children.append(self.primary) self.children.append(self.args) + self.children.append(self.ID) def disambigName(self): if not self.primary: # this implies our ID doesn't have anything that comes before it - if '.' in self.ID: + if isinstance(self.ID, NameNode) and len(self.ID.IDs) > 1: helperDisambigName(self.ID) def checkType1(self): diff --git a/MemberNodes.py b/MemberNodes.py index e3cacccf34d73b5957b09572ae583c3441a4a533..8b9a72c9b9b8724198c6195bbc227ebe15330b11 100644 --- a/MemberNodes.py +++ b/MemberNodes.py @@ -12,6 +12,7 @@ class FieldNode(ASTNode): def __init__(self, parseTree, typeName, order): self.parseTree = parseTree self.name = '' + self.fieldType = '' self.variableDcl = None self.mods = [] self.env = None @@ -24,6 +25,10 @@ class FieldNode(ASTNode): for n in nameNodes: self.name = n.lex + nameNodes = getParseTreeNodes(['type'], parseTree, ['methodMod', 'methodBody', 'variableInit']) + for n in nameNodes: + self.fieldType = TypeNode(n, self.typeName) + for node in parseTree.children: if node.name == 'methodMod': for m in node.children: diff --git a/NameNode.py b/NameNode.py index d2ce96046cefd0117a22333540d6f809f10c5753..4654e2fea3bbdcddd48cf1d2e5258d4a73c8901f 100644 --- a/NameNode.py +++ b/NameNode.py @@ -1,4 +1,7 @@ from AST import ASTNode, getParseTreeNodes +from TheTypeNode import TypeStruct +import MemberNodes +import TypeNodes from Environment import Env # name nodes: contains compID and IDs @@ -28,6 +31,7 @@ class NameNode(ASTNode): self.env = None self.typeName = typeName # the name of the class or interface that this node belongs under self.children = [] + self.myType = None # will become TypeStruct to tell us what the whole is/returns self.name = getParseTreeNodes(["ID", "COMPID"], parseTree)[0].lex @@ -37,7 +41,7 @@ class NameNode(ASTNode): # ASSUMPTION: will never be called when self.IDs is empty def addToPrefix(self, node): # If self.prefixLink is contain, that means our self.prefix wasn't resolved yet - if self.prefixLink == "contain": + if type(self.prefixLink) is str and self.prefixLink == "contain": self.prefixLink = node return @@ -65,7 +69,7 @@ class NameNode(ASTNode): if not self.IDs: return True ID = self.IDs[0] - localVarNode = self.env.findNode(ID, "expr") + localVarNode = self.env.findNode(ID, "expr") # TODO localVarNode is for some reason returning a tuple: (boolean, node) for example (False, <UnitNodes.ParamNode object at 0x7fb353b1e978>). This will need to be fixed in order for NameNode:checkType to work if localVarNode: self.addToPrefix(localVarNode) return True @@ -80,7 +84,7 @@ class NameNode(ASTNode): ID = self.IDs[0] if self.env.findNode(ID, "fieldDcl") or self.env.findNode(ID, "method"): - self.addToPrefix("contains") + self.addToPrefix("contain") return True return False @@ -95,25 +99,33 @@ class NameNode(ASTNode): if currPrefix: currPrefix += "." currPrefix += ID - - typeNode = self.env.getNode(currPrefix, "type") - if typeNode: - - # checking if the next ID is a static field in the class/interface - if index+1 >= len(self.IDs): - return False - - # if the next field is not a method inovocation - # (it could only be a method invocation if self.methodinvoke is true and the next field is the last element in the compID) - if not (self.methodInvoke and index+1 == len(self.IDs)): - staticFieldName = self.IDs[index+1] - typeFieldNode = typeNode.env.getNode(staticFieldName, "fieldDcl") - if "static" in typeFieldNode.mods: - self.prefixLink = typeFieldNode - self.prefix = currPrefix + "." + staticFieldName - self.IDs = self.IDs[index+2:] - return True - return False + + try: + typeNode = self.env.getNode(currPrefix, "type") + except Exception as e: + continue + + # checking if the next ID is a static field in the class/interface + if index+1 >= len(self.IDs): + return False + + # if the next field is not a method inovocation + # (it could only be a method invocation if self.methodinvoke is true and the next field is the last element in the compID) + if not (self.methodInvoke and index+1 == len(self.IDs) - 1): + staticFieldName = self.IDs[index+1] + typeFieldNode = typeNode.env.getNode(staticFieldName, "fieldDcl") + if "static" in typeFieldNode.mods: + self.prefixLink = typeFieldNode + self.prefix = currPrefix + "." + staticFieldName + self.IDs = self.IDs[index+2:] + return True + return False + elif self.methodInvoke and index+1 == len(self.IDs) - 1: + # TODO set the most recent? is this the correct implementation we want? + self.prefixLink = typeNode + self.prefix = currPrefix + self.IDs = self.IDs[index+1:] + return True return False @@ -125,7 +137,6 @@ class NameNode(ASTNode): # (e.g. if there's sth like a.b.c().d, there would be 2 parse tree nodes: methodInvoke(a.b.c) and fieldAccess(d), # then disambigName is only called on the methodInvoke node) def disambigName(self): - # Checking if a1 is "this" if self.checkThis(): return @@ -142,8 +153,37 @@ class NameNode(ASTNode): # Checking if the shortest prefix is a static field if self.checkStatic(): return - raise Exception("ERROR at disambiguating namespace: no prefix of name {} is found in environment.".format(self.name)) + def checkType(self): + # type checking: go through each prefix and determine what type it is, get that type, and check if that type contains the next access + # eg: a.b.c.d - disambigName would have already determined what the heck the shortest prefix is for this, so take that (let's say it's a.b) then check type c, see if it contains d, then get d return type and add it to self.myType + + # if (self.typeName == "Main"): + # print('\nCheck contents of NameNode') + # print('self.typeName ', self.typeName) + # print('self.name ', self.name) + # print('self.IDs ', self.IDs) + # print('self.prefix ', self.prefix) + # print('self.prefixLink ', self.prefixLink) + # print('self.methodInvoke ', self.methodInvoke) + + if self.methodInvoke \ + or not self.prefixLink \ + or (type(self.prefixLink) is str and self.prefixLink == 'contain') \ + or not isinstance(self.prefixLink, ASTNode): # this is regarding the localVarNode issue I pointed out above + return + + curType = self.prefixLink + + if self.IDs: # go through remaining ids + for ID in self.IDs: # curType is a type + curType = curType.env.getNode(ID, 'fieldDcl') + self.myType = curType.fieldType.myType + + else: # found the node for the whole call already + # find the return type for the whole thing + if isinstance(self.prefixLink, MemberNodes.FieldNode): + self.myType = self.prefixLink.fieldType.myType diff --git a/Test.py b/Test.py index 6fa1c55fc8df322fb1ee1037db62b599741de456..5e1195a53ed0f06bc11ddc94c2a73bad1396367c 100644 --- a/Test.py +++ b/Test.py @@ -59,7 +59,6 @@ def a2Multiple(): total += 1 if ret == "": - # print(c) if 'Je_' in c: print(c) print("JE Passed without error") @@ -82,7 +81,6 @@ def run(testFiles): parseTrees = [] for f in testFiles: - # print(f) if f.split("/")[-1] == ".DS_Store": continue content = open(f, "r").read() @@ -120,7 +118,6 @@ def run(testFiles): (tree, error) = parse(tokens) except: print("Exception in Parsing") - # print(tree) # Error in Parsing if tree is None: @@ -134,15 +131,11 @@ def run(testFiles): parseTrees.append((f, tree)) - # print("Scan and Parse Succeeded") - # print("**********************************************************") + # for (n, t) in parseTrees: + # if n == "Tests/A3/J1_accessstaticfield/Main.java": + # print(n) + # print(t) - # try: - # ASTs = astBuild(parseTrees) - # except Exception as e: - # print("ERROR at AST building for file {}".format(f)) - # traceback.print_stack() - # return "building AST: " + e.args[0] ASTs = astBuild(parseTrees) # for (n, t) in ASTs: @@ -154,25 +147,13 @@ def run(testFiles): try: buildEnvAndLink(ASTs) except Exception as e: - # print(testFiles) - # print("error at environment building and linking") - # print(e) return "buildEnvAndLink: " + e.args[0] - # print("<<<<------- after buildEnvAndLink -------->>>>>>") - # for (n, t) in ASTs: - # print(n) - # print("--------------------") - # t.printTree() - # print("\n \n\n \n") + try: + disamiguateAndTypeChecking(ASTs) + except Exception as e: + return "disamiguateAndTypeChecking: " + e.args[0] - # try: - # disamiguateAndTypeChecking(ASTs) - # except Exception as e: - # return "Disambiguate and Type checking: " + e.args[0] - disamiguateAndTypeChecking(ASTs) - # print("Succeeded") - # print("**********************************************************") return "" main()