]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - ast.c
ast_binstore_codegen initialize left ir value to null for output left side used for...
[xonotic/gmqcc.git] / ast.c
diff --git a/ast.c b/ast.c
index f6a5d87455150021484edcffee3d4ebb389e0d07..7061f1eff909e5ab63d30d5647398499d69d4a78 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -47,6 +47,7 @@ static void asterror(lex_ctx ctx, const char *msg, ...)
 /* It must not be possible to get here. */
 static GMQCC_NORETURN void _ast_node_destroy(ast_node *self)
 {
+    (void)self;
     con_err("ast node missing destroy()\n");
     abort();
 }
@@ -652,6 +653,11 @@ ast_ternary* ast_ternary_new(lex_ctx ctx, ast_expression *cond, ast_expression *
     self->on_true  = ontrue;
     self->on_false = onfalse;
 
+    if (!ast_type_adopt(self, ontrue)) {
+        ast_ternary_delete(self);
+        return NULL;
+    }
+
     return self;
 }
 
@@ -935,7 +941,7 @@ const char* ast_function_label(ast_function *self, const char *prefix)
     size_t len;
     char  *from;
 
-    if (!opts_dump)
+    if (!opts_dump && !opts_dumpfin)
         return NULL;
 
     id  = (self->labelcount++);
@@ -961,6 +967,8 @@ const char* ast_function_label(ast_function *self, const char *prefix)
 
 bool ast_value_codegen(ast_value *self, ast_function *func, bool lvalue, ir_value **out)
 {
+    (void)func;
+    (void)lvalue;
     /* NOTE: This is the codegen for a variable used in an expression.
      * It is not the codegen to generate the value. For this purpose,
      * ast_local_codegen and ast_global_codegen are to be used before this
@@ -1285,6 +1293,8 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
     ast_expression_common *ec;
     size_t    i;
 
+    (void)ir;
+
     irf = self->ir_func;
     if (!irf) {
         asterror(ast_ctx(self), "ast_function's related ast_value was not generated yet");
@@ -1407,10 +1417,11 @@ bool ast_block_codegen(ast_block *self, ast_function *func, bool lvalue, ir_valu
 bool ast_store_codegen(ast_store *self, ast_function *func, bool lvalue, ir_value **out)
 {
     ast_expression_codegen *cgen;
-    ir_value *left, *right;
+    ir_value *left  = NULL;
+    ir_value *right = NULL;
 
     ast_value       *arr;
-    ast_value       *idx;
+    ast_value       *idx = 0;
     ast_array_index *ai = NULL;
 
     if (lvalue && self->expression.outl) {
@@ -1630,7 +1641,12 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
 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;
+    ir_value *leftl = NULL, *leftr, *right, *bin;
+
+    ast_value       *arr;
+    ast_value       *idx = 0;
+    ast_array_index *ai = NULL;
+    ir_value        *iridx = NULL;
 
     if (lvalue && self->expression.outl) {
         *out = self->expression.outl;
@@ -1642,8 +1658,23 @@ bool ast_binstore_codegen(ast_binstore *self, ast_function *func, bool lvalue, i
         return true;
     }
 
+    if (ast_istype(self->dest, ast_array_index))
+    {
+
+        ai = (ast_array_index*)self->dest;
+        idx = (ast_value*)ai->index;
+
+        if (ast_istype(ai->index, ast_value) && idx->isconst)
+            ai = NULL;
+    }
+
     /* for a binstore we need both an lvalue and an rvalue for the left side */
     /* rvalue of destination! */
+    if (ai) {
+        cgen = idx->expression.codegen;
+        if (!(*cgen)((ast_expression*)(idx), func, false, &iridx))
+            return false;
+    }
     cgen = self->dest->expression.codegen;
     if (!(*cgen)((ast_expression*)(self->dest), func, false, &leftr))
         return false;
@@ -1658,16 +1689,45 @@ bool ast_binstore_codegen(ast_binstore *self, ast_function *func, bool lvalue, i
                                 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;
+    if (ai) {
+        /* we need to call the setter */
+        ir_value  *funval;
+        ir_instr  *call;
+
+        if (lvalue) {
+            asterror(ast_ctx(self), "array-subscript assignment cannot produce lvalues");
+            return false;
+        }
+
+        arr = (ast_value*)ai->array;
+        if (!ast_istype(ai->array, ast_value) || !arr->setter) {
+            asterror(ast_ctx(self), "value has no setter (%s)", arr->name);
+            return false;
+        }
+
+        cgen = arr->setter->expression.codegen;
+        if (!(*cgen)((ast_expression*)(arr->setter), func, true, &funval))
+            return false;
+
+        call = ir_block_create_call(func->curblock, ast_function_label(func, "store"), funval);
+        if (!call)
+            return false;
+        ir_call_param(call, iridx);
+        ir_call_param(call, bin);
+        self->expression.outr = bin;
+    } else {
+        /* 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
@@ -1716,6 +1776,8 @@ bool ast_return_codegen(ast_return *self, ast_function *func, bool lvalue, ir_va
     ast_expression_codegen *cgen;
     ir_value *operand;
 
+    *out = NULL;
+
     /* In the context of a return operation, we don't actually return
      * anything...
      */
@@ -1921,10 +1983,11 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va
     self->expression.outr = (ir_value*)1;
 
     /* generate the condition */
-    func->curblock = cond;
     cgen = self->cond->expression.codegen;
     if (!(*cgen)((ast_expression*)(self->cond), func, false, &condval))
         return false;
+    /* update the block which will get the jump - because short-logic or ternaries may have changed this */
+    cond = func->curblock;
 
     /* on-true path */
 
@@ -1971,7 +2034,6 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va
     merge = ir_function_create_block(func->ir_func, ast_function_label(func, "endif"));
     if (!merge)
         return false;
-
     /* add jumps ot the merge block */
     if (ontrue && !ontrue_endblock->final && !ir_block_create_jump(ontrue_endblock, merge))
         return false;
@@ -2330,6 +2392,8 @@ bool ast_breakcont_codegen(ast_breakcont *self, ast_function *func, bool lvalue,
 {
     ir_block *target;
 
+    *out = NULL;
+
     if (lvalue) {
         asterror(ast_ctx(self), "break/continue expression is not an l-value");
         return false;