]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
Merge branch 'master' of github.com:graphitemaster/gmqcc
authorDale Weiler <killfieldengine@gmail.com>
Sun, 23 Dec 2012 06:06:57 +0000 (06:06 +0000)
committerDale Weiler <killfieldengine@gmail.com>
Sun, 23 Dec 2012 06:06:57 +0000 (06:06 +0000)
29 files changed:
Makefile
ast.c
doc/gmqcc.1
exec.c
lexer.c
lexer.h
main.c
opts.c
opts.def
parser.c
tests/correct-logic-1-s.tmpl [new file with mode: 0644]
tests/correct-logic-1.tmpl [new file with mode: 0644]
tests/correct-logic-2-s.tmpl [new file with mode: 0644]
tests/correct-logic-2.tmpl [new file with mode: 0644]
tests/correct-logic.qc [new file with mode: 0644]
tests/correct-vs-short-1.tmpl [new file with mode: 0644]
tests/correct-vs-short-2.tmpl [new file with mode: 0644]
tests/correct-vs-short-3.tmpl [new file with mode: 0644]
tests/correct-vs-short.qc [new file with mode: 0644]
tests/noreturn.qc
tests/noreturn1.tmpl
tests/noreturn2.tmpl
tests/truth-flags-1-s.tmpl [new file with mode: 0644]
tests/truth-flags-1.tmpl [new file with mode: 0644]
tests/truth-flags-2-s.tmpl [new file with mode: 0644]
tests/truth-flags-2.qc [new file with mode: 0644]
tests/truth-flags-2.tmpl [new file with mode: 0644]
tests/truth-flags-3-s.tmpl [new file with mode: 0644]
tests/truth-flags-3.tmpl [new file with mode: 0644]

index 94b25e377ad4afdca79c5cfab92c249fe107aa68..b6ea92b7338508acbcdc37873f65f3b222f5ab7e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -89,6 +89,7 @@ clean:
 $(OBJ_D) $(OBJ_C) $(OBJ_X): gmqcc.h opts.def
 main.o:   lexer.h
 parser.o: ast.h lexer.h
+lexer.o:  lexer.h
 ast.o:    ast.h ir.h
 ir.o:     ir.h
 
diff --git a/ast.c b/ast.c
index e544e48a24984edd9e6176bec0afe3297d84a324..5dc131ea38bc617289aac9a5dae09d91985502d0 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -1699,7 +1699,7 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
         return true;
     }
 
-    if (OPTS_FLAG(SHORT_LOGIC) &&
+    if ((OPTS_FLAG(SHORT_LOGIC) || OPTS_FLAG(PERL_LOGIC)) &&
         (self->op == INSTR_AND || self->op == INSTR_OR))
     {
         /* short circuit evaluation */
@@ -1707,64 +1707,42 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
         ir_block *from_left, *from_right;
         ir_instr *phi;
         size_t    merge_id;
-        uint16_t  notop;
-
-        /* Note about casting to true boolean values:
-         * We use a single NOT for sub expressions, and an
-         * overall NOT at the end, and for that purpose swap
-         * all the jump conditions in order for the NOT to get
-         * doubled.
-         * ie: (a && b) usually becomes (!!a ? !!b : !!a)
-         * but we translate this to (!(!a ? !a : !b))
-         */
 
+        /* prepare end-block */
         merge_id = vec_size(func->ir_func->blocks);
-        merge = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "sce_merge"));
+        merge    = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "sce_merge"));
 
+        /* generate the left expression */
         cgen = self->left->expression.codegen;
         if (!(*cgen)((ast_expression*)(self->left), func, false, &left))
             return false;
-        if (!OPTS_FLAG(PERL_LOGIC)) {
-            notop = type_not_instr[left->vtype];
-            if (notop == AINSTR_END) {
-                compile_error(ast_ctx(self), "don't know how to cast to bool...");
-                return false;
-            }
-            left = ir_block_create_unary(func->curblock, ast_ctx(self),
-                                         ast_function_label(func, "sce_not"),
-                                         notop,
-                                         left);
-        }
+        /* remember the block */
         from_left = func->curblock;
 
+        /* create a new block for the right expression */
         other = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "sce_other"));
