]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - parser.c
fix a leak in the local-allocator
[xonotic/gmqcc.git] / parser.c
index 511370070a8118400e4ab6e1f102b7e5966f1f8d..7bf7a0cd89682a4b6fe47e64c97de271a5c1121a 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -488,10 +488,6 @@ static bool immediate_is_true(lex_ctx ctx, ast_value *v)
             if (v->constval.vstring && OPTS_FLAG(TRUE_EMPTY_STRINGS))
                 return true;
             return !!v->constval.vstring[0];
-        case TYPE_ENTITY:
-            return !!v->constval.ventity;
-        case TYPE_FIELD:
-            return !!v->constval.vfield;
         default:
             compile_error(ctx, "internal error: immediate_is_true on invalid type");
             return !!v->constval.vfunc;
@@ -1898,10 +1894,61 @@ static void parser_addlocal(parser_t *parser, const char *name, ast_expression *
     util_htset(vec_last(parser->variables), name, (void*)e);
 }
 
+static ast_expression* process_condition(parser_t *parser, ast_expression *cond, bool *_ifnot)
+{
+    bool       ifnot = false;
+    ast_unary *unary;
+    ast_expression *prev;
+
+    if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && cond->expression.vtype == TYPE_STRING) {
+        prev = cond;
+        cond = (ast_expression*)ast_unary_new(ast_ctx(cond), INSTR_NOT_S, cond);
+        if (!cond) {
+            ast_unref(prev);
+            parseerror(parser, "internal error: failed to process condition");
+            return NULL;
+        }
+        ifnot = !ifnot;
+    }
+    else if (OPTS_FLAG(CORRECT_LOGIC)) {
+        /* everything must use a NOT_ */
+        unary = (ast_unary*)cond;
+        if (!ast_istype(cond, ast_unary) || unary->op < INSTR_NOT_F || unary->op > INSTR_NOT_FNC)
+        {
+            /* use the right NOT_ */
+            prev = cond;
+            cond = (ast_expression*)ast_unary_new(ast_ctx(cond), type_not_instr[cond->expression.vtype], cond);
+            if (!cond) {
+                ast_unref(prev);
+                parseerror(parser, "internal error: failed to process condition");
+                return NULL;
+            }
+            ifnot = !ifnot;
+        }
+    }
+
+    unary = (ast_unary*)cond;
+    while (ast_istype(cond, ast_unary) && unary->op == INSTR_NOT_F)
+        /*&& unary->operand->expression.vtype != TYPE_STRING) */
+    {
+        cond = unary->operand;
+        unary->operand = NULL;
+        ast_delete(unary);
+        ifnot = !ifnot;
+        unary = (ast_unary*)cond;
+    }
+
+    if (!cond)
+        parseerror(parser, "internal error: failed to process condition");
+
+    if (ifnot) *_ifnot = !*_ifnot;
+    return cond;
+}
+
 static bool parse_if(parser_t *parser, ast_block *block, ast_expression **out)
 {
     ast_ifthen *ifthen;
-    ast_expression *cond, *ontrue, *onfalse = NULL;
+    ast_expression *cond, *ontrue = NULL, *onfalse = NULL;
     bool ifnot = false;
 
     lex_ctx ctx = parser_ctx(parser);
@@ -1965,6 +2012,13 @@ static bool parse_if(parser_t *parser, ast_block *block, ast_expression **out)
         }
     }
 
+    cond = process_condition(parser, cond, &ifnot);
+    if (!cond) {
+        if (ontrue)  ast_delete(ontrue);
+        if (onfalse) ast_delete(onfalse);
+        return false;
+    }
+
     if (ifnot)
         ifthen = ast_ifthen_new(ctx, cond, onfalse, ontrue);
     else
@@ -1978,6 +2032,8 @@ static bool parse_while(parser_t *parser, ast_block *block, ast_expression **out
     ast_loop *aloop;
     ast_expression *cond, *ontrue;
 
+    bool ifnot = false;
+
     lex_ctx ctx = parser_ctx(parser);
 
     (void)block; /* not touching */
@@ -2013,7 +2069,12 @@ static bool parse_while(parser_t *parser, ast_block *block, ast_expression **out
         return false;
     }
 
-    aloop = ast_loop_new(ctx, NULL, cond, NULL, NULL, ontrue);
+    cond = process_condition(parser, cond, &ifnot);
+    if (!cond) {
+        ast_delete(ontrue);
+        return false;
+    }
+    aloop = ast_loop_new(ctx, NULL, cond, ifnot, NULL, false, NULL, ontrue);
     *out = (ast_expression*)aloop;
     return true;
 }
@@ -2023,6 +2084,8 @@ static bool parse_dowhile(parser_t *parser, ast_block *block, ast_expression **o
     ast_loop *aloop;
     ast_expression *cond, *ontrue;
 
+    bool ifnot = false;
+
     lex_ctx ctx = parser_ctx(parser);
 
     (void)block; /* not touching */
@@ -2082,7 +2145,12 @@ static bool parse_dowhile(parser_t *parser, ast_block *block, ast_expression **o
         return false;
     }
 
-    aloop = ast_loop_new(ctx, NULL, NULL, cond, NULL, ontrue);
+    cond = process_condition(parser, cond, &ifnot);
+    if (!cond) {
+        ast_delete(ontrue);
+        return false;
+    }
+    aloop = ast_loop_new(ctx, NULL, NULL, false, cond, ifnot, NULL, ontrue);
     *out = (ast_expression*)aloop;
     return true;
 }
@@ -2092,7 +2160,9 @@ static bool parse_for(parser_t *parser, ast_block *block, ast_expression **out)
     ast_loop       *aloop;
     ast_expression *initexpr, *cond, *increment, *ontrue;
     ast_value      *typevar;
-    bool   retval = true;
+
+    bool retval = true;
+    bool ifnot  = false;
 
     lex_ctx ctx = parser_ctx(parser);
 
@@ -2185,7 +2255,12 @@ static bool parse_for(parser_t *parser, ast_block *block, ast_expression **out)
     if (!parse_statement_or_block(parser, &ontrue))
         goto onerr;
 
-    aloop = ast_loop_new(ctx, initexpr, cond, NULL, increment, ontrue);
+    if (cond) {
+        cond = process_condition(parser, cond, &ifnot);
+        if (!cond)
+            goto onerr;
+    }
+    aloop = ast_loop_new(ctx, initexpr, cond, ifnot, NULL, false, increment, ontrue);
     *out = (ast_expression*)aloop;
 
     if (!parser_leaveblock(parser))