]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
ast_ternary - contrary to ast_ifthen neither ontrue nor onfalse can be NULL, and...
authorWolfgang Bumiller <wolfgang.linux@bumiller.com>
Tue, 1 May 2012 15:02:45 +0000 (17:02 +0200)
committerWolfgang Bumiller <wolfgang.linux@bumiller.com>
Tue, 1 May 2012 15:02:45 +0000 (17:02 +0200)
ast.c
ast.h

diff --git a/ast.c b/ast.c
index 3ab7b3755db6a8372292b90d6d821b85d83f7e3f..63787cd547d0f56582c8689212bd583ea6f91896 100644 (file)
--- 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 c9311eeb7e4e6b96eaf23785029a509ec108f4ed..f1149994226f054b912c02e636e1772c94f3d159 100644 (file)
--- 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
  *
  */