Exemple #1
0
    async def compile(self, ctx: CompileContext) -> Register:
        lhs, rhs = await self.compile_meta(ctx)

        res = ctx.get_register(lhs.size, self.sign)

        op = {"+": "add", "-": "sub"}[self.op]

        if isinstance(await self.type, Pointer):
            # adding a pointer with an integer multiplies the integer side by the pointed to type
            (ptr_type, non_ptr) = ((self.left_type, rhs) if isinstance(
                self.left_type, Pointer) else (self.right_type, lhs))

            if isinstance(ptr_type.to, Void):
                raise self.error("Cannot perform pointer arithmetic on pointer to void.")

            ctx.emit(Binary.mul(non_ptr, Immediate(ptr_type.to.size, non_ptr.size)))
        elif (op == "sub"
              and isinstance(self.left_type, Pointer)
              and isinstance(self.right_type, Pointer)):
            if isinstance(self.left_type.to, Void):
                raise self.error("Cannot perform pointer arithmetic on pointer to void.")

            if self.left_type != self.right_type:
                raise self.error("Both sides of pointer subtraction must be the same type.")

            # subtracting two pointers of equal type yields the number of elements between them
            ctx.emit(Binary(lhs, rhs, op, res))
            ctx.emit(Binary.udiv(res, Immediate(self.left_type.to.size, res.size)))
            return res

        ctx.emit(Binary(lhs, rhs, op, res))
        return res
Exemple #2
0
    async def compile_as_arr(self, ctx: CompileContext) -> Register:
        """Compile an array literal but inline the inner values."""

        if (isinstance((await self.type).to, types.Array)
                and (not isinstance(self.first_elem, ArrayLiteral))):
            # Maybe just cast the internal type to a pointer.
            raise self.error(
                "Internal type is of array type but is not a literal.")

        if self.var is None:
            self.var = ctx.declare_unique_variable(await self.type)
            self.var.lvalue_is_rvalue = True

        base = ctx.get_register(types.Pointer.size)
        index = ctx.get_register(types.Pointer.size)

        ctx.emit(LoadVar(self.var, base))
        ctx.emit(Mov(index, base))

        elem_size = (await self.type).to.size

        for i in self.exprs:
            await i.compile_as_arr_helper(ctx, index)

        # NOTE: will we ever hit this?
        if self.float_size:
            ctx.emit(Binary.add(index, Immediate(elem_size * self.float_size)))

        return base
Exemple #3
0
    async def compile(self, ctx: CompileContext) -> Register:
        op = {"|": "or", "^": "xor", "&": "and"}[self.op]

        lhs, rhs = await self.compile_meta(ctx)
        res = ctx.get_register(lhs.size, self.sign)
        ctx.emit(Binary(lhs, rhs, op, res))
        return res
Exemple #4
0
    async def compile_as_ref(self, ctx: CompileContext) -> Register:
        """Compile to the array literal and return a reference to the start.

        This function is for when an array of references is the wanted outcome.
        This function will not work on array types.
        """

        if self.var is None:
            self.var = ctx.declare_unique_variable(await self.type)
            self.var.lvalue_is_rvalue = True

        if (isinstance(self.first_elem, ArrayLiteral) and (not isinstance(
            (await self.type).to, types.Pointer))):
            raise self.error(
                "Cannot compile to references if internal array type is an array and not a pointer"
            )

        base = ctx.get_register(types.Pointer.size)
        index = ctx.get_register(types.Pointer.size)

        ctx.emit(LoadVar(self.var, base))
        ctx.emit(Mov(index, base))

        elem_type = (await self.type).to

        for i in self.exprs:
            r = await i.compile(ctx)

            if r.size != elem_type.size:
                r0 = r.resize(elem_type.size, elem_type.signed)
                ctx.emit(Resize(r, r0))
                r = r0

            ctx.emit(Mov(Dereference(index, r.size), r))
            ctx.emit(Binary.add(index, Immediate(r.size, types.Pointer.size)))

        if self.float_size:
            # fill in missing values
            ctx.emit(
                Binary.add(
                    index,
                    Immediate(elem_type.size * self.float_size, index.size)))

        return base
