From: Wolfgang Bumiller Date: Tue, 1 May 2012 15:02:45 +0000 (+0200) Subject: ast_ternary - contrary to ast_ifthen neither ontrue nor onfalse can be NULL, and... X-Git-Tag: 0.1-rc1~523 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=1e0a688bc58835872db02436443f67a764d4baf5;p=xonotic%2Fgmqcc.git ast_ternary - contrary to ast_ifthen neither ontrue nor onfalse can be NULL, and it does output a value --- diff --git a/ast.c b/ast.c index 3ab7b37..63787cd 100644 --- a/ast.c +++ b/ast.c @@ -178,6 +178,32 @@ void ast_ifthen_delete(ast_ifthen *self) mem_d(self); } +ast_ternary* ast_ternary_new(lex_ctx ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse) +{ + ast_instantiate(ast_ternary, ctx, ast_ternary_delete); + /* This time NEITHER must be NULL */ + if (!ontrue || !onfalse) { + mem_d(self); + return NULL; + } + ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_ternary_codegen); + + self->cond = cond; + self->on_true = ontrue; + self->on_false = onfalse; + self->phi_out = NULL; + + return self; +} + +void ast_ternary_delete(ast_ternary *self) +{ + ast_unref(self->cond); + ast_unref(self->on_true); + ast_unref(self->on_false); + mem_d(self); +} + ast_store* ast_store_new(lex_ctx ctx, int op, ast_value *dest, ast_expression *source) { @@ -374,3 +400,17 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va if (out) *out = NULL; return false; } + +bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_value **out) +{ + /* In theory it shouldn't be possible to pass through a node twice, but + * in case we add any kind of optimization pass for the AST itself, it + * may still happen, thus we remember a created ir_value and simply return one + * if it already exists. + */ + if (self->phi_out) { + *out = self->phi_out; + return true; + } + return false; +} diff --git a/ast.h b/ast.h index c9311ee..f114999 100644 --- a/ast.h +++ b/ast.h @@ -38,6 +38,7 @@ typedef struct ast_binary_s ast_binary; typedef struct ast_store_s ast_store; typedef struct ast_entfield_s ast_entfield; typedef struct ast_ifthen_s ast_ifthen; +typedef struct ast_ternary_s ast_ternary; /* Node interface with common components */ @@ -205,6 +206,36 @@ void ast_ifthen_delete(ast_ifthen*); bool ast_ifthen_codegen(ast_ifthen*, ast_function*, bool lvalue, ir_value**); +/* Ternary expressions... + * + * Contrary to 'if-then-else' nodes, ternary expressions actually + * return a value, otherwise they behave the very same way. + * The difference in 'codegen' is that it'll return the value of + * a PHI node. + * + * The other difference is that in an ast_ternary, NEITHER side + * must be NULL, there's ALWAYS an else branch. + * + * This is the only ast_node beside ast_value which contains + * an ir_value. Theoretically we don't need to remember it though. + */ +struct ast_ternary_s +{ + ast_expression_common expression; + ast_expression *cond; + /* It's all just 'expressions', since an ast_block is one too. */ + ast_expression *on_true; + ast_expression *on_false; + /* After a ternary expression we find ourselves in a new IR block + * and start with a PHI node */ + ir_value *phi_out; +}; +ast_ternary* ast_ternary_new(lex_ctx ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse); +void ast_ternary_delete(ast_ternary*); + +bool ast_ternary_codegen(ast_ternary*, ast_function*, bool lvalue, ir_value**); + + /* Blocks * */