-
Nicholas Robinson authored
- fixed getParseTreeNodes - fixed getting name for TypeNode
Nicholas Robinson authored- fixed getParseTreeNodes - fixed getting name for TypeNode
Environment.py 5.59 KiB
import string
class Env:
nodeToNamespace = dict({
'FieldNode': 'fieldDcl',
'InterNode': 'type',
'ClassNode': 'type',
'MethodNode': 'method',
'VarDclNode': 'expr'
})
def __init__(self, parentEnv):
self.parentEnv = parentEnv
self.map = {}
# entries in the map:
# type: (typeName, 'type') -> node
# method: (methodName. 'method') -> {paramTypes -> node} for method overloding
# expr: (name, 'expr') -> node
def addtoEnv(self, node):
# use node.__class__.__name__ to get namespace
nodeType = node.__class__.__name__
if nodeType not in self.nodeToNamespace:
namespace = 'expr'
else:
namespace = self.nodeToNamespace.get(nodeType)
# Add to Env
key = (node.name, namespace)
# add entry in nested map for method overloding
if namespace == 'method':
if key not in self.map:
self.map[key] = {}
self.map[key][node.paramTypes] = node
else:
if key in self.map:
raise Exception('ERROR: Declaration of {} is already in current Environment'.format(node.name))
if namespace == 'expr':
self.map[key] = (False, node)
else:
self.map[key] = node
def getNode(self, name, namespace):
key = (name, namespace)
if key in self.map:
return self.map.get(key)
elif self.parentEnv:
return self.parentEnv.getNode(name, namespace)
raise Exception("ERROR: Can't find definition of {} in the Environment".format(name))
# A wrapper around getNode to find if node exists in environment already
def findNode(self, name, namespace):
try:
self.getNode(name, namespace)
except:
return False # node is not found in environment
return True
###################################
class GlobalEnv(Env):
def __init__(self):
super().__init__(None)
#self.map = {} # {Canonical name -> node}
self.packageMap = {} # {packageName -> {(simpleName, namespace) -> node}}
# A map of maps
# contains duplicate info as self.map for easy searching
# input: Compiliation Unit Node (CompNode)
def addtoEnv(self, 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)
# Add to map
mapKey = pName + '.' + typeDcl.name
if mapKey in self.map:
raise Exception('ERROR: Declaration of {} is already in current Environment'.format(pName + '.' + typeDcl.name))
self.map[mapKey] = typeDcl
# Add to packageMap
pMapKey = (typeDcl.name, namespace)
if not pName in self.packageMap:
self.packageMap[pName] = {}
if pMapKey in self.packageMap[pName]:
raise Exception('ERROR: Declaration of {} is already in current Environment'.format(pName + '.' + typeDcl.name))
self.packageMap[pName][pMapKey] = typeDcl
# Use getNode() from base class to get node using Canonical Name (full name)
def getNode(self, key, imported, packageName):
# TODO: error if ambiguous
# TODO: not sure whether name is canonical or not????
# i.e. there are more than one of this type. Currently it only gets the first occurence
name = key[0]
# 1. enclosing class/interface
# - already did
# 2. single-type import
if name in imported and name in self.map:
return self.map.get(name)
# 3. type in the current package
full = packageName + '.' + name
# print(full)
if full in self.map:
return self.map.get(full)
# 4. import-on-demand
for i in imported:
if '*' in i:
full = i.replace("*", name)
if full in self.map:
return self.map.get(full)
# imported implicitly: java.io.*, java.lang.*, java.util.*
implicitly = ['java.lang.', 'java.io.', 'java.util.']
for i in implicitly:
if i in name and name in self.map:
return self.map.get(name)
elif (i+name) in self.map:
return self.map.get(i+name)
raise Exception("ERROR: Can't find definition of {} in the Environment".format(key))
# method for getting all the nodes under a package (import All)
# returns a dict of types under that package name
def getNodesByPackage(self, pName):
if not pName in self.packageMap:
raise Exception("ERROR: Can't find definition of package {} in the Environment".format(pName))
return self.packageMap.get(pName)
###################################
class CompEnv(Env):
def __init__(self, parentEnv, imported, packageName):
super().__init__(parentEnv) # globalEnv is parentEnv
self.imported = imported # list of strings that have been imported in this comp
self.packageName = packageName # string of the current file's package name
def getNode(self, name, namespace):
key = (name, namespace)
if key in self.map:
return self.map.get(key)
elif self.parentEnv: # globalEnv
return self.parentEnv.getNode(key, self.imported, self.packageName)
raise Exception("ERROR: Can't find definition of {} in the Environment".format(name))