Example #1
0
    def build_del_statement(self, del_statement):
        for expression in del_statement.expressions:
            if type(expression) is GetAttrExpression:
                obj = self.build_expression(expression.target)
                if obj.type == "None":
                    raise CodegenError(
                        "AttributeError: 'NoneType' object has no attribute '{}'."
                        .format(expression.item))
                function_name = obj.type + ".__delattr__"
                self.make_call(function_name, obj,
                               self.build_string(expression.item))
                self.memory_manager.try_free_temporary([obj])
            elif type(expression) is GetItemExpression:
                obj = self.build_expression(expression.target)
                if obj.type == "None":
                    raise CodegenError(
                        "TypeError: 'NoneType' object does not support item deletion."
                    )
                function_name = obj.type + ".__delitem__"

                args = [obj]
                for arg_ast in expression.args:
                    arg = self.build_expression(arg_ast)
                    args.append(arg)
                self.make_call(function_name, *args)
                self.memory_manager.try_free_temporary(args)
            elif type(expression) is VariableExpression:
                self.memory_manager.delete_variable(expression.name)
            else:
                raise CodegenError("can not delete {}".format(
                    type(expression)))
Example #2
0
    def get_attribute(self, obj, attr):
        if isinstance(attr, StringConstant):
            attr_name = attr.value
        elif isinstance(attr, str):
            attr_name = attr
        else:
            raise CodegenError(
                "get attribute from object dynamically is not supported yet.")

        t = self.compiler.get_type(obj.type)

        for i, field in enumerate(t.fields):
            if field.name == attr_name:
                field_ptr = self.ir_builder.gep(obj.value, [
                    self.ir_const(0),
                    self.ir_const(i),
                ])
                # 不太对。。取属性的话应该使用复制构造函数弄个新的值出来。。
                if self.builtins_builder.is_primitive_type(field.type):
                    field_value = self.ir_builder.load(field_ptr)
                    return self.primitive(field.type, field_value)
                else:
                    field_ir_type = self.compiler.get_ir_type(field.type)
                    field_value = Slot(field.type, field_ir_type, is_tmp=False)
                    field_value.value = field_ptr  # ir.PointerType(field_ir_type)!
                    field_value.ref = None
                    return field_value
        else:
            raise CodegenError("type {} has no field named {}".format(
                obj.type, attr_name))
Example #3
0
 def build_return_statement(self, return_statement):
     assert self.ast_function.rtype
     if return_statement.expression:
         if self.ast_function.rtype == "None":
             raise CodegenError(
                 "function {} must not return a value.".format(
                     self.ast_function.qname))
         expr = self.build_expression(return_statement.expression)
         if self.ir_builder.block is not self.memory_manager.variables.block:
             print(self.ir_builder.block,
                   self.memory_manager.variables.block)
             raise CodegenError(
                 "checkpoint: variables.block is not the same as self.ir_builder.block."
             )
         self.retvalue_versions.append([expr.value, self.ir_builder.block])
         self.ir_builder.branch(self.clean_block)
     else:
         if self.ast_function.rtype == "None":
             if self.retvalue_versions:
                 raise CodegenError(
                     "function {} must not return any value.".format(
                         self.ast_function.qname))
             else:
                 self.ir_builder.branch(self.clean_block)
         else:
             raise CodegenError("function must return a value.")
Example #4
0
    def build_if_statement(self, if_statement):
        if not if_statement.flow:
            raise CodegenError(
                "if statement must have one or more than one suite.")

        orignal_block = self.ir_builder.block
        endif_block = None

        branch_versions = []
        for condition, suite in if_statement.flow:
            true_block = self.ir_builder.append_basic_block(
                name=orignal_block.name + ".if")
            false_block = self.ir_builder.append_basic_block(
                name=orignal_block.name + ".else")
            expr = self.build_expression(condition)
            converted_value = self.cast(expr, "bool")
            condition_version = self.memory_manager.variables
            self.ir_builder.cbranch(converted_value.value, true_block,
                                    false_block)

            self.ir_builder.position_at_end(true_block)
            self.memory_manager.branch_version(true_block)
            self.build_suite(suite)
            if self.ir_builder.block.terminator is None:  # 可能里面又有跳转。。所以 self.builder.block 不一定是 true_block
                if endif_block is None:
                    endif_block = self.ir_builder.append_basic_block(
                        name=orignal_block.name + ".endif")
                self.ir_builder.branch(endif_block)
                branch_versions.append(self.memory_manager.variables)

            self.ir_builder.position_at_end(false_block)
            self.memory_manager.variables = condition_version  # restore orignal version
            self.memory_manager.branch_version(false_block)

        if if_statement.otherwise:
            self.memory_manager.branch_version(self.ir_builder.block)
            self.build_suite(if_statement.otherwise)
            if self.ir_builder.block.terminator is None:
                if endif_block is None:
                    endif_block = self.ir_builder.append_basic_block(
                        name=orignal_block.name + ".endif")
                self.ir_builder.branch(endif_block)
                branch_versions.append(self.memory_manager.variables)

        if endif_block is not None:
            if not branch_versions:
                raise CodegenError(
                    "endif block exists while branch_versions is empty.")
            self.ir_builder.position_at_end(endif_block)
            self.memory_manager.variables = self.memory_manager.merge_versions(
                branch_versions)
            self.memory_manager.variables.block = endif_block
        else:
            if branch_versions:
                raise CodegenError(
                    "endif block not exists while branch_versions is not empty."
                )
