]> git.rm.cloudns.org Git - xonotic/gmqcc.git/commitdiff
Perliminary stuff for any/all ranges. This doesn't do anything, important, just some... graphitemaster/range
authorDale Weiler <killfieldengine@gmail.com>
Mon, 16 Dec 2013 23:35:31 +0000 (18:35 -0500)
committerDale Weiler <killfieldengine@gmail.com>
Mon, 16 Dec 2013 23:35:31 +0000 (18:35 -0500)
ast.c
ast.h

diff --git a/ast.c b/ast.c
index e10bbed51712ecea27d544b466517ecf5ec99749..0ee4a2148b6b4e77f8b1d6845c10930d153162e0 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -75,6 +75,8 @@ static void ast_binstore_delete(ast_binstore*);
 static bool ast_binstore_codegen(ast_binstore*, ast_function*, bool lvalue, ir_value**);
 static void ast_binary_delete(ast_binary*);
 static bool ast_binary_codegen(ast_binary*, ast_function*, bool lvalue, ir_value**);
+static void ast_range_delete(ast_range *);
+static bool ast_range_codegen(ast_range*, ast_function*, bool lvalue, ir_value**);
 
 /* It must not be possible to get here. */
 static GMQCC_NORETURN void _ast_node_destroy(ast_node *self)
@@ -918,6 +920,27 @@ void ast_switch_delete(ast_switch *self)
     mem_d(self);
 }
 
+ast_range* ast_range_new(lex_ctx_t ctx, ast_expression *lower, ast_expression *upper) {
+    ast_instantiate(ast_range, ctx, ast_range_delete);
+    ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_range_codegen);
+
+    self->lower = lower;
+    self->upper = upper;
+
+    ast_propagate_effects(self, lower);
+    ast_propagate_effects(self, upper);
+
+    return self;
+}
+
+void ast_range_delete(ast_range *self) {
+    ast_unref(self->upper);
+    ast_unref(self->lower);
+
+    ast_expression_delete((ast_expression*)self);
+    mem_d(self);
+}
+
 ast_label* ast_label_new(lex_ctx_t ctx, const char *name, bool undefined)
 {
     ast_instantiate(ast_label, ctx, ast_label_delete);
@@ -3266,6 +3289,30 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va
     return true;
 }
 
+bool ast_range_codegen(ast_range *self, ast_function *func, bool lvalue, ir_value **out) {
+    ast_expression_codegen *cgen    = NULL;
+    ir_value               *irupper = NULL;
+    ir_value               *irlower = NULL;
+
+    if (lvalue) {
+        compile_error(ast_ctx(self), "range expression is not an l-value");
+        return false;
+    }
+
+    /* generate (lower .. upper) */
+    cgen = self->lower->codegen;
+    if (!(*cgen)((ast_expression*)(self->lower), func, false, &irlower))
+        return false;
+    cgen = self->upper->codegen;
+    if (!(*cgen)((ast_expression*)(self->upper), func, false, &irupper))
+        return false;
+
+    (void)lvalue;
+    (void)out;
+
+    return true;
+}
+
 bool ast_label_codegen(ast_label *self, ast_function *func, bool lvalue, ir_value **out)
 {
     size_t i;
diff --git a/ast.h b/ast.h
index 936a58763db75af31fe75925cc49e7b21766da4f..122af2fb386b37b66fd34598645a73d67492660c 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -51,6 +51,7 @@ typedef struct ast_member_s      ast_member;
 typedef struct ast_array_index_s ast_array_index;
 typedef struct ast_breakcont_s   ast_breakcont;
 typedef struct ast_switch_s      ast_switch;
+typedef struct ast_range_s       ast_range;
 typedef struct ast_label_s       ast_label;
 typedef struct ast_goto_s        ast_goto;
 typedef struct ast_argpipe_s     ast_argpipe;
@@ -98,10 +99,11 @@ enum {
     TYPE_ast_member,      /* 15 */
     TYPE_ast_array_index, /* 16 */
     TYPE_ast_breakcont,   /* 17 */
-    TYPE_ast_switch,      /* 18 */
-    TYPE_ast_label,       /* 19 */
-    TYPE_ast_goto,        /* 20 */
-    TYPE_ast_argpipe      /* 21 */
+    TYPE_ast_range,       /* 18 */
+    TYPE_ast_switch,      /* 19 */
+    TYPE_ast_label,       /* 20 */
+    TYPE_ast_goto,        /* 21 */
+    TYPE_ast_argpipe      /* 22 */
 };
 
 #define ast_istype(x, t) ( ((ast_node*)x)->nodetype == (TYPE_##t) )
@@ -537,6 +539,38 @@ struct ast_switch_s
 
 ast_switch* ast_switch_new(lex_ctx_t ctx, ast_expression *op);
 
+/*
+ * Ranges
+ *
+ * Used to implement any/all ranges, which are inclusive only.
+ * This any / all are range specifiers which change the semantics of
+ * how the range expression is dealt with. Because of the nature of ranges
+ * the whole expression it's used in needs to be rewrote. A table of how
+ * the rewrite works is provided below:
+ *
+ *  (a == any b .. c) -> (a >= b && a <= c)
+ *  (a == all b .. c) -> error (makes no sense)
+ *  (a != any b .. c) -> error (makes no sense)
+ *  (a != all b .. c) -> (a < b || a > c)
+ *  (a <= any b .. c) -> (a <= c)
+ *  (a <= all b .. c) -> (a <= b)
+ *  (a >= any b .. c) -> (a >= b)
+ *  (a >= all b .. c) -> (a >= c)
+ *  (a < any b .. c) -> (a < c)
+ *  (a < all b .. c) -> (a < b)
+ *  (a > any b .. c) -> (a > b)
+ *  (a > all b .. c) -> (a > c)
+ *  (a <=> any b .. c) -> error (why would you even try)
+ *  (a <=> all b .. c) -> error (why would you even try)
+ */
+struct ast_range_s {
+    ast_expression expression;
+    ast_expression *lower;
+    ast_expression *upper;
+};
+
+ast_range* ast_range_new(lex_ctx_t ctx, ast_expression *lower, ast_expression *upper);
+
 /* Label nodes
  *
  * Introduce a label which can be used together with 'goto'