From 3fb133b896ba9dfa3e3c333183117d75de4d6dd4 Mon Sep 17 00:00:00 2001 From: Xun Yang <x299yang@uwaterloo.ca> Date: Fri, 21 Feb 2020 18:02:19 -0500 Subject: [PATCH] Environment --- AST.py | 16 ++++--- AstBuilding.py | 23 +++++++++ Environment.py | 128 ++++++++++++++++++++++++++----------------------- Test.py | 2 +- 4 files changed, 103 insertions(+), 66 deletions(-) diff --git a/AST.py b/AST.py index a7a89fe..c7fe49a 100644 --- a/AST.py +++ b/AST.py @@ -16,13 +16,15 @@ class ASTNode(): # call the same method in each class and its children recursively # the methods that represent an action would return arguments to be used in # the child nodes' method if neccessary - def recurseAction(self, actionName, args): - func = self.getattr(actionName) + def recurseAction(self, actionName, args=None): + func = getattr(self, actionName) result = None - if func: + if func and args: result = func(args) + elif func: + result = func() for c in self.children: - c.recurseAction(result) + c.recurseAction(actionName, result) # use the parse tree to populate current AST node and construct child AST nodes def buildASTNodeRecursive(self): @@ -35,8 +37,10 @@ class ASTNode(): pp.pprint(vars(self)) pp.pprint("-----children-----") prefix += 1 - for c in self.children: - c.printNodePretty(prefix) + return prefix + + def printTree(self): + self.recurseAction('printNodePretty') # Utils ###################################################### diff --git a/AstBuilding.py b/AstBuilding.py index 5b96449..190bd21 100644 --- a/AstBuilding.py +++ b/AstBuilding.py @@ -1,4 +1,6 @@ from CompNode import CompNode +from pprpint import pprint +from Env import GlobalEnv # tree: (filename, parseTree) def astBuild(trees): @@ -7,6 +9,27 @@ def astBuild(trees): ASTs.append((n, CompNode(t))) return ASTs +def buildEnvAndLink(ASTs): + # build env + globalEnv = GlobalEnv() + for t in ASTs: + globalEnv.addtoEnv(t) + # build Env inside each class / interface + t.typeDcl.recurseAction("buildEnv") + + # type Linking + for t in ASTs: + t.buildEnvFromImports(globalEnv) + # t.typeDcl.recurseAction("linkType") + + print ("\n\n###################### global Env ####################") + pprint(GlobalEnv) + for t in ASTs: + printt ("\n\n###################### Comp Unit Env ####################") + t.recurseAction("printEnv") + +####################################################### + # # ast: Node # def weed(ast): # res = ast.weed() diff --git a/Environment.py b/Environment.py index e3badd8..8404087 100644 --- a/Environment.py +++ b/Environment.py @@ -1,68 +1,78 @@ -from ASTNode import ScopeNode, Environment +class Env: + nodeToNamespace = dict({ + 'FieldNode': 'field', + 'InterNode': 'interface', + 'ClassNode': 'class', + 'MethodNode': 'method' + }) -################################################################## + def __init__(self, parentEnv): + self.parentEnv = parentEnv + self.map = {} # {(name, namespace) -> node} -# give a list of parseTrees, returns the global Environemnt object and -# a list of classNodes with globalEnv attached to them -def buildGlobalEnv(parseTrees): - gEnv = Environment(None) - ASTs = [] + def addtoEnv(node): + # use node.__class__.__name__ to get namespace + nodeType = node.__class__.__name__ + if not self.nodeToNamespace.contains(nodeType): + namespace = 'local' + namespace = self.nodeToNamespace.get(nodeType) + # Add to Env + key = (node.name, namespace) + if self.map.contains(key): + raise Exception('ERROR: Declaration of {} is already in current Environment'.format(node.name)) + self.map[key] = node - for t in parseTrees: - # add imports - imports = getParseTreeNodes(['importDcl'], t) - for i in imports: - importNames = getParseTreeNodes(['ID', 'COMPID', 'IMPORTALL'], i) - for n in importNames: - gEnv.addName(n.lex, 'package', None) + def getNode(name, namespace): + key = (name, namespace) - # TODO: figure out package name - packages = getParseTreeNodes('packageDcl', t) - pNames = [] - for p in packages: - pNames.extend(getParseTreeNodes(['ID', 'COMPID'], p)) - if pNames: - pNames = pNames[0] - else: - pNames = 'no packageName' + if self.map.contains(key): + return self.map.get(key) + elif namespace == 'local': + key2 = (name, 'field') + if self.map.contains(key2): + return self.map.get(key2) + elif parentEnv: + return parentEnv.getNode(name, namespace) + raise Exception("ERROR: Can't find definition of {} in the Environment".format(name)) - # add class to global Env - classDcl = getParseTreeNodes('classDcl', t) - interfaceDcl = getParseTreeNodes('interfaceDcl', t) +################################### - if not classDcl: - intNode = ScopeNode(interfaceDcl[0], gEnv) - ASTs.append(intNode) - gEnv.addName(pNames+ " " + intNode.name, 'interface', intNode) - else: - classNode = ScopeNode(classDcl[0], gEnv) - ASTs.append(classNode) - gEnv.addName(pNames+ " " + classNode.name, 'class', classNode) +class GlobalEnv(Env): + def __init__(self): + super().__init__(None) + #self.map = {} # {(Canonical name, namespace) -> node} + self.pacakgeMap = {} # {packageName -> {(simpleName, namespace) -> node}} + # A map of maps + # contains duplicate info as self.map for easy searching - #prints + # input: Compiliation Unit Node (CompNode) + def addtoEnv(node): + pName = node.packageName + typeDcl = node.typeDcl + typeDclType = typeDcl.__class__.__name__ + # at global level there are only class and interface + namespace = self.nodeToNamespace.get(typeDclType) - print('----------- global env ------------') - for g in gEnv.map: - print(g) - for gg in gEnv.map[g]: - print(gg) - print('----------- ASTs -----------------') - for a in ASTs: - print(a.name) - return gEnv, ASTs + # Add to map + mapKey = (pName + '.' + typeDclType.name, namespace) + if self.map.contains(mapKey): + raise Exception('ERROR: Declaration of {} is already in current Environment'.format(pName + '.' + typeDclType.name)) + self.map[mapKey] = typeDcl -# Utils: given a parseTree and a list of names, traverse the tree -# to return a list of tree nodes(on the same level) that -# has one of those names -def getParseTreeNodes(names, tree): - result = [] - if tree.name in names: - return result.append(tree) - if not tree.children: - return [] - for n in tree.children: - if n.name in names: - result.append(n) - else: - result.extend(getParseTreeNodes(names, n)) - return result + # Add to packageMap + pMapKey = (typeDclType.name, namespace) + if not self.pacakgeMap.contains(pName): + self.pacakgeMap[pName] = {} + + if not self.pacakgeMap[pName].contains(pMapKey): + raise Exception('ERROR: Declaration of {} is already in current Environment'.format(pName + '.' + typeDclType.name)) + self.pacakgeMap[pName][pMapKey] = typeDcl + + # Use getNode() from base class to get node using Canonical Name (full name) + + # method for getting all the nodes under a package (import All) + # returns a dict of types under that package name + def getNodesByPackage(pName): + if not self.pacakgeMap.contains(pName): + raise Exception("ERROR: Can't find definition of package {} in the Environment".format(pName)) + return self.pacakgeMap.get(pName) diff --git a/Test.py b/Test.py index c69c96d..ba6c77e 100644 --- a/Test.py +++ b/Test.py @@ -103,7 +103,7 @@ def run(testFiles): for (n, t) in ASTs: print(n) print("--------------------") - t.printNodePretty() + t.printTree() print("\n \n\n \n") -- GitLab