def setup_env_class(builder: IRBuilder) -> ClassIR: """Generate a class representing a function environment. Note that the variables in the function environment are not actually populated here. This is because when the environment class is generated, the function environment has not yet been visited. This behavior is allowed so that when the compiler visits nested functions, it can use the returned ClassIR instance to figure out free variables it needs to access. The remaining attributes of the environment class are populated when the environment registers are loaded. Return a ClassIR representing an environment for a function containing a nested function. """ env_class = ClassIR('{}_env'.format(builder.fn_info.namespaced_name()), builder.module_name, is_generated=True) env_class.attributes[SELF_NAME] = RInstance(env_class) if builder.fn_info.is_nested: # If the function is nested, its environment class must contain an environment # attribute pointing to its encapsulating functions' environment class. env_class.attributes[ENV_ATTR_NAME] = RInstance( builder.fn_infos[-2].env_class) env_class.mro = [env_class] builder.fn_info.env_class = env_class builder.classes.append(env_class) return env_class
def deserialize_modules(data: Dict[str, JsonDict], ctx: DeserMaps) -> Dict[str, ModuleIR]: """Deserialize a collection of modules. The modules can contain dependencies on each other. Arguments: data: A dict containing the modules to deserialize. ctx: The deserialization maps to use and to populate. They are populated with information from the deserialized modules and as a precondition must have been populated by deserializing any dependencies of the modules being deserialized (outside of dependencies between the modules themselves). Returns a map containing the deserialized modules. """ for mod in data.values(): # First create ClassIRs for every class so that we can construct types and whatnot for cls in mod['classes']: ir = ClassIR(cls['name'], cls['module_name']) assert ir.fullname not in ctx.classes, "Class %s already in map" % ir.fullname ctx.classes[ir.fullname] = ir for mod in data.values(): # Then deserialize all of the functions so that methods are available # to the class deserialization. for method in mod['functions']: func = FuncIR.deserialize(method, ctx) assert func.decl.fullname not in ctx.functions, ( "Method %s already in map" % func.decl.fullname) ctx.functions[func.decl.fullname] = func return {k: ModuleIR.deserialize(v, ctx) for k, v in data.items()}
def setUp(self) -> None: self.env = Environment() self.n = self.env.add_local(Var('n'), int_rprimitive) self.m = self.env.add_local(Var('m'), int_rprimitive) self.k = self.env.add_local(Var('k'), int_rprimitive) self.l = self.env.add_local(Var('l'), list_rprimitive) # noqa self.ll = self.env.add_local(Var('ll'), list_rprimitive) self.o = self.env.add_local(Var('o'), object_rprimitive) self.o2 = self.env.add_local(Var('o2'), object_rprimitive) self.d = self.env.add_local(Var('d'), dict_rprimitive) self.b = self.env.add_local(Var('b'), bool_rprimitive) self.s1 = self.env.add_local(Var('s1'), short_int_rprimitive) self.s2 = self.env.add_local(Var('s2'), short_int_rprimitive) self.i32 = self.env.add_local(Var('i32'), int32_rprimitive) self.i32_1 = self.env.add_local(Var('i32_1'), int32_rprimitive) self.i64 = self.env.add_local(Var('i64'), int64_rprimitive) self.i64_1 = self.env.add_local(Var('i64_1'), int64_rprimitive) self.ptr = self.env.add_local(Var('ptr'), pointer_rprimitive) self.t = self.env.add_local(Var('t'), RTuple([int_rprimitive, bool_rprimitive])) self.tt = self.env.add_local( Var('tt'), RTuple( [RTuple([int_rprimitive, bool_rprimitive]), bool_rprimitive])) ir = ClassIR('A', 'mod') ir.attributes = OrderedDict([('x', bool_rprimitive), ('y', int_rprimitive)]) compute_vtable(ir) ir.mro = [ir] self.r = self.env.add_local(Var('r'), RInstance(ir)) self.context = EmitterContext(NameGenerator([['mod']]))
def setUp(self) -> None: self.env = Environment() self.n = self.env.add_local(Var('n'), int_rprimitive) self.m = self.env.add_local(Var('m'), int_rprimitive) self.k = self.env.add_local(Var('k'), int_rprimitive) self.l = self.env.add_local(Var('l'), list_rprimitive) # noqa self.ll = self.env.add_local(Var('ll'), list_rprimitive) self.o = self.env.add_local(Var('o'), object_rprimitive) self.o2 = self.env.add_local(Var('o2'), object_rprimitive) self.d = self.env.add_local(Var('d'), dict_rprimitive) self.b = self.env.add_local(Var('b'), bool_rprimitive) self.t = self.env.add_local(Var('t'), RTuple([int_rprimitive, bool_rprimitive])) self.tt = self.env.add_local( Var('tt'), RTuple( [RTuple([int_rprimitive, bool_rprimitive]), bool_rprimitive])) ir = ClassIR('A', 'mod') ir.attributes = OrderedDict([('x', bool_rprimitive), ('y', int_rprimitive)]) compute_vtable(ir) ir.mro = [ir] self.r = self.env.add_local(Var('r'), RInstance(ir)) self.context = EmitterContext(NameGenerator([['mod']])) self.emitter = Emitter(self.context, self.env) self.declarations = Emitter(self.context, self.env) self.visitor = FunctionEmitterVisitor(self.emitter, self.declarations, 'prog.py', 'prog')
def setup_generator_class(builder: IRBuilder) -> ClassIR: name = '{}_gen'.format(builder.fn_info.namespaced_name()) generator_class_ir = ClassIR(name, builder.module_name, is_generated=True) generator_class_ir.attributes[ENV_ATTR_NAME] = RInstance(builder.fn_info.env_class) generator_class_ir.mro = [generator_class_ir] builder.classes.append(generator_class_ir) builder.fn_info.generator_class = GeneratorClass(generator_class_ir) return generator_class_ir
def setup_callable_class(builder: IRBuilder) -> None: """Generates a callable class representing a nested function or a function within a non-extension class and sets up the 'self' variable for that class. This takes the most recently visited function and returns a ClassIR to represent that function. Each callable class contains an environment attribute with points to another ClassIR representing the environment class where some of its variables can be accessed. Note that its '__call__' method is not yet implemented, and is implemented in the add_call_to_callable_class function. Returns a newly constructed ClassIR representing the callable class for the nested function. """ # Check to see that the name has not already been taken. If so, rename the class. We allow # multiple uses of the same function name because this is valid in if-else blocks. Example: # if True: # def foo(): ----> foo_obj() # return True # else: # def foo(): ----> foo_obj_0() # return False name = base_name = '{}_obj'.format(builder.fn_info.namespaced_name()) count = 0 while name in builder.callable_class_names: name = base_name + '_' + str(count) count += 1 builder.callable_class_names.add(name) # Define the actual callable class ClassIR, and set its environment to point at the # previously defined environment class. callable_class_ir = ClassIR(name, builder.module_name, is_generated=True) # The functools @wraps decorator attempts to call setattr on nested functions, so # we create a dict for these nested functions. # https://github.com/python/cpython/blob/3.7/Lib/functools.py#L58 if builder.fn_info.is_nested: callable_class_ir.has_dict = True # If the enclosing class doesn't contain nested (which will happen if # this is a toplevel lambda), don't set up an environment. if builder.fn_infos[-2].contains_nested: callable_class_ir.attributes[ENV_ATTR_NAME] = RInstance( builder.fn_infos[-2].env_class ) callable_class_ir.mro = [callable_class_ir] builder.fn_info.callable_class = ImplicitClass(callable_class_ir) builder.classes.append(callable_class_ir) # Add a 'self' variable to the callable class' environment, and store that variable in a # register to be accessed later. self_target = add_self_to_env(builder.environment, callable_class_ir) builder.fn_info.callable_class.self_reg = builder.read(self_target, builder.fn_info.fitem.line)
def build_type_map(mapper: Mapper, modules: List[MypyFile], graph: Graph, types: Dict[Expression, Type], options: CompilerOptions, errors: Errors) -> None: # Collect all classes defined in everything we are compiling classes = [] for module in modules: module_classes = [ node for node in module.defs if isinstance(node, ClassDef) ] classes.extend([(module, cdef) for cdef in module_classes]) # Collect all class mappings so that we can bind arbitrary class name # references even if there are import cycles. for module, cdef in classes: class_ir = ClassIR(cdef.name, module.fullname, is_trait(cdef), is_abstract=cdef.info.is_abstract) class_ir.is_ext_class = is_extension_class(cdef) if class_ir.is_ext_class: class_ir.deletable = cdef.info.deletable_attributes[:] # If global optimizations are disabled, turn of tracking of class children if not options.global_opts: class_ir.children = None mapper.type_to_ir[cdef.info] = class_ir # Populate structural information in class IR for extension classes. for module, cdef in classes: with catch_errors(module.path, cdef.line): if mapper.type_to_ir[cdef.info].is_ext_class: prepare_class_def(module.path, module.fullname, cdef, errors, mapper) else: prepare_non_ext_class_def(module.path, module.fullname, cdef, errors, mapper) # Collect all the functions also. We collect from the symbol table # so that we can easily pick out the right copy of a function that # is conditionally defined. for module in modules: for func in get_module_func_defs(module): prepare_func_def(module.fullname, None, func, mapper)
def test_can_coerce_to(self) -> None: cls = ClassIR(name="Cls", module_name="cls") valid_cases = [ (int64_rprimitive, int64_rprimitive), (str_rprimitive, str_rprimitive), (str_rprimitive, object_rprimitive), (object_rprimitive, str_rprimitive), (RUnion([bytes_rprimitive, str_rprimitive]), str_rprimitive), (str_rprimitive, RUnion([bytes_rprimitive, str_rprimitive])), (RInstance(cls), object_rprimitive), ] invalid_cases = [ (int64_rprimitive, int32_rprimitive), (RInstance(cls), str_rprimitive), (str_rprimitive, bytes_rprimitive), ] for src, dest in valid_cases: assert can_coerce_to(src, dest) for src, dest in invalid_cases: assert not can_coerce_to(src, dest)
def setUp(self) -> None: self.registers = [] # type: List[Register] def add_local(name: str, rtype: RType) -> Register: reg = Register(rtype, name) self.registers.append(reg) return reg self.n = add_local('n', int_rprimitive) self.m = add_local('m', int_rprimitive) self.k = add_local('k', int_rprimitive) self.l = add_local('l', list_rprimitive) # noqa self.ll = add_local('ll', list_rprimitive) self.o = add_local('o', object_rprimitive) self.o2 = add_local('o2', object_rprimitive) self.d = add_local('d', dict_rprimitive) self.b = add_local('b', bool_rprimitive) self.s1 = add_local('s1', short_int_rprimitive) self.s2 = add_local('s2', short_int_rprimitive) self.i32 = add_local('i32', int32_rprimitive) self.i32_1 = add_local('i32_1', int32_rprimitive) self.i64 = add_local('i64', int64_rprimitive) self.i64_1 = add_local('i64_1', int64_rprimitive) self.ptr = add_local('ptr', pointer_rprimitive) self.t = add_local('t', RTuple([int_rprimitive, bool_rprimitive])) self.tt = add_local( 'tt', RTuple( [RTuple([int_rprimitive, bool_rprimitive]), bool_rprimitive])) ir = ClassIR('A', 'mod') ir.attributes = OrderedDict([('x', bool_rprimitive), ('y', int_rprimitive)]) compute_vtable(ir) ir.mro = [ir] self.r = add_local('r', RInstance(ir)) self.context = EmitterContext(NameGenerator([['mod']]))
def setUp(self) -> None: self.inst_a = RInstance(ClassIR('A', '__main__')) self.inst_b = RInstance(ClassIR('B', '__main__'))