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