]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - fold.c
&& and || op folding
[xonotic/gmqcc.git] / fold.c
diff --git a/fold.c b/fold.c
index 98e854ee3ceedd91c082a5d7e4dd496f97c378d4..403b6f51b6d2a180438f08d4e7138d55387c9379 100644 (file)
--- a/fold.c
+++ b/fold.c
@@ -113,7 +113,6 @@ static GMQCC_INLINE qcfloat_t vec3_mulvv(vec3_t a, vec3_t b) {
     return (a.x * b.x + a.y * b.y + a.z * b.z);
 }
 
-
 static GMQCC_INLINE vec3_t vec3_mulvf(vec3_t a, qcfloat_t b) {
     vec3_t out;
     out.x = a.x * b;
@@ -136,6 +135,10 @@ static GMQCC_INLINE vec3_t vec3_create(float x, float y, float z) {
     return out;
 }
 
+static GMQCC_INLINE bool vec3_pbool(vec3_t a) {
+    return (a.x && a.y && a.z);
+}
+
 
 static GMQCC_INLINE float fold_immvalue_float(ast_value *expr) {
     return expr->constval.vfloat;
@@ -357,6 +360,24 @@ static GMQCC_INLINE ast_expression *fold_op_mul(fold_t *fold, ast_value *a, ast_
     return NULL;
 }
 
+static GMQCC_INLINE bool fold_immediate_true(fold_t *fold, ast_value *v) {
+    switch (v->expression.vtype) {
+        case TYPE_FLOAT:   return !!v->constval.vfloat;
+        case TYPE_INTEGER: return !!v->constval.vint;
+        case TYPE_VECTOR:  return OPTS_FLAG(CORRECT_LOGIC) ? vec3_pbool(v->constval.vvec) : !!v->constval.vvec.x;
+        case TYPE_STRING:
+            if (!v->constval.vstring)
+                return false;
+            if (OPTS_FLAG(TRUE_EMPTY_STRINGS))
+                return true;
+            return !!v->constval.vstring[0];
+        default:
+            compile_error(fold_ctx(fold), "internal error: fold_immediate_true on invalid type");
+            break;
+    }
+    return !!v->constval.vfunc;
+}
+
 static GMQCC_INLINE ast_expression *fold_op_div(fold_t *fold, ast_value *a, ast_value *b) {
     if (isfloatonly(a)) {
         return (fold_possible(a) && fold_possible(b))
@@ -373,6 +394,21 @@ static GMQCC_INLINE ast_expression *fold_op_div(fold_t *fold, ast_value *a, ast_
     return NULL;
 }
 
+static GMQCC_INLINE ast_expression *fold_op_andor(fold_t *fold, ast_value *a, ast_value *b, bool isor) {
+    if (fold_possible(a) && fold_possible(b)) {
+        if (OPTS_FLAG(PERL_LOGIC)) {
+            if (fold_immediate_true(fold, b))
+                return (ast_expression*)b;
+        } else {
+            return ((isor) ? (fold_immediate_true(fold, a) || fold_immediate_true(fold, b))
+                           : (fold_immediate_true(fold, a) && fold_immediate_true(fold, b)))
+                                 ? (ast_expression*)fold->imm_float[1]  /* 1.0f */
+                                 : (ast_expression*)fold->imm_float[0]; /* 0.0f */
+        }
+    }
+    return NULL;
+}
+
 ast_expression *fold_op(fold_t *fold, const oper_info *info, ast_expression **opexprs) {
     ast_value *a = (ast_value*)opexprs[0];
     ast_value *b = (ast_value*)opexprs[1];
@@ -438,16 +474,10 @@ ast_expression *fold_op(fold_t *fold, const oper_info *info, ast_expression **op
             return isfloat(a)              ? fold_constgen_float (fold, ~(qcint_t)fold_immvalue_float(a))
                  : NULL;
 
-        case opid1('*'): return fold_op_mul(fold, a, b);
-        case opid1('/'): return fold_op_div(fold, a, b);
-            /* TODO: seperate function for this case */
-            return NULL;
-        case opid2('|','|'):
-            /* TODO: seperate function for this case */
-            return NULL;
-        case opid2('&','&'):
-            /* TODO: seperate function for this case */
-            return NULL;
+        case opid1('*'):     return fold_op_mul  (fold, a, b);
+        case opid1('/'):     return fold_op_div  (fold, a, b);
+        case opid2('|','|'): return fold_op_andor(fold, a, b, true);
+        case opid2('&','&'): return fold_op_andor(fold, a, b, false);
         case opid2('?',':'):
             /* TODO: seperate function for this case */
             return NULL;