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
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
async def compile(self, ctx: CompileContext) -> Register: lhs_type, rhs_type = await self.left.type, await self.right.type if not rhs_type.implicitly_casts_to(lhs_type): raise self.error( f"Right argument to boolean operator: '{self.right.matched_region}'\n" f"of type: {rhs_type} cannot be casted to left argument: '{self.left.matched_region}'\n" f"of type {lhs_type}") if isinstance(lhs_type, Void): raise self.left.error("Void type argument to boolean operator") if isinstance(rhs_type, Void): raise self.right.error("Void type argument to boolean operator") r1: Register = await self.left.compile(ctx) ctx.emit(Compare(r1, Immediate(0, r1.size))) target = JumpTarget() op = {'or': CompType.neq, 'and': CompType.eq}[self.op] cond = ctx.get_register(1) ctx.emit(SetCmp(cond, op)) ctx.emit(Jump(target, cond)) r2: Register = (await self.right.compile(ctx)) if r2.size != r1.size: r2_ = r2.resize(r1.size, r1.sign) ctx.emit(Resize(r2, r2_)) r2 = r2_ ctx.emit(Mov(r1, r2)) ctx.emit(target) return r1
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
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
async def compile(self, ctx: CompileContext) -> Register: my_type = await self.type ptr = await self.load_lvalue(ctx) if isinstance(my_type, Void): raise self.error("Cannot dereference a void pointer.") reg = ctx.get_register(my_type.size, my_type.signed) ctx.emit(Mov(reg, Dereference(ptr, reg.size))) return reg
async def compile(self, ctx: CompileContext) -> Register: ptr: Register = await self.load_lvalue(ctx) if ptr.size != Pointer.size: ptr0 = ptr.resize(Pointer.size) ctx.emit(Resize(ptr, ptr0)) ptr = ptr0 # indexes that leave an array type dont dereference if isinstance(await self.type, Array): return ptr my_type = await self.type res = ctx.get_register(my_type.size, my_type.signed) ctx.emit(Mov(res, Dereference(ptr, res.size))) return res
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)))
async def compile(self, ctx: CompileContext) -> Register: rhs: Register = (await self.right.compile(ctx)) lhs: Register = (await self.left.load_lvalue(ctx)) lhs_type = await self.left.type rhs_type = await self.right.type lhs_sign = lhs_type.signed lhs_size = lhs_type.size if not rhs_type.implicitly_casts_to(lhs_type): raise self.right.error(f"Incompatible rhs type '{rhs_type}' assignment to type '{lhs_type}'") if lhs_type.const: raise self.error("cannot assign to const type.") if lhs_size != rhs.size: rhs_ = rhs.resize(lhs_size, lhs_sign) ctx.emit(Resize(rhs, rhs_)) rhs = rhs_ ctx.emit(Mov(Dereference(lhs, rhs.size), rhs)) return rhs
async def compile(self, ctx: CompileContext) -> Register: reg = ctx.get_register(self._type.size, self._type.signed) ctx.emit(Mov(reg, Immediate(self.lit, self._type.size))) return reg