raiseException("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))
defreachCheck(self,inMaybe):
ifnotinMaybe:
raiseException("ERROR: not reaching a assignment statement")
self.cons=None# the constructor used to create the class
defcheckType(self):
# return # TO REMOVE after name node type checking is done
self.args.checkType()
classDef=self.className.myType.typePointer
# check class is not abstract
if'abstract'inclassDef.mods:
raiseException('ERROR: Cannot create an instance of abstract class {}.'.format(self.className.myType.name))
elifclassDef.__class__.__name__!='ClassNode':
raiseException('ERROR: Cannot create an instance of {}, it is not a class.'.format(self.className.myType.name))
# check 0 arguement constructor of superclass exists
su=classDef.superClass
whilesu!='':# if it doesn't have an explict super class, its super class is java.lang.object, which is safe
found=False
forcinsu.constructors:
ifc.params==[]:
found=True
break
ifnotfound:
raiseException("ERROR: Class {} doesn't have a zero-arguement constructor.".format(su.name))
su=su.superClass
# get constructor using arg Types
m=getMethod(classDef.constructors,"",self.args)
ifm:
self.cons=m
self.myType=self.className.myType
else:
raiseException("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?)
# if self.cons is protected, check that:
# - current class is in the same package
if'protected'inself.cons.mods:
curClass=self.env.getNode(self.typeName,'type')
ifcurClass.packageName!=classDef.packageName:
raiseException("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))
raiseException("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)
# children of exprNode is either exprNode or literalNode
methods.extend([methformethinself.primary.myType.typePointer.inheritsifisinstance(meth,MemberNodes.MethodNode)])# need to check inherited methods as well
m=getMethod(methods,self.ID.name,self.args)
ifm:
# check static
ifself.ID.shouldBeStaticand(not'static'inm.mods):
raiseException("ERROR: Static access of non-static method {}.".format(m.name))
if (notself.ID.shouldBeStatic)and'static'inm.mods:
raiseException("ERROR: Non-static access of static method {}.".format(m.name))
# check protected
if"protected"inm.mods:
checkProtected(m,self)
self.method=m
self.myType=m.methodType.myType
return
else:
raiseException("ERROR: Class {} doesn't have a method {} with given argument types.".format(self.typeName,self.ID.name))
defreachCheck(self,inMaybe):
ifnotinMaybe:
raiseException("ERROR: not reaching a variable declaration statement for var {}".format(self.name))
self.outMaybe=inMaybe
################# Helper #######################
defgetMethod(methods,methodName,args):
# methodName = "" if it's constructor
forcinmethods:
if (methodName==""orc.name==methodName)andlen(args.exprs)==len(c.params):
found=True
fori,paraminenumerate(args.exprs):
ifc.params[i].paramType.myType!=param.myType:
found=False
iffound:
returnc
returnNone
fromASTimportASTNode,getParseTreeNodes
fromEnvironmentimportEnv
fromUnitNodesimportLiteralNode
importMemberNodes
fromTheTypeNodeimportTypeNode,TypeStruct
fromNameNodeimportNameNode,checkProtected
# file containing smaller (lower level nodes) in the AST
# nodes in this file:
# ArgsNode
# ArrayAccessNode
# ArrayCreateNode
# AssignNode
# CastNode
# ClassCreateNode
# ExprNode
# FieldAccessNode
# MethodInvNode
# TODO: go over nodes in this file to see if need to overright buildEnv
raiseException("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))
defreachCheck(self,inMaybe):
ifnotinMaybe:
raiseException("ERROR: not reaching a assignment statement")
self.cons=None# the constructor used to create the class
defcheckType(self):
# return # TO REMOVE after name node type checking is done
self.args.checkType()
classDef=self.className.myType.typePointer
# check class is not abstract
if'abstract'inclassDef.mods:
raiseException('ERROR: Cannot create an instance of abstract class {}.'.format(self.className.myType.name))
elifclassDef.__class__.__name__!='ClassNode':
raiseException('ERROR: Cannot create an instance of {}, it is not a class.'.format(self.className.myType.name))
# check 0 arguement constructor of superclass exists
su=classDef.superClass
whilesu!='':# if it doesn't have an explict super class, its super class is java.lang.object, which is safe
found=False
forcinsu.constructors:
ifc.params==[]:
found=True
break
ifnotfound:
raiseException("ERROR: Class {} doesn't have a zero-arguement constructor.".format(su.name))
su=su.superClass
# get constructor using arg Types
m=getMethod(classDef.constructors,"",self.args)
ifm:
self.cons=m
self.myType=self.className.myType
else:
raiseException("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?)
# if self.cons is protected, check that:
# - current class is in the same package
if'protected'inself.cons.mods:
curClass=self.env.getNode(self.typeName,'type')
ifcurClass.packageName!=classDef.packageName:
raiseException("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))
raiseException("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)
# children of exprNode is either exprNode or literalNode
methods.extend([methformethinself.primary.myType.typePointer.inheritsifisinstance(meth,MemberNodes.MethodNode)])# need to check inherited methods as well
m=getMethod(methods,self.ID.name,self.args)
ifm:
# I don't see any need for this check, this check causes more harm than good
# because you can call System.out.println, where 'System' is a class with static field 'out',
# which is of type 'PrintStream' which has non-static method 'println', thus going into this if statement
# if self.ID.shouldBeStatic and (not 'static' in m.mods):
# raise Exception("ERROR: Static access of non-static method {}.".format(m.name))
# check static
if (notself.ID.shouldBeStatic)and'static'inm.mods:
raiseException("ERROR: Non-static access of static method {}.".format(m.name))
# check protected
if"protected"inm.mods:
checkProtected(m,self)
self.method=m
self.myType=m.methodType.myType
return
else:
raiseException("ERROR: Class {} doesn't have a method {} with given argument types.".format(self.typeName,self.ID.name))
defreachCheck(self,inMaybe):
ifnotinMaybe:
raiseException("ERROR: not reaching a variable declaration statement for var {}".format(self.name))
self.outMaybe=inMaybe
################# Helper #######################
defgetMethod(methods,methodName,args):
# methodName = "" if it's constructor
forcinmethods:
if (methodName==""orc.name==methodName)andlen(args.exprs)==len(c.params):
# TODO set the most recent? is this the correct implementation we want?
self.prefixLink=typeNode
self.prefix=currPrefix
self.IDs=self.IDs[index+1:]
returnTrue
returnFalse
# Finds the shortest prefix that either is a local variable, instance field or a static field.
# Raises error if no such prefix is found in the environment
# ASSUMPTION: only the left most nodes in the AST
# (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)
defdisambigName(self):
# Checking if a1 is "this"
ifself.checkThis():
self.pointToThis=True
return
# Checking if a1 is length
ifself.checkLength():
return
# Checking if a1 is a local variable
ifself.checkLocalVar():
return
# Checking if a1 is in contains set
ifself.checkContains():
self.pointToThis=True
return
# Checking if the shortest prefix is a static field
ifself.checkStatic():
self.shouldBeStatic=True
return
raiseException("ERROR at disambiguating namespace: no prefix of name {} is found in environment.".format(self.name))
defcheckType(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
# TODO set the most recent? is this the correct implementation we want?
self.prefixLink=typeNode
self.prefix=currPrefix
self.IDs=self.IDs[index+1:]
returnTrue
returnFalse
# Finds the shortest prefix that either is a local variable, instance field or a static field.
# Raises error if no such prefix is found in the environment
# ASSUMPTION: only the left most nodes in the AST
# (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)
defdisambigName(self):
# Checking if a1 is "this"
ifself.checkThis():
self.pointToThis=True
return
# Checking if a1 is length
ifself.checkLength():
return
# Checking if a1 is a local variable
ifself.checkLocalVar():
return
# Checking if a1 is in contains set
ifself.checkContains():
self.pointToThis=True
return
# Checking if the shortest prefix is a static field
ifself.checkStatic():
self.shouldBeStatic=True
return
raiseException("ERROR at disambiguating namespace: no prefix of name {} is found in environment.".format(self.name))
defcheckType(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