Example #5
0
 def call_magic_binary_method(self, operator, lhs, rhs):
     magic_methods = {
         "+": "__add__",
         "-": "__sub__",
         "*": "__mul__",
         "/": "__truediv__",
         "//": "__floordiv__",
         "%": "__mod__",
         "**": "__pow__",
         "<<": "__lshift__",
         ">>": "__rshift__",
         "|": "__or__",
         "&": "__and__",
         "^": "__xor__",
         "<": "__lt__",
         "<=": "__le__",
         "==": "__eq__",
         "!=": "__ne__",
         ">": "__gt__",
         ">=": "__ge__",
         "in": "__contains__",
     }
     reversed_magic_methods = {
         "+": "__radd__",
         "-": "__rsub__",
         "*": "__rmul__",
         "/": "__rtruediv__",
         "//": "__rfloordiv__",
         "%": "__rmod__",
         "**": "__rpow__",
         "<<": "__rlshift__",
         ">>": "__rrshift__",
         "|": "__ror__",
         "&": "__rand__",
         "^": "__rxor__",
     }
     try:
         magic_function_name = magic_methods.get(operator)
         if not magic_function_name:
             raise CodegenError(
                 "unsupported operator {} for type `{}`.".format(
                     operator, lhs.type))
         function_name = lhs.type + "." + magic_function_name
         return self.make_call(function_name, lhs, rhs)
     except FunctionNotFound:
         magic_function_name = reversed_magic_methods.get(operator)
         if not magic_function_name:
             raise CodegenError(
                 "unsupported operator {} for type `{}`.".format(operator))
         function_name = rhs.type + "." + magic_function_name
         try:
             return self.make_call(function_name, rhs, lhs)
         except:
             raise CodegenError("unsupported operator {}".format(operator))
Example #6
0
 def cast(self, expr, target_type):
     if expr.type == target_type:
         return expr
     try:
         target = self.make_call(target_type, expr)
         if target.type == target_type:
             return target
         else:
             raise CodegenError("{}() must return {} type.".format(
                 target_type, target_type))
     except FunctionNotFound:
         raise CodegenError("can not cast {} to {}.".format(
             expr.type, target_type))
Example #7
0
 def make_ir_type(self, compiler):
     if not self.fields:
         raise CodegenError("type {} has no defined field.".format(
             self.name))
     else:
         elems = []
         for field in self.fields:
             try:
                 field_type = compiler.types[field.type]
             except KeyError:
                 raise CodegenError("unknown field type: {}".format(
                     field.type))
             elems.append(field_type.ir_type)
         self.ir_type = ir.LiteralStructType(elems)
Example #8
0
 def call_magic_unary_method(self, operator, expr):
     magic_methods = {
         "~": "__invert__",
         "-": "__neg__",
         "+": "__pos__",
     }
     try:
         magic_function_name = magic_methods.get(operator)
         if not magic_function_name:
             raise CodegenError("unsupported operator {}".format(operator))
         function_name = expr.type + "." + magic_function_name
         return self.make_call(function_name, expr)
     except FunctionNotFound:
         raise CodegenError("unsupported operator {}".format(operator))
