def visit_for(self, node): for element in node.elements: elem_type = self.visit(node.iterator) if isinstance(elem_type, CollectionSymbol): elem_type = elem_type.item_types var_sym = VarSymbol(element.value, elem_type) var_sym.val_assigned = True self.define(var_sym.name, var_sym) self.visit(node.block)
def visit_funcdecl(self, node): func_name = node.name func_type = self.search_scopes(node.return_type.value) if self.search_scopes(func_name) is not None: error('file={} line={}: Cannot redefine a declared function: {}'. format(self.file_name, node.line_num, func_name)) if func_type and func_type.name == FUNC: func_type.func = FuncSymbol( ANON, self.visit(node.return_type.func_ret_type), node.parameters, node.body, node.parameter_defaults) self.define( func_name, FuncSymbol(func_name, func_type, node.parameters, node.body, node.parameter_defaults)) self.new_scope() if node.varargs: varargs_type = self.search_scopes(LIST) varargs_type.type = node.varargs[1].value varargs = CollectionSymbol( node.varargs[0], varargs_type, self.search_scopes(node.varargs[1].value)) varargs.val_assigned = True self.define(varargs.name, varargs) for k, v in node.parameters.items(): var_type = self.search_scopes(v.value) if var_type is self.search_scopes(FUNC): sym = FuncSymbol(k, v.func_ret_type, v.func_params, None) elif isinstance(var_type, TypeSymbol): var_type.accessed = True if var_type.type is self.search_scopes(FUNC): sym = FuncSymbol(k, var_type.type.return_type, v.func_params, None) else: raise NotImplementedError else: sym = VarSymbol(k, var_type) sym.val_assigned = True self.define(sym.name, sym) return_types = self.visit(node.body) return_types = list(flatten(return_types)) if self.return_flag: self.return_flag = False for ret_type in return_types: infered_type = self.infer_type(ret_type) if infered_type is not func_type and not types_compatible( infered_type, func_type): error( 'file={} line={}: The actual return type does not match the declared return type: {}' .format(self.file_name, node.line_num, func_name)) elif func_type is not None: error( 'file={} line={}: No return value was specified for function: {}' .format(self.file_name, node.line_num, func_name)) func_symbol = FuncSymbol(func_name, func_type, node.parameters, node.body, node.parameter_defaults) self.define(func_name, func_symbol, 1) self.drop_top_scope()
def visit_vardecl(self, node): type_name = node.type.value type_symbol = self.search_scopes(type_name) var_name = node.value.value if type_name in (LIST, TUPLE): var_symbol = CollectionSymbol(var_name, type_symbol, node.type.func_params['0'].value) var_symbol.read_only = type_name == TUPLE else: var_symbol = VarSymbol(var_name, type_symbol) self.define(var_symbol.name, var_symbol)
def visit_anonymousfunc(self, node): func_type = self.search_scopes(node.return_type.value) self.new_scope() for k, v in node.parameters.items(): var_type = self.search_scopes(v.value) if var_type is self.search_scopes(FUNC): sym = FuncSymbol(k, v.func_ret_type, None, None) else: sym = VarSymbol(k, var_type) sym.val_assigned = True self.define(sym.name, sym) func_symbol = FuncSymbol(ANON, func_type, node.parameters, node.body) return_var_type = self.visit(func_symbol.body) return_var_type = list(flatten(return_var_type)) for ret_type in return_var_type: if self.infer_type(ret_type) is not func_type: error('file={} line={}: The actual return type does not match the declared return type'.format(self.file_name, node.line_num)) self.drop_top_scope() return func_symbol
def visit_externfuncdecl(self, node): func_name = node.name func_type = self.search_scopes(node.return_type.value) if self.search_scopes(func_name) is not None: error('file={} line={}: Cannot redefine a declared function: {}'. format(self.file_name, node.line_num, func_name)) if func_type and func_type.name == FUNC: func_type.func = FuncSymbol( ANON, self.visit(node.return_type.func_ret_type), node.parameters, node.body, node.parameter_defaults) self.define(func_name, FuncSymbol(func_name, func_type, node.parameters, None)) self.new_scope() if node.varargs: varargs_type = self.search_scopes(LIST) varargs_type.type = node.varargs[1].value varargs = CollectionSymbol( node.varargs[0], varargs_type, self.search_scopes(node.varargs[1].value)) varargs.val_assigned = True self.define(varargs.name, varargs) for k, v in node.parameters.items(): var_type = self.search_scopes(v.value) if var_type is self.search_scopes(FUNC): sym = FuncSymbol(k, v.func_ret_type, None, None) elif isinstance(var_type, TypeSymbol): var_type.accessed = True if var_type.type is self.search_scopes(FUNC): sym = FuncSymbol(k, var_type.type.return_type, None, None) else: raise NotImplementedError else: sym = VarSymbol(k, var_type) sym.val_assigned = True self.define(sym.name, sym) func_symbol = FuncSymbol(func_name, func_type, node.parameters, None) self.define(func_name, func_symbol, 1) self.drop_top_scope()
def visit_assign(self, node): # TODO clean up this mess of a function collection_type = None field_assignment = None collection_assignment = None if isinstance(node.left, VarDecl): var_name = node.left.value.value value = self.infer_type(node.left.type) value.accessed = True if isinstance(node.right, Collection) or isinstance( node.right, Range): _, collection_type = self.visit(node.right) if value.name in (TUPLE, LIST) and (not isinstance(node.right, Range) and node.right.type != value.name): error( 'file={} line={}: Contradicting {}-{} declaration'.format( self.file_name, node.line_num, value.name, node.right.type)) elif hasattr(node.right, 'name') and isinstance( self.search_scopes(node.right.name), (StructSymbol, EnumSymbol, ClassSymbol)): var_name = node.left.value value = self.search_scopes(node.right.name) value.accessed = True elif isinstance(node.right, Collection) or isinstance( node.right, Range): var_name = node.left.value value, collection_type = self.visit(node.right) elif isinstance(node.left, DotAccess): field_assignment = True var_name = self.visit(node.left) value = self.visit(node.right) elif isinstance(node.right, DotAccess): var_name = node.left.value value = self.search_scopes(node.right.obj) value.accessed = True value = self.infer_type(value) elif isinstance(node.left, CollectionAccess): collection_assignment = True var_name = node.left.collection.value value = self.visit(node.right) else: var_name = node.left.value value = self.visit(node.right) if isinstance(value, VarSymbol): value = value.type lookup_var = self.search_scopes(var_name) if not lookup_var: if collection_type: col_sym = CollectionSymbol(var_name, value, collection_type) col_sym.val_assigned = True self.define(var_name, col_sym) elif field_assignment: if var_name is value: return else: error( 'file={} line={} Type Error: What are you trying to do?!?! (fix this message)' .format(self.file_name, node.line_num)) elif isinstance(value, FuncSymbol): value.name = var_name self.define(var_name, value) elif hasattr(value, 'name') and value.name == FUNC: var = self.visit(node.right) if isinstance(var, FuncSymbol): self.define(var_name, var) elif isinstance(var, BuiltinTypeSymbol): self.define(var_name, var.func) else: val_info = self.search_scopes(node.right.value) func_sym = FuncSymbol(var_name, val_info.type.return_type, val_info.parameters, val_info.body, val_info.parameter_defaults) self.define(var_name, func_sym) else: var_sym = VarSymbol(var_name, value, node.left.read_only) var_sym.val_assigned = True self.define(var_name, var_sym) else: if isinstance(node.left, VarDecl): error( 'file={} line={}: Cannot redefine the type of a declared variable: {}' .format(self.file_name, node.line_num, var_name)) if collection_assignment: col = self.search_scopes(node.left.collection.value) if col.type.name == TUPLE: error( 'file={} line={}: Cannot change the elements of a tuple: {}' .format(self.file_name, node.line_num, var_name)) elif lookup_var.item_types == value: return if lookup_var.read_only: error( 'file={} line={}: Cannot change the value of a variable declared constant: {}' .format(self.file_name, node.line_num, var_name)) lookup_var.val_assigned = True if lookup_var.type in (self.search_scopes(DOUBLE), self.search_scopes(FLOAT)): if value in (self.search_scopes(INT), self.search_scopes(DOUBLE), self.search_scopes(FLOAT)): return if lookup_var.type is value: return if hasattr(value, 'type') and lookup_var.type is value.type: return if isinstance(value, TypeSymbol): value.accessed = True if value.type is self.search_scopes(FUNC): if value.type.return_type == lookup_var.type: return if hasattr(value, 'value'): if value.value == lookup_var.type.name: return error( 'file={} line={} Type Error: Not good things happening (fix this message)' .format(self.file_name, node.line_num))