class TypeCollector(object): def __init__(self, errors=[]): self.context = None self.errors = errors @visitor.on("node") def visit(self, node): pass @visitor.when(ProgramNode) def visit(self, node): self.context = Context() self.context.types["Object"] = ObjectType() self.context.types["Int"] = IntType() self.context.types["String"] = StringType() self.context.types["Bool"] = BoolType() self.context.types["AUTO_TYPE"] = AutoType() self.context.types["SELF_TYPE"] = SelfType() self.context.types["IO"] = IOType() object_type = self.context.get_type("Object") for typex in self.context.types.values(): if typex == object_type: continue typex.set_parent(object_type) for declaration in node.declarations: self.visit(declaration) copy_visitor = CopyVisitor() newAst = copy_visitor.visit(node) newAst.context = self.context # Reset state self.context = None self.errors = None return newAst @visitor.when(ClassDeclarationNode) def visit(self, node): try: self.context.create_type(node.id.lex) except SError as error: # class alerady defined node_row, node_col = node.id.location self.errors.append(SemanticError(node_row, node_col, error.text))
class TypeCollector(object): def __init__(self, errors=[]): self.context = None self.errors = errors self.parent = {} @visitor.on('node') def visit(self, node): pass @visitor.when(ProgramNode) def visit(self, node): self.context = Context() self.define_built_in_types() # Adding built-in types to context for typex in built_in_types: self.context.types[typex.name] = typex for declaration in node.declarations: self.visit(declaration) self.check_parents() self.check_cyclic_inheritance() # Order class declarations according to their depth in the inheritance tree node.declarations = self.order_types(node) @visitor.when(ClassDeclarationNode) def visit(self, node): # flag will be True if the class is succesfully added to the context flag = False try: if node.id == 'AUTO_TYPE': raise SemanticError('Name of class can\'t be autotype') self.context.create_type(node.id) flag = True self.parent[node.id] = node.parent except SemanticError as ex: self.errors.append(ex.text) # changing class id so it can be added to context while not flag: node.id = f'1{node.id}' try: self.context.create_type(node.id) flag = True self.parent[node.id] = node.parent except SemanticError: pass def define_built_in_types(self): objectx = ObjectType() iox = IOType() intx = IntType() stringx = StringType() boolx = BoolType() self_type = SelfType() autotype = AutoType() # Object Methods objectx.define_method('abort', [], [], objectx, []) objectx.define_method('type_name', [], [], stringx, []) objectx.define_method('copy', [], [], self_type, []) # IO Methods iox.define_method('out_string', ['x'], [stringx], self_type, [None]) iox.define_method('out_int', ['x'], [intx], self_type, [None]) iox.define_method('in_string', [], [], stringx, []) iox.define_method('in_int', [], [], intx, []) # String Methods stringx.define_method('length', [], [], intx, []) stringx.define_method('concat', ['s'], [stringx], stringx, [None]) stringx.define_method('substr', ['i', 'l'], [intx, intx], stringx, [None]) # Setting Object as parent iox.set_parent(objectx) stringx.set_parent(objectx) intx.set_parent(objectx) boolx.set_parent(objectx) built_in_types.extend( [objectx, iox, stringx, intx, boolx, self_type, autotype]) def check_parents(self): for item in self.parent.keys(): item_type = self.context.get_type(item) if self.parent[item] is None: # setting Object as parent item_type.set_parent(built_in_types[0]) else: try: typex = self.context.get_type(self.parent[item]) if not typex.can_be_inherited(): self.errors.append( f'Class {item} can not inherit from {typex.name}') typex = built_in_types[0] item_type.set_parent(typex) except SemanticError as ex: self.errors.append(ex.text) item_type.set_parent(built_in_types[0]) def check_cyclic_inheritance(self): flag = [] def find(item): for i, typex in enumerate(flag): if typex.name == item.name: return i return len(flag) def check_path(idx, item): while True: flag.append(item) parent = item.parent if parent is None: break pos = find(parent) if pos < len(flag): if pos >= idx: self.errors.append( f'Class {item.name} can not inherit from {parent.name}' ) item.parent = built_in_types[0] break item = parent for item in self.context.types.values(): idx = find(item) if idx == len(flag): check_path(idx, item) def order_types(self, node): sorted_declarations = [] flag = [False] * len(node.declarations) change = True while change: change = False current = [] for i, dec in enumerate(node.declarations): if not flag[i]: typex = self.context.get_type(dec.id) if typex.parent.name in [ item.id for item in sorted_declarations ] or any(typex.parent.name == bit.name for bit in built_in_types): current.append(dec) flag[i] = True change = True sorted_declarations.extend(current) return sorted_declarations
class TypeCollector(object): def __init__(self): self.context = None self.errors = [] self.class_tree = { "Object": ["IO", "String", "Int", "Bool"], "IO": [], "String": [], "Int": [], "Bool": [] } self.types_nodes = dict() @visitor.on('node') def visit(self, node): pass @visitor.when(ProgramNode) def visit(self, node): self.context = Context() self.init_default_classes() for class_def in node.declarations: self.visit(class_def) ordered = [] self.check_type_tree(ordered, self.class_tree) node.declarations = ordered self.context.type_tree = self.class_tree self.context.type_tree["<error>"] = tuple() @visitor.when(ClassDeclarationNode) def visit(self, node): try: self.context.create_type(node.id) if node.id[0] != node.id[0].upper(): self.errors.append( f"Class {node.id} must start with a capital word.") self.types_nodes[node.id] = node if not node.id in self.class_tree: self.class_tree[node.id] = [] if node.parent: if node.parent in {"String", "Int", "Bool"}: raise SemanticError( f"Class {node.id} cannot inherit from {node.parent} beacuse is forbidden." ) try: self.class_tree[node.parent].append(node.id) except KeyError: self.class_tree[node.parent] = [node.id] else: node.parent = "Object" self.class_tree["Object"].append(node.id) except SemanticError as err: self.errors.append(err.text) def init_default_classes(self): self.context.create_type('Object').index = 0 self.context.create_type('String') self.context.create_type('Int') self.context.create_type('IO') self.context.create_type('Bool') def check_type_tree(self, ordered, graph): visited = set(["Object"]) self.get_type_hierarchy("Object", graph, visited, ordered, 1) for node in graph: if not node in visited: visited.add(node) self.errors.append( "Circular Heritage: " + str(get_circular_heritage(node, graph, [node], visited))) def get_type_hierarchy(self, root, graph, visited: set, ordered: list, index): if not root in graph: return None for node in graph[root]: if not node in visited: visited.add(node) if node not in {"Int", "String", "IO", "Bool", "Object"}: ordered.append(self.types_nodes[node]) self.context.get_type(node).index = index self.get_type_hierarchy(node, graph, visited, ordered, index + 1)