-        if ( !(self->op == INSTR_OR) != !OPTS_FLAG(PERL_LOGIC) ) {
+        if (self->op == INSTR_AND) {
+            /* on AND: left==true -> other */
             if (!ir_block_create_if(func->curblock, ast_ctx(self), left, other, merge))
                 return false;
         } else {
+            /* on OR: left==false -> other */
             if (!ir_block_create_if(func->curblock, ast_ctx(self), left, merge, other))
                 return false;
         }
         /* use the likely flag */
         vec_last(func->curblock->instr)->likely = true;
 
+        /* enter the right-expression's block */
         func->curblock = other;
+        /* generate */
         cgen = self->right->expression.codegen;
         if (!(*cgen)((ast_expression*)(self->right), func, false, &right))
             return false;
-        if (!OPTS_FLAG(PERL_LOGIC)) {
-            notop = type_not_instr[right->vtype];
-            if (notop == AINSTR_END) {
-                compile_error(ast_ctx(self), "don't know how to cast to bool...");
-                return false;
-            }
-            right = ir_block_create_unary(func->curblock, ast_ctx(self),
-                                          ast_function_label(func, "sce_not"),
-                                          notop,
-                                          right);
-        }
+        /* remember block */
         from_right = func->curblock;
 
+        /* jump to the merge block */
         if (!ir_block_create_jump(func->curblock, ast_ctx(self), merge))
             return false;
 
@@ -1772,23 +1750,50 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
         vec_push(func->ir_func->blocks, merge);
 
         func->curblock = merge;
-        phi = ir_block_create_phi(func->curblock, ast_ctx(self), ast_function_label(func, "sce_value"), TYPE_FLOAT);
+        phi = ir_block_create_phi(func->curblock, ast_ctx(self),
+                                  ast_function_label(func, "sce_value"),
+                                  self->expression.vtype);
         ir_phi_add(phi, from_left, left);
         ir_phi_add(phi, from_right, right);
         *out = ir_phi_value(phi);
+        if (!*out)
+            return false;
+
         if (!OPTS_FLAG(PERL_LOGIC)) {
-            notop = type_not_instr[(*out)->vtype];
-            if (notop == AINSTR_END) {
-                compile_error(ast_ctx(self), "don't know how to cast to bool...");
-                return false;
+            /* cast-to-bool */
+            if (OPTS_FLAG(CORRECT_LOGIC) && (*out)->vtype == TYPE_VECTOR) {
+                *out = ir_block_create_unary(func->curblock, ast_ctx(self),
+                                             ast_function_label(func, "sce_bool_v"),
+                                             INSTR_NOT_V, *out);
+                if (!*out)
+                    return false;
+                *out = ir_block_create_unary(func->curblock, ast_ctx(self),
+                                             ast_function_label(func, "sce_bool"),
+                                             INSTR_NOT_F, *out);
+                if (!*out)
+                    return false;
+            }
+            else if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && (*out)->vtype == TYPE_STRING) {
+                *out = ir_block_create_unary(func->curblock, ast_ctx(self),
+                                             ast_function_label(func, "sce_bool_s"),
+                                             INSTR_NOT_S, *out);
+                if (!*out)
+                    return false;
+                *out = ir_block_create_unary(func->curblock, ast_ctx(self),
+                                             ast_function_label(func, "sce_bool"),
+                                             INSTR_NOT_F, *out);
+                if (!*out)
+                    return false;
+            }
+            else {
+                *out = ir_block_create_binop(func->curblock, ast_ctx(self),
+                                             ast_function_label(func, "sce_bool"),
+                                             INSTR_AND, *out, *out);
+                if (!*out)
+                    return false;
             }
-            *out = ir_block_create_unary(func->curblock, ast_ctx(self),
-                                         ast_function_label(func, "sce_final_not"),
-                                         notop,
-                                         *out);
         }
-        if (!*out)
-            return false;
+
         self->expression.outr = *out;
         return true;
     }
index 89605fe233a1a6d2f2e12026c12015c99ca54ea3..8ccc6e08203b825f8177d9269e7cbf252317b5d2 100644 (file)
@@ -116,7 +116,7 @@ them.
 -f\fIno-\fRcorrect-ternary
 .fi
 .in
-.SH Warnings
+.SH COMPILE WARNINGS
 .TP
 .B -Wunused-variable
 Generate a warning about variables which are declared but never used.
@@ -238,7 +238,11 @@ or code after a call to a function marked as 'noreturn'.
 .B -Wdebug
 Enable some warnings added in order to help debugging in the compiler.
 You won't need this.
-.SH Compile Flags
+.B -Wunknown-attribute
+Warn on an unknown attribute. The warning will inlclude only the first
+token inside the enclosing attribute-brackets. This may change when
+the actual attribute syntax is better defined.
+.SH COMPILE FLAGS
 .TP
 .B -foverlap-locals
 Allow local variables to overlap with each other if they don't
@@ -305,9 +309,9 @@ prevents components from being listed.
 .TP
 .B -fcorrect-logic
 Most QC compilers translate if(a_vector) directly as an IF on the
-vector, which means only the x-component is checked. This causes all
-non-float types to use an appropriate NOT instruction on all logic
-operations and invert their use.
+vector, which means only the x-component is checked. This causes
+vectors to be cast to actual booleans via a NOT_V and, if necessary, a
+NOT_F chained to it.
 .in +4
 .nf
 if (a_vector) // becomes