Exemple #5
0
    async def compile(self, ctx: CompileContext) -> Register:
        my_type = await self.type

        ptr: Register = await self.load_lvalue(ctx)
        tmp = ctx.get_register(my_type.size, my_type.signed)

        increment = 1
        # in the case of pointer increments, increment by the size of the pointer's underlying type
        if isinstance(my_type, Pointer):
            increment = my_type.to.size

        ctx.emit(Mov(tmp, Dereference(ptr, tmp.size)))
        ctx.emit(Binary(tmp, Immediate(increment, tmp.size), self.op))
        ctx.emit(Mov(Dereference(ptr, tmp.size), tmp))
        return tmp
Exemple #6
0
    async def load_lvalue(self, ctx: CompileContext) -> Register:
        atype = await self.arg.type

        if not isinstance(atype, (Pointer, Array)):
            raise self.error(f"Incompatible type to array index base {atype}")

        # don't allow void pointer arithmetic
        # This 'would' fail later with an error about requesting a register of size 0
        # But that would be less informative than catching the error now.
        if isinstance(atype.to, Void):
            raise self.error("Cannot perform pointer arithemetic on void pointers.")

        argument = await self.arg.compile(ctx)
        offset = await self.offset.compile(ctx)

        # get the size of the inner type if type.to is an array,
        # this will be the size of the internal array
        size = await self.size

        # make sure both the offset and the arguments are the correct size (size of a pointer)
        if argument.size != Pointer.size:
            argument0 = argument.resize(Pointer.size)
            ctx.emit(Resize(argument, argument0))
            argument = argument0

        if offset.size != Pointer.size:
            offset0 = offset.resize(Pointer.size)
            ctx.emit(Resize(offset, offset0))
            offset = offset0

        result = ctx.get_register(Pointer.size)
        # multiply to the size of the inner type of the pointer/ array
        ctx.emit(Binary.mul(offset, Immediate(size, offset.size)))
        ctx.emit(Binary.add(argument, offset, result))

        return result
Exemple #7
0
 async def compile_as_arr_helper(self, ctx: CompileContext, base: Register):
     if isinstance(self.first_elem, ArrayLiteral) and isinstance(
             await self.type, types.Array):
         for i in self.exprs:
             await i.compile_as_arr_helper(ctx, base)
     else:
         elem_type = (await self.type).to
         for i in self.exprs:
             r = await i.compile(ctx)
             if r.size != elem_type.size:
                 r0 = r.resize(elem_type.size, elem_type.signed)
                 ctx.emit(Resize(r, r0))
                 r = r0
             ctx.emit(Mov(Dereference(base, r.size), r))
             ctx.emit(
                 Binary.add(base, Immediate(r.size, types.Pointer.size)))
Exemple #8
0
    async def compile(self, ctx: CompileContext) -> Register:
        my_type = await self.type

        ptr: Register = await self.arg.load_lvalue(ctx)
        size = my_type.size
        res, temp = (ctx.get_register(size, my_type.signed),
                     ctx.get_register(size))

        increment = 1
        if isinstance(my_type, Pointer):
            increment = my_type.to.size

        ctx.emit(Mov(res, Dereference(ptr, res.size)))
        ctx.emit(Binary(res, Immediate(increment, size), self.op, temp))
        ctx.emit(Mov(Dereference(ptr, temp.size), temp))
        return res
Exemple #9
0
    async def compile(self, ctx: CompileContext) -> Register:
        lhs, rhs = await self.compile_meta(ctx)
        if rhs.sign:
            raise self.right.error(
                "RHS operand to a binary shift op must be unsigned.")

        res = ctx.get_register(lhs.size, self.sign)

        if self.op == "<<":
            op = "shl"
        elif self.op == ">>" and lhs.sign:
            op = "sar"
        else:
            op = "shr"

        ctx.emit(Binary(lhs, rhs, op, res))
        return res
Exemple #10
0
    async def compile(self, ctx: CompileContext) -> Register:
        lhs, rhs = await self.compile_meta(ctx)

        res = ctx.get_register(lhs.size, self.sign)

        if self.op == "*":
            op = "mul"
        elif self.op == "%":
            if self.sign:
                op = "imod"
            else:
                op = "umod"
        elif self.op == "/" and self.sign:
            op = "idiv"
        else:
            op = "udiv"

        ctx.emit(Binary(lhs, rhs, op, res))
        return res