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

j1_reachability_return & static errors

parent a07f6098
No related branches found
No related tags found
No related merge requests found
from AST import ASTNode, getParseTreeNodes from AST import ASTNode, getParseTreeNodes
from Environment import Env from Environment import Env
from UnitNodes import LiteralNode from UnitNodes import LiteralNode
import MemberNodes import MemberNodes
from TheTypeNode import TypeNode, TypeStruct from TheTypeNode import TypeNode, TypeStruct
from NameNode import NameNode, checkProtected from NameNode import NameNode, checkProtected
# file containing smaller (lower level nodes) in the AST # file containing smaller (lower level nodes) in the AST
# nodes in this file: # nodes in this file:
# ArgsNode # ArgsNode
# ArrayAccessNode # ArrayAccessNode
# ArrayCreateNode # ArrayCreateNode
# AssignNode # AssignNode
# CastNode # CastNode
# ClassCreateNode # ClassCreateNode
# ExprNode # ExprNode
# FieldAccessNode # FieldAccessNode
# MethodInvNode # MethodInvNode
# TODO: go over nodes in this file to see if need to overright buildEnv # TODO: go over nodes in this file to see if need to overright buildEnv
########################################################### ###########################################################
# factory methods # factory methods
########################################################### ###########################################################
# parses the expr node in the parse tree to be either ID or CastNode or ExprNode # parses the expr node in the parse tree to be either ID or CastNode or ExprNode
def makeNodeFromExpr(parseTree, typeName): def makeNodeFromExpr(parseTree, typeName):
c = parseTree c = parseTree
while (42): while (42):
if c.name == 'primaryAndArray': if c.name == 'primaryAndArray':
return makeNodeFromAllPrimary(c, typeName) return makeNodeFromAllPrimary(c, typeName)
elif c.name == 'ID' or c.name == 'COMPID': elif c.name == 'ID' or c.name == 'COMPID':
return NameNode(c, False, typeName) # TODO is this always False?? return NameNode(c, False, typeName) # TODO is this always False??
elif c.name == 'assignment': elif c.name == 'assignment':
return AssignNode(c, typeName) return AssignNode(c, typeName)
elif c.name == 'refType': elif c.name == 'refType':
return TypeNode(c, typeName) return TypeNode(c, typeName)
elif len(c.children) == 1: elif len(c.children) == 1:
c = c.children[0] c = c.children[0]
elif c.name == 'castExpr': elif c.name == 'castExpr':
return CastNode(c, typeName) return CastNode(c, typeName)
else: else:
return ExprNode(c, typeName) return ExprNode(c, typeName)
# parses the primaryAndArray/primary/primaryNoArrayAccess node in the parse tree and return corresponding AST nodes # parses the primaryAndArray/primary/primaryNoArrayAccess node in the parse tree and return corresponding AST nodes
def makeNodeFromAllPrimary(parseTree, typeName): def makeNodeFromAllPrimary(parseTree, typeName):
if parseTree.name == 'primaryAndArray': if parseTree.name == 'primaryAndArray':
if parseTree.children[0].name == 'arrayCreationExpr': if parseTree.children[0].name == 'arrayCreationExpr':
parseTree = parseTree.children[0] parseTree = parseTree.children[0]
return ArrayCreateNode(parseTree, typeName) return ArrayCreateNode(parseTree, typeName)
elif parseTree.children[0].name == 'primary': elif parseTree.children[0].name == 'primary':
if parseTree.children[0].children[0].name == 'arrayAccess': if parseTree.children[0].children[0].name == 'arrayAccess':
return ArrayAccessNode(parseTree.children[0].children[0], typeName) return ArrayAccessNode(parseTree.children[0].children[0], typeName)
parseTree = parseTree.children[0].children[0] parseTree = parseTree.children[0].children[0]
if parseTree.name == 'primary': if parseTree.name == 'primary':
if parseTree.children[0].name == 'arrayAccess': if parseTree.children[0].name == 'arrayAccess':
return ArrayAccessNode(parseTree.children[0], typeName) return ArrayAccessNode(parseTree.children[0], typeName)
parseTree = parseTree.children[0] parseTree = parseTree.children[0]
node = parseTree.children[0] node = parseTree.children[0]
if node.name == 'literal': if node.name == 'literal':
return LiteralNode(node, typeName) return LiteralNode(node, typeName)
elif node.name == 'LPAREN': # primaryNoArrayAccess LPAREN expr RPAREN elif node.name == 'LPAREN': # primaryNoArrayAccess LPAREN expr RPAREN
return makeNodeFromExpr(parseTree.children[1], typeName) return makeNodeFromExpr(parseTree.children[1], typeName)
elif node.name == 'classInstanceCreate': elif node.name == 'classInstanceCreate':
return ClassCreateNode(node.children[0], typeName) return ClassCreateNode(node.children[0], typeName)
elif node.name == 'methodInvoc': elif node.name == 'methodInvoc':
return MethodInvNode(node, typeName) return MethodInvNode(node, typeName)
elif node.name == 'fieldAccess': elif node.name == 'fieldAccess':
return FieldAccessNode(node, typeName) return FieldAccessNode(node, typeName)
else: else:
raise Exception('ERROR: something wrong at primaryNoArrayAccess') raise Exception('ERROR: something wrong at primaryNoArrayAccess')
########################################################### ###########################################################
# helper methods # helper methods
########################################################### ###########################################################
def helperDisambigName(node): def helperDisambigName(node):
if node and node.__class__.__name__ == "NameNode": if node and node.__class__.__name__ == "NameNode":
try: try:
node.disambigName() node.disambigName()
except Exception as e: except Exception as e:
raise e raise e
########################################################### ###########################################################
########################### Node Definitions ##################################### ########################### Node Definitions #####################################
################################################################################### ###################################################################################
# args exprs, exprs expr COMMA exprs # args exprs, exprs expr COMMA exprs
class ArgsNode(ASTNode): class ArgsNode(ASTNode):
# always list all fields in the init method to show the class structure # always list all fields in the init method to show the class structure
def __init__(self, parseTree, typeName): def __init__(self, parseTree, typeName):
self.parseTree = parseTree self.parseTree = parseTree
self.exprs = [] # a list of expressions self.exprs = [] # a list of expressions
self.env = None self.env = None
self.children = [] self.children = []
self.typeName = typeName # the type (class/interface) this node belongs under self.typeName = typeName # the type (class/interface) this node belongs under
exprs = getParseTreeNodes(['expr'], parseTree) exprs = getParseTreeNodes(['expr'], parseTree)
for e in exprs: for e in exprs:
self.exprs.append(makeNodeFromExpr(e, typeName)) self.exprs.append(makeNodeFromExpr(e, typeName))
self.children.extend(self.exprs) self.children.extend(self.exprs)
def disambigName(self): def disambigName(self):
for expr in self.exprs: for expr in self.exprs:
expr.disambigName() expr.disambigName()
# helperDisambigName(expr) # helperDisambigName(expr)
################################################################################### ###################################################################################
# Array Access # Array Access
class ArrayAccessNode(ASTNode): class ArrayAccessNode(ASTNode):
# always list all fields in the init method to show the class structure # always list all fields in the init method to show the class structure
def __init__(self, parseTree, typeName): def __init__(self, parseTree, typeName):
self.parseTree = parseTree self.parseTree = parseTree
self.array = '' # either a variableName, a field, or array access self.array = '' # either a variableName, a field, or array access
self.index = '' # expr self.index = '' # expr
self.env = None self.env = None
self.children = [] self.children = []
self.typeName = typeName # the type (class/interface) this node belongs under self.typeName = typeName # the type (class/interface) this node belongs under
# input parse tree is either: arrayAccess name LSQRBRACK expr RSQRBRACK # input parse tree is either: arrayAccess name LSQRBRACK expr RSQRBRACK
# arrayAccess ID LSQRBRACK expr RSQRBRACK # arrayAccess ID LSQRBRACK expr RSQRBRACK
# arrayAccess primaryNoArrayAccess LSQRBRACK expr RSQRBRACK # arrayAccess primaryNoArrayAccess LSQRBRACK expr RSQRBRACK
if (parseTree.children[0].name == 'primaryNoArrayAccess'): if (parseTree.children[0].name == 'primaryNoArrayAccess'):
self.array = makeNodeFromAllPrimary(parseTree.children[0], typeName) self.array = makeNodeFromAllPrimary(parseTree.children[0], typeName)
else: else:
self.array = NameNode(parseTree.children[0], False, typeName) self.array = NameNode(parseTree.children[0], False, typeName)
self.index = makeNodeFromExpr(parseTree.children[2], typeName) self.index = makeNodeFromExpr(parseTree.children[2], typeName)
self.children.append(self.array) self.children.append(self.array)
self.children.append(self.index) self.children.append(self.index)
def disambigName(self): def disambigName(self):
self.array.disambigName() self.array.disambigName()
self.index.disambigName() self.index.disambigName()
def checkType(self): def checkType(self):
self.array.disambigName() # hacky fix, not sure why disambigName wasn't called before self.array.disambigName() # hacky fix, not sure why disambigName wasn't called before
self.array.checkType() self.array.checkType()
self.index.checkType() self.index.checkType()
if not self.array.myType.isArray: if not self.array.myType.isArray:
raise Exception("ERROR: Cannot perform array access on non-array {}".format(self.array.name)) raise Exception("ERROR: Cannot perform array access on non-array {}".format(self.array.name))
if not self.index.myType.isNum(): if not self.index.myType.isNum():
raise Exception("ERROR: Array index must be a number.") raise Exception("ERROR: Array index must be a number.")
self.myType = TypeStruct(self.array.myType.name, self.array.myType.typePointer) self.myType = TypeStruct(self.array.myType.name, self.array.myType.typePointer)
################################################################################### ###################################################################################
# arrayCreationExpr # arrayCreationExpr
# arrayCreationExpr NEW primitiveType LSQRBRACK expr RSQRBRACK # arrayCreationExpr NEW primitiveType LSQRBRACK expr RSQRBRACK
# arrayCreationExpr NEW name LSQRBRACK expr RSQRBRACK # arrayCreationExpr NEW name LSQRBRACK expr RSQRBRACK
# arrayCreationExpr NEW primitiveType LSQRBRACK RSQRBRACK # arrayCreationExpr NEW primitiveType LSQRBRACK RSQRBRACK
# arrayCreationExpr NEW name LSQRBRACK RSQRBRACK # arrayCreationExpr NEW name LSQRBRACK RSQRBRACK
class ArrayCreateNode(ASTNode): class ArrayCreateNode(ASTNode):
# always list all fields in the init method to show the class structure # always list all fields in the init method to show the class structure
def __init__(self, parseTree, typeName): def __init__(self, parseTree, typeName):
self.parseTree = parseTree self.parseTree = parseTree
self.arrayType = '' self.arrayType = ''
self.arraySize = 0 # or Expr self.arraySize = 0 # or Expr
self.env = None self.env = None
self.children = [] self.children = []
self.typeName = typeName # the type (class/interface) this node belongs under self.typeName = typeName # the type (class/interface) this node belongs under
# input is arrayCreationExpr NEW type LSQRBRACK expr RSQRBRACK # input is arrayCreationExpr NEW type LSQRBRACK expr RSQRBRACK
self.arrayType = TypeNode(parseTree.children[1], typeName) self.arrayType = TypeNode(parseTree.children[1], typeName)
expr = getParseTreeNodes(['expr'], parseTree) expr = getParseTreeNodes(['expr'], parseTree)
if len(expr) > 0: if len(expr) > 0:
self.arraySize = makeNodeFromExpr(expr[0], typeName) self.arraySize = makeNodeFromExpr(expr[0], typeName)
self.children.append(self.arrayType) self.children.append(self.arrayType)
self.children.append(self.arraySize) self.children.append(self.arraySize)
def disambigName(self): def disambigName(self):
self.arraySize.disambigName() self.arraySize.disambigName()
# helperDisambigName(self.arraySize) # helperDisambigName(self.arraySize)
def checkType(self): def checkType(self):
if self.arraySize != 0: if self.arraySize != 0:
self.arraySize.checkType() self.arraySize.checkType()
if not self.arraySize.myType.isNum(): if not self.arraySize.myType.isNum():
raise Exception("ERROR: Array index must be a number.") raise Exception("ERROR: Array index must be a number.")
self.myType = TypeStruct(self.arrayType.myType.name, self.arrayType.myType.typePointer) self.myType = TypeStruct(self.arrayType.myType.name, self.arrayType.myType.typePointer)
self.myType.isArray = True self.myType.isArray = True
################################################################################### ###################################################################################
# assignment leftHandSide ASSIGN expr # assignment leftHandSide ASSIGN expr
class AssignNode(ASTNode): class AssignNode(ASTNode):
# always list all fields in the init method to show the class structure # always list all fields in the init method to show the class structure
def __init__(self, parseTree, typeName): def __init__(self, parseTree, typeName):
self.parseTree = parseTree self.parseTree = parseTree
self.left = None self.left = None
self.right = makeNodeFromExpr(parseTree.children[2], typeName) self.right = makeNodeFromExpr(parseTree.children[2], typeName)
self.env = None self.env = None
self.children = [] self.children = []
self.typeName = typeName # the type (class/interface) this node belongs under self.typeName = typeName # the type (class/interface) this node belongs under
if parseTree.children[0].children[0].name == 'fieldAccess': if parseTree.children[0].children[0].name == 'fieldAccess':
self.left = FieldAccessNode(parseTree.children[0].children[0], typeName) self.left = FieldAccessNode(parseTree.children[0].children[0], typeName)
elif parseTree.children[0].children[0].name == 'arrayAccess': elif parseTree.children[0].children[0].name == 'arrayAccess':
self.left = ArrayAccessNode(parseTree.children[0].children[0], typeName) self.left = ArrayAccessNode(parseTree.children[0].children[0], typeName)
else: else:
self.left = NameNode(parseTree.children[0].children[0], False, typeName) self.left = NameNode(parseTree.children[0].children[0], False, typeName)
self.children.append(self.right) self.children.append(self.right)
self.children.append(self.left) self.children.append(self.left)
def disambigName(self): def disambigName(self):
self.left.disambigName() self.left.disambigName()
self.right.disambigName() self.right.disambigName()
# helperDisambigName(self.right) # helperDisambigName(self.right)
# helperDisambigName(self.left) # helperDisambigName(self.left)
def checkType(self): def checkType(self):
self.left.checkType() self.left.checkType()
self.right.checkType() self.right.checkType()
if self.left.myType.assignable(self.right.myType): if self.left.myType.assignable(self.right.myType):
self.myType = self.left.myType self.myType = self.left.myType
return return
raise Exception("ERROR: assignment operation failed. Cannot assign type {0} to type {1} at class {2}".format(self.left.myType.name, self.right.myType.name, self.typeName)) raise Exception("ERROR: assignment operation failed. Cannot assign type {0} to type {1} at class {2}".format(self.left.myType.name, self.right.myType.name, self.typeName))
def reachCheck(self, inMaybe): def reachCheck(self, inMaybe):
if not inMaybe: if not inMaybe:
raise Exception("ERROR: not reaching a assignment statement") raise Exception("ERROR: not reaching a assignment statement")
self.outMaybe = inMaybe self.outMaybe = inMaybe
################################################################################## ##################################################################################
# cast: castExpr LPAREN castType RPAREN unaryNotPlusMinus # cast: castExpr LPAREN castType RPAREN unaryNotPlusMinus
class CastNode(ASTNode): class CastNode(ASTNode):
# always list all fields in the init method to show the class structure # always list all fields in the init method to show the class structure
def __init__(self, parseTree, typeName): def __init__(self, parseTree, typeName):
self.parseTree = parseTree self.parseTree = parseTree
self.left = parseTree.children[1] # cast: (left)right self.left = parseTree.children[1] # cast: (left)right
self.right = makeNodeFromExpr(parseTree.children[3], typeName) # expr self.right = makeNodeFromExpr(parseTree.children[3], typeName) # expr
self.env = None self.env = None
self.children = [] self.children = []
self.typeName = typeName # the type (class/interface) this node belongs under self.typeName = typeName # the type (class/interface) this node belongs under
if self.left.name == 'expr': if self.left.name == 'expr':
self.left = makeNodeFromExpr(self.left, typeName) self.left = makeNodeFromExpr(self.left, typeName)
else: #primitiveType or ArrayType else: #primitiveType or ArrayType
self.left = TypeNode(self.left, typeName) self.left = TypeNode(self.left, typeName)
# since a type might be mis-parsed as a name # since a type might be mis-parsed as a name
if self.left.__class__.__name__ == 'NameNode': if self.left.__class__.__name__ == 'NameNode':
self.left = TypeNode(self.parseTree.children[1], typeName) self.left = TypeNode(self.parseTree.children[1], typeName)
self.children.append(self.left) self.children.append(self.left)
self.children.append(self.right) self.children.append(self.right)
def disambigName(self): def disambigName(self):
if self.left.__class__.__name__ != 'TypeNode': if self.left.__class__.__name__ != 'TypeNode':
self.left.disambigName() self.left.disambigName()
self.right.disambigName() self.right.disambigName()
# helperDisambigName(self.left) # helperDisambigName(self.left)
# helperDisambigName(self.right) # helperDisambigName(self.right)
def checkType(self): def checkType(self):
self.left.checkType() self.left.checkType()
from pprint import pprint from pprint import pprint
self.right.disambigName() self.right.disambigName()
self.right.checkType() self.right.checkType()
if (self.left.myType.isNum() and self.right.myType.isNum()) \ if (self.left.myType.isNum() and self.right.myType.isNum()) \
or self.left.myType.assignable(self.right.myType) \ or self.left.myType.assignable(self.right.myType) \
or self.right.myType.assignable(self.left.myType): or self.right.myType.assignable(self.left.myType):
self.myType = self.left.myType self.myType = self.left.myType
return return
raise Exception("ERROR: Cannot cast type {} to type {}.".format(self.right.myType.name, self.left.myType.name)) raise Exception("ERROR: Cannot cast type {} to type {}.".format(self.right.myType.name, self.left.myType.name))
################################################################################### ###################################################################################
# unqualCreate NEW name LPAREN args RPAREN # unqualCreate NEW name LPAREN args RPAREN
class ClassCreateNode(ASTNode): class ClassCreateNode(ASTNode):
# always list all fields in the init method to show the class structure # always list all fields in the init method to show the class structure
def __init__(self, parseTree, typeName): def __init__(self, parseTree, typeName):
self.parseTree = parseTree self.parseTree = parseTree
self.className = TypeNode(parseTree.children[1], typeName) self.className = TypeNode(parseTree.children[1], typeName)
self.args = ArgsNode(parseTree.children[3], typeName) self.args = ArgsNode(parseTree.children[3], typeName)
self.env = None self.env = None
self.children = [self.className, self.args] self.children = [self.className, self.args]
self.typeName = typeName self.typeName = typeName
self.cons = None # the constructor used to create the class self.cons = None # the constructor used to create the class
def checkType(self): def checkType(self):
# return # TO REMOVE after name node type checking is done # return # TO REMOVE after name node type checking is done
self.args.checkType() self.args.checkType()
classDef = self.className.myType.typePointer classDef = self.className.myType.typePointer
# check class is not abstract # check class is not abstract
if 'abstract' in classDef.mods: if 'abstract' in classDef.mods:
raise Exception('ERROR: Cannot create an instance of abstract class {}.'.format(self.className.myType.name)) raise Exception('ERROR: Cannot create an instance of abstract class {}.'.format(self.className.myType.name))
elif classDef.__class__.__name__ != 'ClassNode': elif classDef.__class__.__name__ != 'ClassNode':
raise Exception('ERROR: Cannot create an instance of {}, it is not a class.'.format(self.className.myType.name)) raise Exception('ERROR: Cannot create an instance of {}, it is not a class.'.format(self.className.myType.name))
# check 0 arguement constructor of superclass exists # check 0 arguement constructor of superclass exists
su = classDef.superClass su = classDef.superClass
while su != '': # if it doesn't have an explict super class, its super class is java.lang.object, which is safe while su != '': # if it doesn't have an explict super class, its super class is java.lang.object, which is safe
found = False found = False
for c in su.constructors: for c in su.constructors:
if c.params == []: if c.params == []:
found = True found = True
break break
if not found: if not found:
raise Exception("ERROR: Class {} doesn't have a zero-arguement constructor.".format(su.name)) raise Exception("ERROR: Class {} doesn't have a zero-arguement constructor.".format(su.name))
su = su.superClass su = su.superClass
# get constructor using arg Types # get constructor using arg Types
m = getMethod(classDef.constructors, "", self.args) m = getMethod(classDef.constructors, "", self.args)
if m: if m:
self.cons = m self.cons = m
self.myType = self.className.myType self.myType = self.className.myType
else: else:
raise Exception("ERROR: Class {} doesn't have a constructor with given argument types.".format(classDef.name)) raise Exception("ERROR: Class {} doesn't have a constructor with given argument types.".format(classDef.name))
# check to make sure we are allowed to call this (protected?) # check to make sure we are allowed to call this (protected?)
# if self.cons is protected, check that: # if self.cons is protected, check that:
# - current class is in the same package # - current class is in the same package
if 'protected' in self.cons.mods: if 'protected' in self.cons.mods:
curClass = self.env.getNode(self.typeName, 'type') curClass = self.env.getNode(self.typeName, 'type')
if curClass.packageName != classDef.packageName: if curClass.packageName != classDef.packageName:
raise Exception("ERROR: In class {0}, using a protected constructor, but class {1} is not in class {0}'s package ({2}).".format(curClass.name, classDef.name, curClass.packageName)) raise Exception("ERROR: In class {0}, using a protected constructor, but class {1} is not in class {0}'s package ({2}).".format(curClass.name, classDef.name, curClass.packageName))
################################################################################# #################################################################################
# condOrExpr # condOrExpr
class ExprNode(ASTNode): class ExprNode(ASTNode):
# always list all fields in the init method to show the class structure # always list all fields in the init method to show the class structure
def __init__(self, parseTree, typeName): def __init__(self, parseTree, typeName):
self.parseTree = parseTree self.parseTree = parseTree
self.left = None self.left = None
self.op = '' self.op = ''
self.right = None # another expr self.right = None # another expr
self.env = None self.env = None
self.children = [] self.children = []
self.typeName = typeName # the type (class/interface) this node belongs under self.typeName = typeName # the type (class/interface) this node belongs under
if parseTree.name == 'unaryNotPlusMinus' or parseTree.name == 'unaryExpr': if parseTree.name == 'unaryNotPlusMinus' or parseTree.name == 'unaryExpr':
self.op = parseTree.children[0].lex self.op = parseTree.children[0].lex
self.right = makeNodeFromExpr(parseTree.children[1], typeName) self.right = makeNodeFromExpr(parseTree.children[1], typeName)
else: else:
self.left = makeNodeFromExpr(parseTree.children[0], typeName) self.left = makeNodeFromExpr(parseTree.children[0], typeName)
self.op = parseTree.children[1].lex self.op = parseTree.children[1].lex
self.right = makeNodeFromExpr(parseTree.children[2], typeName) self.right = makeNodeFromExpr(parseTree.children[2], typeName)
self.children.append(self.left) self.children.append(self.left)
self.children.append(self.right) self.children.append(self.right)
def disambigName(self): def disambigName(self):
if self.left: if self.left:
self.left.disambigName() self.left.disambigName()
self.right.disambigName() self.right.disambigName()
# helperDisambigName(self.left) # helperDisambigName(self.left)
# helperDisambigName(self.right) # helperDisambigName(self.right)
# use wrong name to stop method from being called until we finish other implemetation # use wrong name to stop method from being called until we finish other implemetation
# def checkType(self): # def checkType(self):
def checkType(self): def checkType(self):
# steps of type checking: # steps of type checking:
# check children's types (children's myType field will be populated with a typeStruct) # check children's types (children's myType field will be populated with a typeStruct)
# check using the rule for current node # check using the rule for current node
# make a TypeStruct node and populate myType field for self # make a TypeStruct node and populate myType field for self
super().checkType() # check children's type first to populate their myType field super().checkType() # check children's type first to populate their myType field
# Unary operations: # Unary operations:
if not self.left: if not self.left:
if self.op == '-' and self.right.myType.isNum(): if self.op == '-' and self.right.myType.isNum():
self.myType = TypeStruct("int", None) self.myType = TypeStruct("int", None)
return return
elif self.op == '!' and self.right.myType.name == 'boolean': elif self.op == '!' and self.right.myType.name == 'boolean':
self.myType = self.myType = TypeStruct("boolean", None) self.myType = self.myType = TypeStruct("boolean", None)
return return
# Numeric types # Numeric types
if self.left.myType.isNum() and self.right.myType.isNum(): if self.left.myType.isNum() and self.right.myType.isNum():
# Comparisons: # Comparisons:
if self.op in ['==', '!=', '<=', '>=', '>', '<']: if self.op in ['==', '!=', '<=', '>=', '>', '<']:
self.myType = TypeStruct("boolean", None) self.myType = TypeStruct("boolean", None)
return return
# numeric operations: # numeric operations:
elif self.op in ['+', '-', '*', '/', '%']: elif self.op in ['+', '-', '*', '/', '%']:
self.myType = TypeStruct("int", None) self.myType = TypeStruct("int", None)
return return
# Boolean operations: # Boolean operations:
if self.left.myType.name == 'boolean' and self.right.myType.name == 'boolean': if self.left.myType.name == 'boolean' and self.right.myType.name == 'boolean':
if self.op in ['&&', '&', '|', '||', '!=', '==']: if self.op in ['&&', '&', '|', '||', '!=', '==']:
self.myType = TypeStruct("boolean", None) self.myType = TypeStruct("boolean", None)
return return
if self.left.myType.assignable(self.right.myType) or self.right.myType.assignable(self.left.myType): if self.left.myType.assignable(self.right.myType) or self.right.myType.assignable(self.left.myType):
if self.op == '==' or self.op == '!=' or self.op == 'instanceof': if self.op == '==' or self.op == '!=' or self.op == 'instanceof':
self.myType = TypeStruct("boolean", None) self.myType = TypeStruct("boolean", None)
return return
# String concat: # String concat:
if ((self.left.myType.name =='java.lang.String' and self.right.myType.name not in ['void']) \ if ((self.left.myType.name =='java.lang.String' and self.right.myType.name not in ['void']) \
or (self.right.myType.name =='java.lang.String' and self.left.myType.name not in ['void'])) and self.op == '+': or (self.right.myType.name =='java.lang.String' and self.left.myType.name not in ['void'])) and self.op == '+':
self.myType = TypeStruct('java.lang.String', self.env.getNode('java.lang.String', 'type')) self.myType = TypeStruct('java.lang.String', self.env.getNode('java.lang.String', 'type'))
self.myType.link(self.env) self.myType.link(self.env)
return return
raise Exception("ERROR: Incompatible types. Left of {} type can't be used with right of {} type on operation {}".format(self.left.myType.name, self.right.myType.name, self.op)) raise Exception("ERROR: Incompatible types. Left of {} type can't be used with right of {} type on operation {}".format(self.left.myType.name, self.right.myType.name, self.op))
# returns True, False, Int or None (for non-constant expr) # returns True, False, Int or None (for non-constant expr)
# children of exprNode is either exprNode or literalNode # children of exprNode is either exprNode or literalNode
def getConstant(self): def getConstant(self):
if not hasattr(self.right, "getConstant"): if not hasattr(self.right, "getConstant"):
return None return None
cRight = self.right.getConstant() cRight = self.right.getConstant()
if cRight == None: if cRight == None:
return None return None
# Unary Ops # Unary Ops
if not self.left: if not self.left:
if self.op == '-': if self.op == '-':
return -cRight return -cRight
return not cRight # op = '!' return not cRight # op = '!'
else: else:
if not hasattr(self.left, "getConstant"): if not hasattr(self.left, "getConstant"):
return None return None
cLeft = self.left.getConstant() cLeft = self.left.getConstant()
if cLeft == None: if cLeft == None:
return None return None
# arithmetic # arithmetic
if self.op == '+': if self.op == '+':
return cLeft + cRight return cLeft + cRight
elif self.op == '-': elif self.op == '-':
return cLeft - cRight return cLeft - cRight
elif self.op == '*': elif self.op == '*':
return cLeft * cRight return cLeft * cRight
elif self.op == '/': elif self.op == '/':
return cLeft // cRight return cLeft // cRight
elif self.op == '%': elif self.op == '%':
return cLeft % cRight return cLeft % cRight
# Comparison # Comparison
elif self.op == '==': elif self.op == '==':
return cLeft == cRight return cLeft == cRight
elif self.op == '!=': elif self.op == '!=':
return cLeft != cRight return cLeft != cRight
elif self.op == '>': elif self.op == '>':
return cLeft > cRight return cLeft > cRight
elif self.op == '<': elif self.op == '<':
return cLeft < cRight return cLeft < cRight
elif self.op == '>=': elif self.op == '>=':
return cLeft >= cRight return cLeft >= cRight
elif self.op == '<=': elif self.op == '<=':
return cLeft <= cRight return cLeft <= cRight
# boolean Ops # boolean Ops
elif self.op == '&&' or self.op == '&': elif self.op == '&&' or self.op == '&':
return cLeft and cRight return cLeft and cRight
elif self.op == '||' or self.op == '|': elif self.op == '||' or self.op == '|':
return cLeft or cRight return cLeft or cRight
else: else:
return None return None
################################################################################### ###################################################################################
# fieldAccess primary PERIOD ID # fieldAccess primary PERIOD ID
class FieldAccessNode(ASTNode): class FieldAccessNode(ASTNode):
# always list all fields in the init method to show the class structure # always list all fields in the init method to show the class structure
def __init__(self, parseTree, typeName): def __init__(self, parseTree, typeName):
self.parseTree = parseTree self.parseTree = parseTree
self.primary = '' self.primary = ''
self.ID = '' # method/fieldName self.ID = '' # method/fieldName
self.env = None self.env = None
self.children = [] self.children = []
self.typeName = typeName # the type (class/interface) this node belongs under self.typeName = typeName # the type (class/interface) this node belongs under
# input: fieldAccess primary PERIOD ID # input: fieldAccess primary PERIOD ID
self.primary = makeNodeFromAllPrimary(parseTree.children[0], typeName) self.primary = makeNodeFromAllPrimary(parseTree.children[0], typeName)
self.ID = NameNode(parseTree.children[2], False, typeName) self.ID = NameNode(parseTree.children[2], False, typeName)
self.children.append(self.primary) self.children.append(self.primary)
self.children.append(self.ID) self.children.append(self.ID)
def disambigName(self): def disambigName(self):
if not self.primary: # this implies that the ID has nothing that comes before it if not self.primary: # this implies that the ID has nothing that comes before it
# helperDisambigName(self.ID) # helperDisambigName(self.ID)
self.ID.disambigName() self.ID.disambigName()
# self.right.disambigName() # self.right.disambigName()
else: else:
self.primary.disambigName() self.primary.disambigName()
def checkType(self): def checkType(self):
self.primary.checkType() self.primary.checkType()
if self.primary.myType.isArray or self.primary.myType.isPrimitive: if self.primary.myType.isArray or self.primary.myType.isPrimitive:
self.ID.prefixLink = self.primary self.ID.prefixLink = self.primary
else: else:
self.ID.prefixLink = self.primary.myType.typePointer self.ID.prefixLink = self.primary.myType.typePointer
self.ID.checkType() self.ID.checkType()
self.myType = self.ID.myType self.myType = self.ID.myType
# check protected # check protected
try: try:
if "protected" in self.ID.prefixLink.mods: if "protected" in self.ID.prefixLink.mods:
checkProtected(self.ID.prefixLink, self) checkProtected(self.ID.prefixLink, self)
except: # where there are no mods except: # where there are no mods
return return
################################################################################### ###################################################################################
# methodInvoc # methodInvoc
class MethodInvNode(ASTNode): class MethodInvNode(ASTNode):
# always list all fields in the init method to show the class structure # always list all fields in the init method to show the class structure
def __init__(self, parseTree, typeName): def __init__(self, parseTree, typeName):
self.parseTree = parseTree self.parseTree = parseTree
self.primary = None # can be empty self.primary = None # can be empty
self.ID = '' # can be either ID or compID self.ID = '' # can be either ID or compID
self.args = None self.args = None
self.env = None self.env = None
self.children = [] self.children = []
self.method = None self.method = None
self.typeName = typeName # the type (class/interface) this node belongs under self.typeName = typeName # the type (class/interface) this node belongs under
# input parse tree is either: methodInvoc primary PERIOD ID LPAREN args RPAREN # input parse tree is either: methodInvoc primary PERIOD ID LPAREN args RPAREN
# methodInvoc name LPAREN args RPAREN # methodInvoc name LPAREN args RPAREN
self.ID = NameNode(parseTree.children[-4], True, typeName) self.ID = NameNode(parseTree.children[-4], True, typeName)
self.args = ArgsNode(parseTree.children[-2], typeName) self.args = ArgsNode(parseTree.children[-2], typeName)
if parseTree.children[0].name == 'primary': if parseTree.children[0].name == 'primary':
self.primary = makeNodeFromAllPrimary(parseTree.children[0], typeName) self.primary = makeNodeFromAllPrimary(parseTree.children[0], typeName)
self.children.append(self.primary) self.children.append(self.primary)
self.children.append(self.args) self.children.append(self.args)
self.children.append(self.ID) self.children.append(self.ID)
def disambigName(self): def disambigName(self):
if not self.primary: # this implies our ID doesn't have anything that comes before it if not self.primary: # this implies our ID doesn't have anything that comes before it
if isinstance(self.ID, NameNode) and len(self.ID.IDs) > 1: if isinstance(self.ID, NameNode) and len(self.ID.IDs) > 1:
self.ID.disambigName() self.ID.disambigName()
# helperDisambigName(self.ID) # helperDisambigName(self.ID)
if self.args: if self.args:
self.args.disambigName() self.args.disambigName()
def checkType(self): def checkType(self):
# steps of type checking: # steps of type checking:
# check param's types # check param's types
# check using the rule for current node # check using the rule for current node
# make a TypeStruct node for self (return type of method) # make a TypeStruct node for self (return type of method)
# populate params myTypes # populate params myTypes
for param in self.args.exprs: for param in self.args.exprs:
param.checkType() param.checkType()
# now that we have the method name, param types, we need to: # now that we have the method name, param types, we need to:
# - check if method exists under the class its under # - check if method exists under the class its under
m = None m = None
if not self.primary: if not self.primary:
self.ID.checkType() self.ID.checkType()
m = getMethod(self.ID.prefixLink.values(), self.ID.methodName, self.args) m = getMethod(self.ID.prefixLink.values(), self.ID.methodName, self.args)
else: else:
self.primary.checkType() self.primary.checkType()
methods = [] methods = []
methods.extend(self.primary.myType.typePointer.methods) methods.extend(self.primary.myType.typePointer.methods)
methods.extend([meth for meth in self.primary.myType.typePointer.inherits if isinstance(meth, MemberNodes.MethodNode)]) # need to check inherited methods as well methods.extend([meth for meth in self.primary.myType.typePointer.inherits if isinstance(meth, MemberNodes.MethodNode)]) # need to check inherited methods as well
m = getMethod(methods, self.ID.name, self.args) m = getMethod(methods, self.ID.name, self.args)
if m: if m:
# check static # I don't see any need for this check, this check causes more harm than good
if self.ID.shouldBeStatic and (not 'static' in m.mods): # because you can call System.out.println, where 'System' is a class with static field 'out',
raise Exception("ERROR: Static access of non-static method {}.".format(m.name)) # which is of type 'PrintStream' which has non-static method 'println', thus going into this if statement
if (not self.ID.shouldBeStatic) and 'static' in m.mods: # if self.ID.shouldBeStatic and (not 'static' in m.mods):
raise Exception("ERROR: Non-static access of static method {}.".format(m.name)) # raise Exception("ERROR: Static access of non-static method {}.".format(m.name))
# check protected # check static
if "protected" in m.mods: if (not self.ID.shouldBeStatic) and 'static' in m.mods:
checkProtected(m, self) raise Exception("ERROR: Non-static access of static method {}.".format(m.name))
self.method = m # check protected
self.myType = m.methodType.myType if "protected" in m.mods:
return checkProtected(m, self)
else:
self.method = m
raise Exception("ERROR: Class {} doesn't have a method {} with given argument types.".format(self.typeName, self.ID.name)) self.myType = m.methodType.myType
return
def reachCheck(self, inMaybe): else:
if not inMaybe:
raise Exception("ERROR: not reaching a variable declaration statement for var {}".format(self.name)) raise Exception("ERROR: Class {} doesn't have a method {} with given argument types.".format(self.typeName, self.ID.name))
self.outMaybe = inMaybe
def reachCheck(self, inMaybe):
################# Helper ####################### if not inMaybe:
raise Exception("ERROR: not reaching a variable declaration statement for var {}".format(self.name))
def getMethod(methods, methodName, args): self.outMaybe = inMaybe
# methodName = "" if it's constructor
for c in methods: ################# Helper #######################
if (methodName == "" or c.name == methodName) and len(args.exprs) == len(c.params):
found = True def getMethod(methods, methodName, args):
for i, param in enumerate(args.exprs): # methodName = "" if it's constructor
if c.params[i].paramType.myType != param.myType: for c in methods:
found = False if (methodName == "" or c.name == methodName) and len(args.exprs) == len(c.params):
if found: found = True
return c for i, param in enumerate(args.exprs):
return None if c.params[i].paramType.myType != param.myType:
found = False
if found:
return c
return None
This diff is collapsed.
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