diff --git a/exec.c b/exec.c
index 0b9b3621f308536e4e9b58e1e48098577f943c67..c1aa695f23c43f67813f69e775d51e9e69a14e6a 100644 (file)
--- a/exec.c
+++ b/exec.c
@@ -977,6 +977,17 @@ int main(int argc, char **argv)
         printf("Program's system-checksum = 0x%04x\n", (unsigned int)prog->crc16);
         printf("Entity field space: %u\n", (unsigned int)prog->entityfields);
         printf("Globals: %u\n", (unsigned int)vec_size(prog->globals));
+        printf("Counts:\n"
+               "      code: %lu\n"
+               "      defs: %lu\n"
+               "    fields: %lu\n"
+               " functions: %lu\n"
+               "   strings: %lu\n",
+               (unsigned long)vec_size(prog->code),
+               (unsigned long)vec_size(prog->defs),
+               (unsigned long)vec_size(prog->fields),
+               (unsigned long)vec_size(prog->functions),
+               (unsigned long)vec_size(prog->strings));
     }
 
     if (opts_info) {
diff --git a/lexer.c b/lexer.c
index cf554fb2d41fb2512766f647a2c9810f76373f67..e506aec31ef8c105f7c3ef5de7a74eefd560d809 100644 (file)
--- a/lexer.c
+++ b/lexer.c
@@ -50,8 +50,6 @@ static const char *keywords_fg[] = {
     "typedef",
     "goto",
 
-    "noreturn",
-
     "__builtin_debug_printtype"
 };
 static size_t num_keywords_fg = sizeof(keywords_fg) / sizeof(keywords_fg[0]);
@@ -1117,6 +1115,15 @@ int lex_do(lex_file *lex)
     switch (ch)
     {
         case '[':
+            nextch = lex_getch(lex);
+            if (nextch == '[') {
+                lex_tokench(lex, ch);
+                lex_tokench(lex, nextch);
+                lex_endtoken(lex);
+                return (lex->tok.ttype = TOKEN_ATTRIBUTE_OPEN);
+            }
+            lex_ungetch(lex, nextch);
+            /* FALL THROUGH */
         case '(':
         case ':':
         case '?':
@@ -1126,11 +1133,23 @@ int lex_do(lex_file *lex)
                 return (lex->tok.ttype = ch);
             else
                 return (lex->tok.ttype = TOKEN_OPERATOR);
+
+        case ']':
+            if (lex->flags.noops) {
+                nextch = lex_getch(lex);
+                if (nextch == ']') {
+                    lex_tokench(lex, ch);
+                    lex_tokench(lex, nextch);
+                    lex_endtoken(lex);
+                    return (lex->tok.ttype = TOKEN_ATTRIBUTE_CLOSE);
+                }
+                lex_ungetch(lex, nextch);
+            }
+            /* FALL THROUGH */
         case ')':
         case ';':
         case '{':
         case '}':
-        case ']':
 
         case '#':
             lex_tokench(lex, ch);
diff --git a/lexer.h b/lexer.h
index e419794eda9f867e150e9f26064cd3ef849c9ec6..e5493734881d6240d3796b4b7a5f41332b46a79d 100644 (file)
--- a/lexer.h
+++ b/lexer.h
@@ -73,6 +73,9 @@ enum {
 
     TOKEN_DOTS, /* 3 dots, ... */
 
+    TOKEN_ATTRIBUTE_OPEN,  /* [[ */
+    TOKEN_ATTRIBUTE_CLOSE, /* ]] */
+
     TOKEN_STRINGCONST, /* not the typename but an actual "string" */
     TOKEN_CHARCONST,
     TOKEN_VECTORCONST,
diff --git a/main.c b/main.c
index d732ef9bd0d1c8175cd750ac0ca10a7839a6b622..107098a6e582acf312b9663b2511ec651c2500aa 100644 (file)
--- a/main.c
+++ b/main.c
@@ -508,6 +508,11 @@ int main(int argc, char **argv) {
         return usage();
     }
 
+    if (OPTS_FLAG(TRUE_EMPTY_STRINGS) && OPTS_FLAG(FALSE_EMPTY_STRINGS)) {
+        con_err("-ftrue-empty-strings and -ffalse-empty-strings are mutually exclusive");
+        exit(1);
+    }
+
     /* the standard decides which set of operators to use */
     if (opts.standard == COMPILER_GMQCC) {
         operators      = c_operators;
diff --git a/opts.c b/opts.c
index 69e93b428fdcdb84689a3c3ddb3a817c2589b75c..5c48286d2d9a7557fc7528efdacf678ffa082a1a 100644 (file)
--- a/opts.c
+++ b/opts.c
@@ -53,6 +53,7 @@ static void opts_setdefault() {
     opts_set(opts.warn,  WARN_UNKNOWN_PRAGMAS,           true);
     opts_set(opts.warn,  WARN_UNREACHABLE_CODE,          true);
     opts_set(opts.warn,  WARN_CPP,                       true);
+    opts_set(opts.warn,  WARN_UNKNOWN_ATTRIBUTE,         true);
     /* flags */
     opts_set(opts.flags, ADJUST_VECTOR_FIELDS,           true);
     opts_set(opts.flags, FTEPP,                          false);
index 9e53ff54ee55f380334a2ceb7ea78ed185f57ef4..697afdc1a15a4a49106318f52bc25137cd6b6b5a 100644 (file)
--- a/opts.def
+++ b/opts.def
@@ -73,6 +73,7 @@
     GMQCC_DEFINE_FLAG(UNKNOWN_PRAGMAS)
     GMQCC_DEFINE_FLAG(UNREACHABLE_CODE)
     GMQCC_DEFINE_FLAG(CPP)
+    GMQCC_DEFINE_FLAG(UNKNOWN_ATTRIBUTE)
 #endif
 
 #ifdef GMQCC_TYPE_OPTIMIZATIONS
index d64741543f25c6133d0f18c49c50b3b3b40c4986..16d783a9c9d2545d00b8494fddb940d47bbfccad 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -890,23 +890,27 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
                     parseerror(parser, "invalid types for logical operation with -fperl-logic: %s and %s", ty1, ty2);
                     return false;
                 }
-                if (OPTS_FLAG(CORRECT_LOGIC)) {
-                    /* non-floats need to be NOTed */
-                    for (i = 0; i < 2; ++i) {
-                        if (exprs[i]->expression.vtype != TYPE_FLOAT) {
-                            if (type_not_instr[exprs[i]->expression.vtype] == AINSTR_END) {
-                                ast_type_to_string(exprs[0], ty1, sizeof(ty1));
-                                ast_type_to_string(exprs[1], ty2, sizeof(ty2));
-                                parseerror(parser, "invalid types for logical operation with -fcorrect-logic: %s and %s", ty1, ty2);
-                                return false;
-                            }
-                            out = (ast_expression*)ast_unary_new(ctx, type_not_instr[exprs[i]->expression.vtype], exprs[i]);
-                            if (!out) break;
-                            out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, out);
-                            if (!out) break;
-                            exprs[i] = out; out = NULL;
-                            if (OPTS_FLAG(PERL_LOGIC)) {
-                            }
+                for (i = 0; i < 2; ++i) {
+                    if (OPTS_FLAG(CORRECT_LOGIC) && exprs[i]->expression.vtype == TYPE_VECTOR) {
+                        out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_V, exprs[i]);
+                        if (!out) break;
+                        out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, out);
+                        if (!out) break;
+                        exprs[i] = out; out = NULL;
+                        if (OPTS_FLAG(PERL_LOGIC)) {
+                            /* here we want to keep the right expressions' type */
+                            break;
+                        }
+                    }
+                    else if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && exprs[i]->expression.vtype == TYPE_STRING) {
+                        out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_S, exprs[i]);
+                        if (!out) break;
+                        out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, out);
+                        if (!out) break;
+                        exprs[i] = out; out = NULL;
+                        if (OPTS_FLAG(PERL_LOGIC)) {
+                            /* here we want to keep the right expressions' type */
+                            break;
                         }
                     }
                 }
@@ -1899,7 +1903,8 @@ static ast_expression* process_condition(parser_t *parser, ast_expression *cond,
     ast_unary *unary;
     ast_expression *prev;
 
-    if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && cond->expression.vtype == TYPE_STRING) {
+    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) {
@@ -1909,22 +1914,15 @@ static ast_expression* process_condition(parser_t *parser, ast_expression *cond,
         }
         ifnot = !ifnot;
     }
-    if (OPTS_FLAG(CORRECT_LOGIC) &&
-        !(cond->expression.vtype == TYPE_STRING && OPTS_FLAG(TRUE_EMPTY_STRINGS)))
+    else if (OPTS_FLAG(CORRECT_LOGIC) && cond->expression.vtype == TYPE_VECTOR)
     {
-        /* non-floats need to use NOT; except for strings on -ftrue-empty-strings */
-        unary = (ast_unary*)cond;
-        if (!ast_istype(cond, ast_unary) || unary->op < INSTR_NOT_F || unary->op > INSTR_NOT_FNC)
+        /* vector types need to be cast to true booleans */
+        ast_binary *bin = (ast_binary*)cond;
+        if (!OPTS_FLAG(PERL_LOGIC) || !ast_istype(cond, ast_binary) || !(bin->op == INSTR_AND || bin->op == INSTR_OR))
         {
-            /* use the right NOT_ */
+            /* in perl-logic, AND and OR take care of the -fcorrect-logic */
             prev = cond;
-            cond = (ast_expression*)ast_unary_new(ast_ctx(cond), type_not_instr[cond->expression.vtype], cond);
-
-            /*
-             * cppcheck: it thinks there is a possible null pointer dereference
-             * otherwise it would be "redundant" to check it ast_unary_new returned
-             * null, it's wrong.
-             */   
+            cond = (ast_expression*)ast_unary_new(ast_ctx(cond), INSTR_NOT_V, cond);
             if (!cond) {
                 ast_unref(prev);
                 parseerror(parser, "internal error: failed to process condition");
@@ -1936,7 +1934,6 @@ static ast_expression* process_condition(parser_t *parser, ast_expression *cond,
 
     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;
@@ -2352,9 +2349,48 @@ static bool parse_var_qualifiers(parser_t *parser, bool with_local, int *cvq, bo
     bool had_var   = false;
     bool had_noref = false;
     bool had_noreturn = false;
+    bool had_attrib = false;
 
+    *cvq = CV_NONE;
     for (;;) {
-        if (!strcmp(parser_tokval(parser), "const"))
+        if (parser->tok == TOKEN_ATTRIBUTE_OPEN) {
+            had_attrib = true;
+            /* parse an attribute */
+            if (!parser_next(parser)) {
+                parseerror(parser, "expected attribute after `[[`");
+                *cvq = CV_WRONG;
+                return false;
+            }
+            if (!strcmp(parser_tokval(parser), "noreturn")) {
+                had_noreturn = true;
+                if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
+                    parseerror(parser, "`noreturn` attribute has no parameters, expected `]]`");
+                    *cvq = CV_WRONG;
+                    return false;
+                }
+            }
+            else if (!strcmp(parser_tokval(parser), "noref")) {
+                had_noref = true;
+                if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
+                    parseerror(parser, "`noref` attribute has no parameters, expected `]]`");
+                    *cvq = CV_WRONG;
+                    return false;
+                }
+            }
+            else
+            {
+                /* Skip tokens until we hit a ]] */
+                (void)!parsewarning(parser, WARN_UNKNOWN_ATTRIBUTE, "unknown attribute starting with `%s`", parser_tokval(parser));
+                while (parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
+                    if (!parser_next(parser)) {
+                        parseerror(parser, "error inside attribute");
+                        *cvq = CV_WRONG;
+                        return false;
+                    }
+                }
+            }
+        }
+        else if (!strcmp(parser_tokval(parser), "const"))
             had_const = true;
         else if (!strcmp(parser_tokval(parser), "var"))
             had_var = true;
@@ -2362,9 +2398,7 @@ static bool parse_var_qualifiers(parser_t *parser, bool with_local, int *cvq, bo
             had_var = true;
         else if (!strcmp(parser_tokval(parser), "noref"))
             had_noref = true;
-        else if (!strcmp(parser_tokval(parser), "noreturn"))
-            had_noreturn = true;
-        else if (!had_const && !had_var && !had_noref && !had_noreturn) {
+        else if (!had_const && !had_var && !had_noref && !had_noreturn && !had_attrib) {
             return false;
         }
         else
diff --git a/tests/correct-logic-1-s.tmpl b/tests/correct-logic-1-s.tmpl
new file mode 100644 (file)
index 0000000..e3f3451
--- /dev/null
@@ -0,0 +1,12 @@
+I: correct-logic.qc
+D: vector logic flags
+T: -execute
+C: -std=fteqcc -fshort-logic
+M:          ! & | i N
+M: 0, 0 -> 1 0 0 0 1
+M: 0, x -> 1 0 1 0 1
+M: x, 0 -> 0 0 1 1 0
+M: x, x -> 0 1 1 1 0
+M: 0, y -> 1 0 0 0 1
+M: y, 0 -> 0 0 0 0 1
+M: y, y -> 0 0 0 0 1
diff --git a/tests/correct-logic-1.tmpl b/tests/correct-logic-1.tmpl
new file mode 100644 (file)
index 0000000..b151f46
--- /dev/null
@@ -0,0 +1,12 @@
+I: correct-logic.qc
+D: vector logic flags
+T: -execute
+C: -std=fteqcc
+M:          ! & | i N
+M: 0, 0 -> 1 0 0 0 1
+M: 0, x -> 1 0 1 0 1
+M: x, 0 -> 0 0 1 1 0
+M: x, x -> 0 1 1 1 0
+M: 0, y -> 1 0 0 0 1
+M: y, 0 -> 0 0 0 0 1
+M: y, y -> 0 0 0 0 1
diff --git a/tests/correct-logic-2-s.tmpl b/tests/correct-logic-2-s.tmpl
new file mode 100644 (file)
index 0000000..a7ada6e
--- /dev/null
@@ -0,0 +1,12 @@
+I: correct-logic.qc
+D: vector logic flags
+T: -execute
+C: -std=fteqcc -fcorrect-logic -fshort-logic
+M:          ! & | i N
+M: 0, 0 -> 1 0 0 0 1
+M: 0, x -> 1 0 1 0 1
+M: x, 0 -> 0 0 1 1 0
+M: x, x -> 0 1 1 1 0
+M: 0, y -> 1 0 1 0 1
+M: y, 0 -> 0 0 1 1 0
+M: y, y -> 0 1 1 1 0
diff --git a/tests/correct-logic-2.tmpl b/tests/correct-logic-2.tmpl
new file mode 100644 (file)
index 0000000..7ecd3df
--- /dev/null
@@ -0,0 +1,12 @@
+I: correct-logic.qc
+D: vector logic flags
+T: -execute
+C: -std=fteqcc -fcorrect-logic
+M:          ! & | i N
+M: 0, 0 -> 1 0 0 0 1
+M: 0, x -> 1 0 1 0 1
+M: x, 0 -> 0 0 1 1 0
+M: x, x -> 0 1 1 1 0
+M: 0, y -> 1 0 1 0 1
+M: y, 0 -> 0 0 1 1 0
+M: y, y -> 0 1 1 1 0
diff --git a/tests/correct-logic.qc b/tests/correct-logic.qc
new file mode 100644 (file)
index 0000000..cb9a38d
--- /dev/null
@@ -0,0 +1,27 @@
+void   print(...)   = #1;
+string ftos (float) = #2;
+
+float test_s_not  (vector s)           { return !s; }
+float test_s_and  (vector s, vector t) { return s && t; }
+float test_s_or   (vector s, vector t) { return s || t; }
+float test_s_if   (vector s)           { if (s) return 1; return 0; }
+float test_s_ifnot(vector s)           { if not (s) return 1; return 0; }
+
+void test(vector s, vector t) {
+    print(ftos(!!test_s_not  (s)), " ");
+    print(ftos(!!test_s_and  (s, t)), " ");
+    print(ftos(!!test_s_or   (s, t)), " ");
+    print(ftos(!!test_s_if   (s)), " ");
+    print(ftos(!!test_s_ifnot(s)), "\n");
+}
+
+void main() {
+    print("        ! & | i N\n");
+    print("0, 0 -> "); test('0 0 0', '0 0 0');
+    print("0, x -> "); test('0 0 0', '1 0 0');
+    print("x, 0 -> "); test('1 0 0', '0 0 0');
+    print("x, x -> "); test('1 0 0', '1 0 0');
+    print("0, y -> "); test('0 0 0', '0 1 0');
+    print("y, 0 -> "); test('0 1 0', '0 0 0');
+    print("y, y -> "); test('0 1 0', '0 1 0');
+}
diff --git a/tests/correct-vs-short-1.tmpl b/tests/correct-vs-short-1.tmpl
new file mode 100644 (file)
index 0000000..9a2ac9b
--- /dev/null
@@ -0,0 +1,14 @@
+I: correct-vs-short.qc
+D: correct-logic vs short-logic without perl-logic
+T: -execute
+C: -std=fteqcc
+M: X               & | B
+M: 0 0 0, 0 0 0 :: 0 0 0
+M: 0 0 0, 5 0 0 :: 0 2 1
+M: 5 0 0, 0 0 0 :: 0 2 1
+M: 5 0 0, 5 0 0 :: 2 2 2
+M: Y               & | B
+M: 0 0 0, 0 0 0 :: 0 0 0
+M: 0 0 0, 0 5 0 :: 0 0 0
+M: 0 5 0, 0 0 0 :: 0 0 0
+M: 0 5 0, 0 5 0 :: 0 0 0
diff --git a/tests/correct-vs-short-2.tmpl b/tests/correct-vs-short-2.tmpl
new file mode 100644 (file)
index 0000000..09897e5
--- /dev/null
@@ -0,0 +1,14 @@
+I: correct-vs-short.qc
+D: correct-logic vs short-logic without perl-logic
+T: -execute
+C: -std=fteqcc -fcorrect-logic
+M: X               & | B
+M: 0 0 0, 0 0 0 :: 0 0 0
+M: 0 0 0, 5 0 0 :: 0 2 1
+M: 5 0 0, 0 0 0 :: 0 2 1
+M: 5 0 0, 5 0 0 :: 2 2 2
+M: Y               & | B
+M: 0 0 0, 0 0 0 :: 0 0 0
+M: 0 0 0, 0 5 0 :: 0 2 1
+M: 0 5 0, 0 0 0 :: 0 2 1
+M: 0 5 0, 0 5 0 :: 2 2 2
diff --git a/tests/correct-vs-short-3.tmpl b/tests/correct-vs-short-3.tmpl
new file mode 100644 (file)
index 0000000..787ae22
--- /dev/null
@@ -0,0 +1,14 @@
+I: correct-vs-short.qc
+D: correct-logic vs short-logic without perl-logic
+T: -execute
+C: -std=fteqcc -fcorrect-logic -fshort-logic
+M: X               & | B
+M: 0 0 0, 0 0 0 :: 0 0 0
+M: 0 0 0, 5 0 0 :: 0 2 1
+M: 5 0 0, 0 0 0 :: 0 2 1
+M: 5 0 0, 5 0 0 :: 2 2 2
+M: Y               & | B
+M: 0 0 0, 0 0 0 :: 0 0 0
+M: 0 0 0, 0 5 0 :: 0 2 1
+M: 0 5 0, 0 0 0 :: 0 2 1
+M: 0 5 0, 0 5 0 :: 2 2 2
diff --git a/tests/correct-vs-short.qc b/tests/correct-vs-short.qc
new file mode 100644 (file)
index 0000000..81f9b7a
--- /dev/null
@@ -0,0 +1,21 @@
+void   print(...)   = #1;
+string ftos (float) = #2;
+
+void test(vector a, vector b) {
+    print(ftos((a && b) + (a && b)), " ");
+    print(ftos((a || b) + (a || b)), " ");
+    print(ftos((a && b) + (a || b)), "\n");
+}
+
+void main() {
+    print("X               & | B\n");
+    print("0 0 0, 0 0 0 :: "); test('0 0 0', '0 0 0');
+    print("0 0 0, 5 0 0 :: "); test('0 0 0', '5 0 0');
+    print("5 0 0, 0 0 0 :: "); test('5 0 0', '0 0 0');
+    print("5 0 0, 5 0 0 :: "); test('5 0 0', '5 0 0');
+    print("Y               & | B\n");
+    print("0 0 0, 0 0 0 :: "); test('0 0 0', '0 0 0');
+    print("0 0 0, 0 5 0 :: "); test('0 0 0', '0 5 0');
+    print("0 5 0, 0 0 0 :: "); test('0 5 0', '0 0 0');
+    print("0 5 0, 0 5 0 :: "); test('0 5 0', '0 5 0');
+}
index 1437b0611ec4f3d2b435091d29d17f358fd87d7f..e56cc8810059c346211642e1653a6f98332cb389 100644 (file)
@@ -1,5 +1,5 @@
 #ifndef NORETURN
-#define NORETURN noreturn
+#define NORETURN [[noreturn]]
 #endif
 
 void          print(...)  = #1;
index db507dd86f069fbb7d6eca6695f45868174538a4..0f6aad138a292c0c283a489a09367a10b38d3546 100644 (file)
@@ -1,4 +1,4 @@
 I: noreturn.qc
 D: noreturn keyword - should work
 T: -compile
-C: -std=fteqcc -Wall -Werror -DTEST=1 -DNORETURN=noreturn
+C: -std=fteqcc -Wall -Werror -DTEST=1 -DNORETURN=[[noreturn]]
index d5d73c2dd8e8dc73e3e062f764bb1a8e66bdd738..8d7ad09c55f572f8c7a1808e80ad227fbfbfbfda 100644 (file)
@@ -1,4 +1,4 @@
 I: noreturn.qc
 D: noreturn keyword - should fail
 T: -compile
-C: -std=fteqcc -Wall -Werror -DTEST=2 -DNORETURN=noreturn
+C: -std=fteqcc -Wall -Werror -DTEST=2 -DNORETURN=[[noreturn]]
diff --git a/tests/truth-flags-1-s.tmpl b/tests/truth-flags-1-s.tmpl
new file mode 100644 (file)
index 0000000..770f306
--- /dev/null
@@ -0,0 +1,14 @@
+I: truth-flags-2.qc
+D: logic flags
+T: -execute
+C: -std=fteqcc -fshort-logic
+M:                  ! & | i N
+M: 'str', 'str' -> 0 1 1 1 0
+M: 'str', ''    -> 0 1 1 1 0
+M: 'str', 0     -> 0 0 1 1 0
+M: '',    'str' -> 1 1 1 1 0
+M: '',    ''    -> 1 1 1 1 0
+M: '',    0     -> 1 0 1 1 0
+M: 0,     'str' -> 1 0 1 0 1
+M: 0,     ''    -> 1 0 1 0 1
+M: 0,     0     -> 1 0 0 0 1
diff --git a/tests/truth-flags-1.tmpl b/tests/truth-flags-1.tmpl
new file mode 100644 (file)
index 0000000..7562374
--- /dev/null
@@ -0,0 +1,14 @@
+I: truth-flags-2.qc
+D: logic flags
+T: -execute
+C: -std=fteqcc
+M:                  ! & | i N
+M: 'str', 'str' -> 0 1 1 1 0
+M: 'str', ''    -> 0 1 1 1 0
+M: 'str', 0     -> 0 0 1 1 0
+M: '',    'str' -> 1 1 1 1 0
+M: '',    ''    -> 1 1 1 1 0
+M: '',    0     -> 1 0 1 1 0
+M: 0,     'str' -> 1 0 1 0 1
+M: 0,     ''    -> 1 0 1 0 1
+M: 0,     0     -> 1 0 0 0 1
diff --git a/tests/truth-flags-2-s.tmpl b/tests/truth-flags-2-s.tmpl
new file mode 100644 (file)
index 0000000..3de75eb
--- /dev/null
@@ -0,0 +1,14 @@
+I: truth-flags-2.qc
+D: logic flags
+T: -execute
+C: -std=fteqcc -fshort-logic -ftrue-empty-strings
+M:                  ! & | i N
+M: 'str', 'str' -> 0 1 1 1 0
+M: 'str', ''    -> 0 1 1 1 0
+M: 'str', 0     -> 0 0 1 1 0
+M: '',    'str' -> 0 1 1 1 0
+M: '',    ''    -> 0 1 1 1 0
+M: '',    0     -> 0 0 1 1 0
+M: 0,     'str' -> 1 0 1 0 1
+M: 0,     ''    -> 1 0 1 0 1
+M: 0,     0     -> 1 0 0 0 1
diff --git a/tests/truth-flags-2.qc b/tests/truth-flags-2.qc
new file mode 100644 (file)
index 0000000..0c10708
--- /dev/null
@@ -0,0 +1,30 @@
+void   print(...)   = #1;
+string ftos (float) = #2;
+
+float test_s_not  (string s)           { return !s; }
+float test_s_and  (string s, string t) { return s && t; }
+float test_s_or   (string s, string t) { return s || t; }
+float test_s_if   (string s)           { if (s) return 1; return 0; }
+float test_s_ifnot(string s)           { if not (s) return 1; return 0; }
+
+void test(string s, string t) {
+    print(ftos(!!test_s_not  (s)), " ");
+    print(ftos(!!test_s_and  (s, t)), " ");
+    print(ftos(!!test_s_or   (s, t)), " ");
+    print(ftos(!!test_s_if   (s)), " ");
+    print(ftos(!!test_s_ifnot(s)), "\n");
+}
+
+string nuls;
+void main() {
+    print("                ! & | i N\n");
+    print("'str', 'str' -> "); test("FULL", "FULL");
+    print("'str', ''    -> "); test("FULL", ""    );
+    print("'str', 0     -> "); test("FULL", nuls  );
+    print("'',    'str' -> "); test("",     "FULL");
+    print("'',    ''    -> "); test("",     ""    );
+    print("'',    0     -> "); test("",     nuls  );
+    print("0,     'str' -> "); test(nuls,   "FULL");
+    print("0,     ''    -> "); test(nuls,   ""    );
+    print("0,     0     -> "); test(nuls,   nuls  );
+}
diff --git a/tests/truth-flags-2.tmpl b/tests/truth-flags-2.tmpl
new file mode 100644 (file)
index 0000000..d9bb543
--- /dev/null
@@ -0,0 +1,14 @@
+I: truth-flags-2.qc
+D: logic flags
+T: -execute
+C: -std=fteqcc -ftrue-empty-strings
+M:                  ! & | i N
+M: 'str', 'str' -> 0 1 1 1 0
+M: 'str', ''    -> 0 1 1 1 0
+M: 'str', 0     -> 0 0 1 1 0
+M: '',    'str' -> 0 1 1 1 0
+M: '',    ''    -> 0 1 1 1 0
+M: '',    0     -> 0 0 1 1 0
+M: 0,     'str' -> 1 0 1 0 1
+M: 0,     ''    -> 1 0 1 0 1
+M: 0,     0     -> 1 0 0 0 1
diff --git a/tests/truth-flags-3-s.tmpl b/tests/truth-flags-3-s.tmpl
new file mode 100644 (file)
index 0000000..1ebd56b
--- /dev/null
@@ -0,0 +1,14 @@
+I: truth-flags-2.qc
+D: logic flags
+T: -execute
+C: -std=fteqcc -fshort-logic -ffalse-empty-strings
+M:                  ! & | i N
+M: 'str', 'str' -> 0 1 1 1 0
+M: 'str', ''    -> 0 0 1 1 0
+M: 'str', 0     -> 0 0 1 1 0
+M: '',    'str' -> 1 0 1 0 1
+M: '',    ''    -> 1 0 0 0 1
+M: '',    0     -> 1 0 0 0 1
+M: 0,     'str' -> 1 0 1 0 1
+M: 0,     ''    -> 1 0 0 0 1
+M: 0,     0     -> 1 0 0 0 1
diff --git a/tests/truth-flags-3.tmpl b/tests/truth-flags-3.tmpl
new file mode 100644 (file)
index 0000000..f166dda
--- /dev/null
@@ -0,0 +1,14 @@
+I: truth-flags-2.qc
+D: logic flags
+T: -execute
+C: -std=fteqcc -ffalse-empty-strings
+M:                  ! & | i N
+M: 'str', 'str' -> 0 1 1 1 0
+M: 'str', ''    -> 0 0 1 1 0
+M: 'str', 0     -> 0 0 1 1 0
+M: '',    'str' -> 1 0 1 0 1
+M: '',    ''    -> 1 0 0 0 1
+M: '',    0     -> 1 0 0 0 1
+M: 0,     'str' -> 1 0 1 0 1
+M: 0,     ''    -> 1 0 0 0 1
+M: 0,     0     -> 1 0 0 0 1