]> git.rm.cloudns.org Git - xonotic/gmqcc.git/commitdiff
allow array size to be inferred from the initializer
authorWolfgang Bumiller <wry.git@bumiller.com>
Wed, 12 Jun 2013 13:47:11 +0000 (15:47 +0200)
committerWolfgang Bumiller <wry.git@bumiller.com>
Wed, 12 Jun 2013 13:47:11 +0000 (15:47 +0200)
ast.c
ast.h
parser.c

diff --git a/ast.c b/ast.c
index c1d8cb9c4c1f0b8096bbec6bdab9a023d64cf586..94b254cc91f5a3ad3931fe81d9654e1d738f4047 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -1373,6 +1373,11 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
         ast_expression *elemtype = self->expression.next;
         int vtype = elemtype->vtype;
 
+        if (self->expression.flags & AST_FLAG_ARRAY_INIT && !self->expression.count) {
+            compile_error(ast_ctx(self), "array `%s' has no size", self->name);
+            return false;
+        }
+
         /* same as with field arrays */
         if (!self->expression.count || self->expression.count > OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE))
             compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)self->expression.count);
diff --git a/ast.h b/ast.h
index 7f56bee618e52ae805117a1847be45861668f3da..1c4574a57182143982355403ae03c96ab1dcb566 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -153,6 +153,9 @@ struct ast_expression_common
 #define AST_FLAG_INCLUDE_DEF  (1<<5)
 #define AST_FLAG_IS_VARARG    (1<<6)
 #define AST_FLAG_ALIAS        (1<<7)
+/* An array declared as []
+ * so that the size is taken from the initializer */
+#define AST_FLAG_ARRAY_INIT   (1<<8)
 #define AST_FLAG_TYPE_MASK (AST_FLAG_VARIADIC | AST_FLAG_NORETURN)
 
 /* Value
index 6a4ae20bedaac8682f1198627d281936f5fe1d38..e6326a9498d3cf259152082c48f31b7c93c1e21f 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -4917,32 +4917,44 @@ static ast_value *parse_arraysize(parser_t *parser, ast_value *var)
         return NULL;
     }
 
-    cexp = parse_expression_leave(parser, true, false, false);
+    if (parser->tok != ']') {
+        cexp = parse_expression_leave(parser, true, false, false);
 
-    if (!cexp || !ast_istype(cexp, ast_value)) {
-        if (cexp)
-            ast_unref(cexp);
-        ast_delete(var);
-        parseerror(parser, "expected array-size as constant positive integer");
-        return NULL;
+        if (!cexp || !ast_istype(cexp, ast_value)) {
+            if (cexp)
+                ast_unref(cexp);
+            ast_delete(var);
+            parseerror(parser, "expected array-size as constant positive integer");
+            return NULL;
+        }
+        cval = (ast_value*)cexp;
+    }
+    else {
+        cexp = NULL;
+        cval = NULL;
     }
-    cval = (ast_value*)cexp;
 
     tmp = ast_value_new(ctx, "<type[]>", TYPE_ARRAY);
     tmp->expression.next = (ast_expression*)var;
     var = tmp;
 
-    if (cval->expression.vtype == TYPE_INTEGER)
-        tmp->expression.count = cval->constval.vint;
-    else if (cval->expression.vtype == TYPE_FLOAT)
-        tmp->expression.count = cval->constval.vfloat;
-    else {
+    if (cval) {
+        if (cval->expression.vtype == TYPE_INTEGER)
+            tmp->expression.count = cval->constval.vint;
+        else if (cval->expression.vtype == TYPE_FLOAT)
+            tmp->expression.count = cval->constval.vfloat;
+        else {
+            ast_unref(cexp);
+            ast_delete(var);
+            parseerror(parser, "array-size must be a positive integer constant");
+            return NULL;
+        }
+
         ast_unref(cexp);
-        ast_delete(var);
-        parseerror(parser, "array-size must be a positive integer constant");
-        return NULL;
+    } else {
+        var->expression.count = -1;
+        var->expression.flags |= AST_FLAG_ARRAY_INIT;
     }
-    ast_unref(cexp);
 
     if (parser->tok != ']') {
         ast_delete(var);
@@ -5192,6 +5204,18 @@ static bool parser_check_qualifiers(parser_t *parser, const ast_value *var, cons
     return true;
 }
 
+static bool create_array_accessors(parser_t *parser, ast_value *var)
+{
+    char name[1024];
+    util_snprintf(name, sizeof(name), "%s##SET", var->name);
+    if (!parser_create_array_setter(parser, var, name))
+        return false;
+    util_snprintf(name, sizeof(name), "%s##GET", var->name);
+    if (!parser_create_array_getter(parser, var, var->expression.next, name))
+        return false;
+    return true;
+}
+
 static bool parse_array(parser_t *parser, ast_value *array)
 {
     if (!parser_next(parser)) {
@@ -5226,6 +5250,16 @@ static bool parse_array(parser_t *parser, ast_value *array)
         return false;
     }
     */
+
+    if (array->expression.flags & AST_FLAG_ARRAY_INIT) {
+        if (array->expression.count != (size_t)-1) {
+            parseerror(parser, "array `%s' has already been initialized with %u elements",
+                       array->name, (unsigned)array->expression.count);
+        }
+        array->expression.count = vec_size(array->initlist);
+        if (!create_array_accessors(parser, array))
+            return false;
+    }
     return true;
 }
 
@@ -5662,13 +5696,10 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
          * deal with arrays
          */
         if (var->expression.vtype == TYPE_ARRAY) {
-            char name[1024];
-            util_snprintf(name, sizeof(name), "%s##SET", var->name);
-            if (!parser_create_array_setter(parser, var, name))
-                goto cleanup;
-            util_snprintf(name, sizeof(name), "%s##GET", var->name);
-            if (!parser_create_array_getter(parser, var, var->expression.next, name))
-                goto cleanup;
+            if (var->expression.count != (size_t)-1) {
+                if (!create_array_accessors(parser, var))
+                    goto cleanup;
+            }
         }
         else if (!localblock && !nofields &&
                  var->expression.vtype == TYPE_FIELD &&