mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2024-11-23 20:33:05 +00:00
Merge branch 'master' of github.com:graphitemaster/gmqcc
This commit is contained in:
commit
6bc29a1601
29 changed files with 430 additions and 94 deletions
1
Makefile
1
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
|
||||
|
||||
|
|
99
ast.c
99
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 (!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;
|
||||
}
|
||||
*out = ir_block_create_unary(func->curblock, ast_ctx(self),
|
||||
ast_function_label(func, "sce_final_not"),
|
||||
notop,
|
||||
*out);
|
||||
}
|
||||
if (!*out)
|
||||
return false;
|
||||
|
||||
if (!OPTS_FLAG(PERL_LOGIC)) {
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
self->expression.outr = *out;
|
||||
return true;
|
||||
}
|
||||
|
|
14
doc/gmqcc.1
14
doc/gmqcc.1
|
@ -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
|
||||
|
|
11
exec.c
11
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) {
|
||||
|
|
25
lexer.c
25
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);
|
||||
|
|
3
lexer.h
3
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,
|
||||
|
|
5
main.c
5
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;
|
||||
|
|
1
opts.c
1
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);
|
||||
|
|
1
opts.def
1
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
|
||||
|
|
106
parser.c
106
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
|
||||
|
|
12
tests/correct-logic-1-s.tmpl
Normal file
12
tests/correct-logic-1-s.tmpl
Normal file
|
@ -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
|
12
tests/correct-logic-1.tmpl
Normal file
12
tests/correct-logic-1.tmpl
Normal file
|
@ -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
|
12
tests/correct-logic-2-s.tmpl
Normal file
12
tests/correct-logic-2-s.tmpl
Normal file
|
@ -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
|
12
tests/correct-logic-2.tmpl
Normal file
12
tests/correct-logic-2.tmpl
Normal file
|
@ -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
|
27
tests/correct-logic.qc
Normal file
27
tests/correct-logic.qc
Normal file
|
@ -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');
|
||||
}
|
14
tests/correct-vs-short-1.tmpl
Normal file
14
tests/correct-vs-short-1.tmpl
Normal file
|
@ -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
|
14
tests/correct-vs-short-2.tmpl
Normal file
14
tests/correct-vs-short-2.tmpl
Normal file
|
@ -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
|
14
tests/correct-vs-short-3.tmpl
Normal file
14
tests/correct-vs-short-3.tmpl
Normal file
|
@ -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
|
21
tests/correct-vs-short.qc
Normal file
21
tests/correct-vs-short.qc
Normal file
|
@ -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');
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef NORETURN
|
||||
#define NORETURN noreturn
|
||||
#define NORETURN [[noreturn]]
|
||||
#endif
|
||||
|
||||
void print(...) = #1;
|
||||
|
|
|
@ -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]]
|
||||
|
|
|
@ -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]]
|
||||
|
|
14
tests/truth-flags-1-s.tmpl
Normal file
14
tests/truth-flags-1-s.tmpl
Normal file
|
@ -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
|
14
tests/truth-flags-1.tmpl
Normal file
14
tests/truth-flags-1.tmpl
Normal file
|
@ -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
|
14
tests/truth-flags-2-s.tmpl
Normal file
14
tests/truth-flags-2-s.tmpl
Normal file
|
@ -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
|
30
tests/truth-flags-2.qc
Normal file
30
tests/truth-flags-2.qc
Normal file
|
@ -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 );
|
||||
}
|
14
tests/truth-flags-2.tmpl
Normal file
14
tests/truth-flags-2.tmpl
Normal file
|
@ -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
|
14
tests/truth-flags-3-s.tmpl
Normal file
14
tests/truth-flags-3-s.tmpl
Normal file
|
@ -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
|
14
tests/truth-flags-3.tmpl
Normal file
14
tests/truth-flags-3.tmpl
Normal file
|
@ -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
|
Loading…
Reference in a new issue