+ self->expression.outr = *out;
+
+ return true;
+}
+
+bool ast_binstore_codegen(ast_binstore *self, ast_function *func, bool lvalue, ir_value **out)
+{
+ ast_expression_codegen *cgen;
+ ir_value *leftl, *leftr, *right, *bin;
+
+ if (lvalue && self->expression.outl) {
+ *out = self->expression.outl;
+ return true;
+ }
+
+ if (!lvalue && self->expression.outr) {
+ *out = self->expression.outr;
+ return true;
+ }
+
+ /* for a binstore we need both an lvalue and an rvalue for the left side */
+ /* rvalue of destination! */
+ cgen = self->dest->expression.codegen;
+ if (!(*cgen)((ast_expression*)(self->dest), func, false, &leftr))
+ return false;
+
+ /* source as rvalue only */
+ cgen = self->source->expression.codegen;
+ if (!(*cgen)((ast_expression*)(self->source), func, false, &right))
+ return false;
+
+ /* now the binary */
+ bin = ir_block_create_binop(func->curblock, ast_function_label(func, "binst"),
+ self->opbin, leftr, right);
+ self->expression.outr = bin;
+
+ /* now store them */
+ cgen = self->dest->expression.codegen;
+ /* lvalue of destination */
+ if (!(*cgen)((ast_expression*)(self->dest), func, true, &leftl))
+ return false;
+ self->expression.outl = leftl;
+
+ if (!ir_block_create_store_op(func->curblock, self->opstore, leftl, bin))
+ return false;
+ self->expression.outr = bin;
+
+ /* Theoretically, an assinment returns its left side as an
+ * lvalue, if we don't need an lvalue though, we return
+ * the right side as an rvalue, otherwise we have to
+ * somehow know whether or not we need to dereference the pointer
+ * on the left side - that is: OP_LOAD if it was an address.
+ * Also: in original QC we cannot OP_LOADP *anyway*.
+ */
+ *out = (lvalue ? leftl : bin);
+
+ return true;
+}
+
+bool ast_unary_codegen(ast_unary *self, ast_function *func, bool lvalue, ir_value **out)
+{
+ ast_expression_codegen *cgen;
+ ir_value *operand;
+
+ /* In the context of a unary operation, we can disregard
+ * the lvalue flag.
+ */
+ (void)lvalue;
+ if (self->expression.outr) {
+ *out = self->expression.outr;
+ return true;
+ }
+
+ cgen = self->operand->expression.codegen;
+ /* lvalue! */
+ if (!(*cgen)((ast_expression*)(self->operand), func, false, &operand))
+ return false;
+
+ *out = ir_block_create_unary(func->curblock, ast_function_label(func, "unary"),
+ self->op, operand);
+ if (!*out)
+ return false;
+ self->expression.outr = *out;
+
+ return true;
+}
+
+bool ast_return_codegen(ast_return *self, ast_function *func, bool lvalue, ir_value **out)
+{
+ ast_expression_codegen *cgen;
+ ir_value *operand;
+
+ /* In the context of a return operation, we can disregard
+ * the lvalue flag.
+ */
+ (void)lvalue;
+ if (self->expression.outr) {
+ asterror(ast_ctx(self), "internal error: ast_return cannot be reused, it bears no result!\n");
+ return false;
+ }
+ self->expression.outr = (ir_value*)1;
+
+ cgen = self->operand->expression.codegen;
+ /* lvalue! */
+ if (!(*cgen)((ast_expression*)(self->operand), func, false, &operand))
+ return false;
+
+ if (!ir_block_create_return(func->curblock, operand))
+ return false;