Example #9
0
 def build_suite(self, suite: Suite):
     for statement in suite.statements:
         if type(statement) is ExpressionStatement:
             self.build_expression_statement(statement)
         elif type(statement) is DelStatement:
             self.build_del_statement(statement)
         elif type(statement) is PassStatement:
             pass
         elif type(statement) is ReturnStatement:
             self.build_return_statement(statement)
         elif type(statement) is BreakStatement:
             self.build_break_statement(statement)
         elif type(statement) is ContinueStatement:
             self.build_continue_statement(statement)
         elif type(statement) is FunctionDefinationStatement:
             self.build_function_statement(statement)
         elif type(statement) is IfStatement:
             self.build_if_statement(statement)
         elif type(statement) is WhileStatement:
             self.build_while_statement(statement)
         elif type(statement) is ForStatement:
             self.build_for_statement(statement)
         else:
             raise CodegenError("{} statement is not implemented!".format(
                 type(statement)))
Example #10
0
 def dot_bool(self, x):
     if x.type == "bool":
         return x
     try:
         return self.function_builder.make_call(x.type + ".__bool__", x)
     except FunctionNotFound:
         raise CodegenError("can not cast {} type to bool.".format(x.type))
Example #11
0
 def create_type(self, name, ir_type):
     if name in self.types:
         raise CodegenError("duplicated type.")
     t = Type(name)
     if ir_type:  # if ir_type is not provided, use make_ir_type() to generate an ir_type later.
         t.ir_type = ir_type
     self.types[name] = t
     return t
Example #12
0
 def dot_count(self, x, y):
     if x.type != "str" or y.type != "str":
         raise CodegenError(
             "str.count() require a str argument, but given {}".format(
                 y.type))
     aggie_str_count = self.native_invoker.aggie_str_count
     result = aggie_str_count(self.function_builder, x.value, y.value)
     self.try_free_temporary([x, y])
     return self.primitive("int", result)
Example #13
0
 def dot_str(self, x=None):
     if x is not None:
         result = self.function_builder.make_call(x.type + ".__str__", x)
         if result.type != "str":
             raise CodegenError("{}.__str__() do not return str.".format(
                 x.type))
         return result
     else:
         return self.function_builder.build_constant("")
Example #14
0
 def dot__add__(self, x, y):
     if x.type != "str" or y.type != "str":
         raise CodegenError(
             "str can only concat with another str, not {}".format(y.type))
     result_slot = self.function_builder.memory_manager.allocate_slot("str")
     aggie_str_concat = self.native_invoker.aggie_str_concat
     aggie_str_concat(self.function_builder, x.value, y.value,
                      result_slot.value)
     self.try_free_temporary([x, y])
     return result_slot
Example #15
0
    def delete_variable(self, name: str, version: Variables = None):
        if version is None:
            version = self.variables

        old_value = version.get(name)
        if old_value:
            old_value.decref(self.function_builder)
        else:
            raise CodegenError(
                "NameError: name '{}' is not defined.".format(name))
Example #16
0
    def make_call(self, function_name, *args):
        try:
            return self.builtins_builder.try_inline(function_name, *args)
        except CanNotInline:
            # TODO use memory_manager to find function by name
            ast_function = self.ast_function
            callee = None
            qname = ""
            while ast_function:
                qname = make_qname(ast_function.qname, function_name)
                callee = self.module.functions.get(qname)
                if callee:
                    break
                ast_function = ast_function.upper
            if not callee:
                raise FunctionNotFound(
                    "function named {} is not found.".format(qname))

            ir_function = self.ir_module.globals.get(qname)
            if not ir_function:
                raise FunctionNotFound(
                    "function named {} is not compile yet.".format(qname))

            if len(callee.ast.args) != len(args):
                raise FunctionNotFound(
                    "function named {} require {} arguments, but provide {}.".
                    format(len(callee.ast.args), len(args)))

            arg_values = []
            if callee.ast.rtype != "None" and not self.builtins_builder.is_primitive_type(
                    callee.ast.rtype):
                result_value = self.memory_manager.allocate_slot(
                    callee.ast.rtype, with_ref=True)
                arg_values.append(result_value.value)
            else:
                result_value = None

            for i, arg in enumerate(args):
                arg_name, arg_type = callee.ast.args[i]
                if arg.type != arg_type:
                    raise CodegenError(
                        "given an unmatched argument {} type {} (wanted {}) while calling {}"
                        .format(i, arg.type, arg_type, callee.name))
                arg_values.append(arg.value)
            result_type = callee.ast.rtype
            t = self.ir_builder.call(ir_function,
                                     arg_values,
                                     name=callee.name + ".rvalue")
            self.memory_manager.try_free_temporary(args)
            if result_type == "None":
                return NoneValue()
            elif self.builtins_builder.is_primitive_type(result_type):
                return self.primitive(result_type, t)
            else:
                return result_value
