Skip to content
Snippets Groups Projects
TheTypeNode.py 3.15 KiB
from AST import ASTNode, getParseTreeNodes
##################################################################################
# TypeNode: an AST node represents a type
# TypeStruct: a struct holding type information for type checking

# TypeNode represents a parse tree unit that contains a type,
# TypeStruct is not a unit on parseTree, it is just a struct living in different AST nodes to keep track of their type

class TypeNode(ASTNode):
    # always list all fields in the init method to show the class structure
    def __init__(self, parseTree, typeName):
        self.parseTree = parseTree
        self.name = ''
        self.env = None
        self.children = []
        self.myType = "" # empty string or typeStruct

        if parseTree == 'VOID':
            self.myType = TypeStruct('void', None)
        else:
            nameNodes = getParseTreeNodes(['BOOLEAN', 'BYTE', 'CHAR', 'INT', 'SHORT'], parseTree)
            if nameNodes:
                self.myType = TypeStruct(nameNodes[0].lex, None)
            else:
                self.myType = TypeStruct(getParseTreeNodes(['ID', 'COMPID'], parseTree)[0].lex, None)

            nameNodes = getParseTreeNodes(['LSQRBRACK'], parseTree)
            if nameNodes:
                self.myType.isArray = True

    def __eq__(self, other):
        return self.myType == other.myType

    def linkType(self):
        self.myType.link(self.env)


class TypeStruct():
    def __init__(self, name, typePointer):
        self.isArray = False
        self.isPrimitive = False
        self.typePointer = typePointer
        self.name = name
        if name in ['boolean', 'byte', 'char', 'int', 'short', 'void']:
            self.isPrimitive = True

    def link(self, env):
        if not self.isPrimitive:
            self.typePointer = env.getNode(self.name, 'type')
            self.name = self.typePointer.canonName  # Use canonName instead of simple name for comparison

    def __eq__(self, other):
        return self.name == other.name

    def isNum(self):
        return self.name in ['int', 'short', 'char', 'byte']

    # if self is assignable to input typeNode: self := right
    # right is either a TypeNode or a LiteralNode
    def assignable(self, right):
        if self.isArray == right.isArray:
            if self == right \
            or (right.name in ['short', 'char', 'byte'] and self.name == 'int') \
            or (right.name == 'byte' and self.name == 'short') \
            or (not self.isPrimitive and right.name == 'null'):
                return True
            #  check if self is super of right
            elif ((not self.isPrimitive) and (not right.isPrimitive)) \
            and (self.name in getSupers(right.typePointer)):
                return True
            return False

        if right.isArray and self.name in ['java.lang.Object', 'java.lang.Cloneable', 'java.io.Serializable']:
            return True

        return False

# helper: get list of all super class/interface of a ClassInterNode
def getSupers(classType):
    result = ["java.lang.Object"]
    if not classType.super:
        return result
    for s in classType.super:
        result.append(s.canonName)
        result.extend(getSupers(s))
    return result