Example #17
0
 def ir_const(self, value: (bool, int, float)):
     if value is True:
         return ir.Constant(ir.IntType(1), 1)
     elif value is False:
         return ir.Constant(ir.IntType(1), 0)
     elif type(value) is int:
         return ir.Constant(ir.IntType(64), value)
     elif type(value) is float:
         return ir.Constant(ir.FloatType(), value)
     else:
         raise CodegenError("unknown constant: {}", repr(value))
Example #18
0
 def dot__mul__(self, x, y):
     if y.type != "int":
         raise CodegenError(
             "duplicate str require an integer times, but given {}.".format(
                 y.type))
     aggie_str_duplicate = self.native_invoker.aggie_str_duplicate
     ptr_result = self.function_builder.memory_manager.allocate_slot("str")
     aggie_str_duplicate(self.function_builder, x.value, y.value,
                         ptr_result.value)
     self.try_free_temporary([x, y])
     return ptr_result
Example #19
0
    def dot_startswith(self, x, y):
        if x.type != "str" or y.type != "str":
            raise CodegenError(
                "str.startswith() require a str argument, but given {}.".
                format(y.type))

        aggie_str_startswith = self.native_invoker.aggie_str_startswith
        result = aggie_str_startswith(self.function_builder, x.value, y.value)
        b = self.char_to_bool(result, name="str.startswith")
        self.try_free_temporary([x, y])
        return self.primitive("bool", b)
Example #20
0
    def allocate_slot(self,
                      slot_type: (str, ir.Type),
                      with_ref=True,
                      init_callback=None):
        slot_name = "slot_" + str(len(self.slots))
        ref_name = "ref_" + str(len(self.slots))

        if isinstance(slot_type, str):
            slot = Slot(slot_type,
                        self.function_builder.compiler.get_ir_type(slot_type),
                        is_tmp=True)
        else:
            if with_ref:
                raise CodegenError(
                    "slot with type {} is not managed by memory manager, must set with_ref = False."
                    .format(slot_type))
            slot = Slot("", slot_type, is_tmp=True)

        ir_builder = self.function_builder.ir_builder

        current_block = ir_builder.block
        ir_builder.position_at_end(self.function_builder.vars_block)

        slot.value = ir_builder.alloca(slot.ir_type, name=slot_name)

        if with_ref:
            slot.ref = ir_builder.alloca(MemoryManager.ReferenceCountIrType,
                                         name=ref_name)
        else:
            slot.ref = None

        if init_callback:
            try:
                init_callback(slot)
            except:
                raise CodegenError(
                    "call init_callback failed while allocating slot.")

        ir_builder.position_at_end(current_block)
        self.slots.append(slot)
        return slot
Example #21
0
    def build_expression_statement(self, expression_statement):
        value = self.build_expression(expression_statement.expression)

        if not expression_statement.variable:
            self.memory_manager.try_free_temporary([value])
            return

        if value.type == "None":
            raise CodegenError("can not assign None to variable {}.".format(
                expression_statement.variable))
        self.memory_manager.assign_variable(expression_statement.variable,
                                            value)
Example #22
0
 def dot__contains__(self, x, y):
     if x.type != "str" or y.type != "str":
         raise CodegenError(
             "contains operation of str require str, not {}".format(y.type))
     aggie_str_contains = self.native_invoker.aggie_str_contains
     bool_result = aggie_str_contains(self.function_builder, x.value,
                                      y.value)
     b = self.ir_builder.icmp_signed("!=",
                                     bool_result,
                                     self.ir_const(0),
                                     name="booltmp")
     self.try_free_temporary([x, y])
     return self.primitive("bool", b)
Example #23
0
 def build_constant(self, value: (bool, int, float, str, bytes)):
     result = self.ir_const(value)
     if value is True or value is False:
         return self.primitive("bool", result)
     elif type(value) is int:
         return self.primitive("int", result)
     elif type(value) is float:
         return self.primitive("float", result)
     elif type(value) is str:
         return self.build_string(value)
     elif type(value) is bytes:
         return self.build_bytes(value)
     else:
         raise CodegenError("unknown constant: {}", repr(value))
Example #24
0
 def rich_compare(self, x, y, operator, name):
     if x.type != "str" or y.type != "str":
         raise CodegenError(
             "str can only compare to another str, but not {}".format(
                 y.type))
     aggie_str_compare = self.native_invoker.aggie_str_compare
     compare_result = aggie_str_compare(self.function_builder, x.value,
                                        y.value)
     b = self.ir_builder.icmp_signed(operator,
                                     compare_result,
                                     self.ir_const(0),
                                     name=name)
     self.try_free_temporary([x, y])
     return "bool",
Example #25
0
    def bootstrap(self, module_name):
        # FIXME this is a very simple libc-amd64 version, do more when porting to windows..
        ir_main_function_type = ir.FunctionType(ir.IntType(32), [])
        function = ir.Function(self.ir_module, ir_main_function_type, "main")
        entry = function.append_basic_block("entry")
        builder = ir.IRBuilder(entry)

        qname = module_name + COMPILE_METHOD
        callee = self.ir_module.globals.get(qname)
        if not callee:
            raise CodegenError("can not find main function.")

        builder.call(callee, [])
        builder.ret(ir.Constant(ir.IntType(32), 0))
Example #26
0
    def compile(self, module_name, module_ast_function, replace=True):
        function = Function(ast=module_ast_function)
        module = Module(module_name, function)

        if module_name in self.modules:
            if replace:
                module.functions = self.modules[module_name].functions
            else:
                raise CodegenError(
                    "module {} has been defined.".format(module_name))

        module_builder = ModuleBuilder(module, self)
        module_builder.build()

        self.modules[module_name] = module
Example #27
0
 def assign_variable(self,
                     name: str,
                     value: Value,
                     version: Variables = None):
     if version is None:
         version = self.variables
     old_value = version.get(name)
     if old_value:
         if old_value.type != value.type:
             raise CodegenError(
                 "can not reassign `{}` from `{}` type to `{}` type.".
                 format(name, old_value.type, value.type))
         old_value.decref(self.function_builder)
     version[name] = value
     value.incref(self.function_builder)
Example #28
0
    def __call__(self, function_compiler, *args):
        ir_builder = function_compiler.ir_builder
        if len(args) != len(self.arguments):
            raise CodegenError("native function call `{}` called without match arguments. ")

        arg_values = []
        for expr_value, expected_arg_native_type in zip(args, self.arguments):
            if expected_arg_native_type is aggie_bool:
                v = ir_builder.zext(expr_value, aggie_bool)
                arg_values.append(v)
            else:
                arg_values.append(expr_value)

        if not self.f:
            self.generator_ir_function(function_compiler.compiler.ir_module)
        return ir_builder.call(self.f, arg_values, name = "{}.rvalue".format(self.name))
Example #29
0
    def make_ir_function_type(self, ast_function):
        param_types = []
        if self.builtins_builder.is_primitive_type(ast_function.rtype):
            ir_rtype = self.compiler.get_ir_type(ast_function.rtype)
        else:
            ir_rtype = ir.VoidType()
            if ast_function.rtype != "None":
                param_types.append(
                    ir.PointerType(
                        self.compiler.get_ir_type(ast_function.rtype)))

        for arg_name, arg_type in ast_function.args:
            if arg_type == "None":
                raise CodegenError("None is not allow for parameters: {}, {}",
                                   ast_function.name, arg_name)
            if self.builtins_builder.is_primitive_type(arg_type):
                param_types.append(self.compiler.get_ir_type(arg_type))
            else:
                param_types.append(
                    ir.PointerType(self.compiler.get_ir_type(arg_type)))
        return ir.FunctionType(ir_rtype, param_types)
Example #30
0
 def dot__getitem__(self, x, y):
     if y.type == "int":
         ptr_char = self.function_builder.memory_manager.allocate_slot(
             "str")
         aggie_str_at = self.native_invoker.aggie_str_at
         aggie_str_at(self.function_builder, x.value, y.value, ptr_char)
         self.try_free_temporary([x])
         return ptr_char
     elif y.type == "slice":
         ptr_substr = self.function_builder.memory_manager.allocate_slot(
             "str")
         aggie_str_mid = self.native_invoker.aggie_str_mid
         start = self.function_builder.get_attribute(y, "start")
         end = self.function_builder.get_attribute(y, "end")
         step = self.function_builder.get_attribute(y, "step")
         aggie_str_mid(self.function_builder, x.value, start.value,
                       end.value, step.value, ptr_substr)
         self.try_free_temporary([x, y])
         return ptr_substr
     else:
         raise CodegenError(
             "str indices require int or slice, but not {}".format(y.type))