[vala/staging] Support non-literal length in fixed-size arrays



commit cbac8f57994989f9deb14c7a54def81e3690273b
Author: Simon <simon werbeck gmail com>
Date:   Thu Mar 13 22:48:40 2014 +0100

    Support non-literal length in fixed-size arrays
    
    Now any constant integer expression can be used as length
    for fixed-size arrays.
    
    Fixes bug 638993

 ccode/valaccodestruct.vala             |    2 +-
 ccode/valaccodevariabledeclarator.vala |   37 +++++++++++++++++++++++++++----
 codegen/valaccodearraymodule.vala      |    8 +++---
 codegen/valaccodeassignmentmodule.vala |    2 +-
 codegen/valaccodebasemodule.vala       |   12 +++++-----
 codegen/valaccodestructmodule.vala     |    7 +++++-
 codegen/valagirwriter.vala             |    5 ++-
 tests/basic-types/arrays.vala          |    4 +++
 vala/valaarraytype.vala                |   21 +++++++++++++++++-
 vala/valacodewriter.vala               |    4 ++-
 vala/valagenieparser.vala              |   11 ++-------
 vala/valaparser.vala                   |   11 ++-------
 12 files changed, 86 insertions(+), 38 deletions(-)
---
diff --git a/ccode/valaccodestruct.vala b/ccode/valaccodestruct.vala
index 76f7679..96836ed 100644
--- a/ccode/valaccodestruct.vala
+++ b/ccode/valaccodestruct.vala
@@ -59,7 +59,7 @@ public class Vala.CCodeStruct : CCodeNode {
         * @param type_name field type
         * @param name      member name
         */
-       public void add_field (string type_name, string name, string? declarator_suffix = null) {
+       public void add_field (string type_name, string name, CCodeDeclaratorSuffix? declarator_suffix = 
null) {
                var decl = new CCodeDeclaration (type_name);
                decl.add_declarator (new CCodeVariableDeclarator (name, null, declarator_suffix));
                add_declaration (decl);
diff --git a/ccode/valaccodevariabledeclarator.vala b/ccode/valaccodevariabledeclarator.vala
index 863ec83..c8dd874 100644
--- a/ccode/valaccodevariabledeclarator.vala
+++ b/ccode/valaccodevariabledeclarator.vala
@@ -39,7 +39,7 @@ public class Vala.CCodeVariableDeclarator : CCodeDeclarator {
        /**
         * The optional declarator suffix.
         */
-       public string? declarator_suffix { get; set; }
+       public CCodeDeclaratorSuffix? declarator_suffix { get; set; }
 
        /**
         * Initializer only used to zero memory, safe to initialize as part
@@ -47,13 +47,13 @@ public class Vala.CCodeVariableDeclarator : CCodeDeclarator {
         */
        public bool init0 { get; set; }
 
-       public CCodeVariableDeclarator (string name, CCodeExpression? initializer = null, string? 
declarator_suffix = null) {
+       public CCodeVariableDeclarator (string name, CCodeExpression? initializer = null, 
CCodeDeclaratorSuffix? declarator_suffix = null) {
                this.name = name;
                this.initializer = initializer;
                this.declarator_suffix = declarator_suffix;
        }
 
-       public CCodeVariableDeclarator.zero (string name, CCodeExpression? initializer, string? 
declarator_suffix = null) {
+       public CCodeVariableDeclarator.zero (string name, CCodeExpression? initializer, 
CCodeDeclaratorSuffix? declarator_suffix = null) {
                this.name = name;
                this.initializer = initializer;
                this.declarator_suffix = declarator_suffix;
@@ -62,8 +62,9 @@ public class Vala.CCodeVariableDeclarator : CCodeDeclarator {
 
        public override void write (CCodeWriter writer) {
                writer.write_string (name);
+
                if (declarator_suffix != null) {
-                       writer.write_string (declarator_suffix);
+                       declarator_suffix.write (writer);
                }
 
                if (initializer != null) {
@@ -74,8 +75,9 @@ public class Vala.CCodeVariableDeclarator : CCodeDeclarator {
 
        public override void write_declaration (CCodeWriter writer) {
                writer.write_string (name);
+
                if (declarator_suffix != null) {
-                       writer.write_string (declarator_suffix);
+                       declarator_suffix.write (writer);
                }
 
                if (initializer != null && init0) {
@@ -97,3 +99,28 @@ public class Vala.CCodeVariableDeclarator : CCodeDeclarator {
                }
        }
 }
+
+public class Vala.CCodeDeclaratorSuffix {
+       public bool array;
+       public CCodeExpression? array_length;
+       public bool deprecated;
+
+       public CCodeDeclaratorSuffix.with_array (CCodeExpression? array_length = null) {
+               this.array_length = array_length;
+               array = true;
+       }
+
+       public void write (CCodeWriter writer) {
+               if (array) {
+                       writer.write_string ("[");
+                       if (array_length != null) {
+                               array_length.write (writer);
+                       }
+                       writer.write_string ("]");
+               }
+
+               if (deprecated) {
+                       writer.write_string (" G_GNUC_DEPRECATED");
+               }
+       }
+}
diff --git a/codegen/valaccodearraymodule.vala b/codegen/valaccodearraymodule.vala
index 7bf6826..8922464 100644
--- a/codegen/valaccodearraymodule.vala
+++ b/codegen/valaccodearraymodule.vala
@@ -117,7 +117,7 @@ public class Vala.CCodeArrayModule : CCodeMethodCallModule {
                var array_type = value.value_type as ArrayType;
 
                if (array_type != null && array_type.fixed_length) {
-                       return new CCodeConstant (array_type.length.to_string ());
+                       return get_ccodenode (array_type.length);
                }
 
                // dim == -1 => total size over all dimensions
@@ -452,7 +452,7 @@ public class Vala.CCodeArrayModule : CCodeMethodCallModule {
 
                        ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy"));
                        ccall.add_argument (get_cvalue_ (value));
-                       ccall.add_argument (new CCodeConstant ("%d".printf (array_type.length)));
+                       ccall.add_argument (get_ccodenode (array_type.length));
                        ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression 
(array_type.element_type), "GDestroyNotify"));
 
                        return ccall;
@@ -559,7 +559,7 @@ public class Vala.CCodeArrayModule : CCodeMethodCallModule {
                        ccode.add_declaration ("int", new CCodeVariableDeclarator ("i"));
 
                        ccode.open_for (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant 
("0")),
-                                          new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new 
CCodeIdentifier ("i"), new CCodeConstant ("%d".printf (array_type.length))),
+                                          new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new 
CCodeIdentifier ("i"), get_ccodenode (array_type.length)),
                                           new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, 
new CCodeIdentifier ("i")));
 
 
@@ -573,7 +573,7 @@ public class Vala.CCodeArrayModule : CCodeMethodCallModule {
 
                        var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
                        sizeof_call.add_argument (new CCodeIdentifier (get_ccode_name 
(array_type.element_type)));
-                       dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new 
CCodeConstant ("%d".printf (array_type.length)), sizeof_call));
+                       dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, 
get_ccodenode (array_type.length), sizeof_call));
 
                        ccode.add_expression (dup_call);
                }
diff --git a/codegen/valaccodeassignmentmodule.vala b/codegen/valaccodeassignmentmodule.vala
index 67be9c9..76004f7 100644
--- a/codegen/valaccodeassignmentmodule.vala
+++ b/codegen/valaccodeassignmentmodule.vala
@@ -104,7 +104,7 @@ public class Vala.CCodeAssignmentModule : CCodeMemberAccessModule {
                        // simple assignments do not work in C
                        var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
                        sizeof_call.add_argument (new CCodeIdentifier (get_ccode_name 
(array_type.element_type)));
-                       var size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant 
("%d".printf (array_type.length)), sizeof_call);
+                       var size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_ccodenode 
(array_type.length), sizeof_call);
 
                        var ccopy = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
                        ccopy.add_argument (get_cvalue_ (lvalue));
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index e708545..8e844a6 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -1897,7 +1897,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                                if (local.captured) {
                                        generate_type_declaration (local.variable_type, cfile);
 
-                                       data.add_field (get_ccode_name (local.variable_type), get_local_cname 
(local) + get_ccode_declarator_suffix (local.variable_type));
+                                       data.add_field (get_ccode_name (local.variable_type), get_local_cname 
(local), get_ccode_declarator_suffix (local.variable_type));
 
                                        if (local.variable_type is ArrayType) {
                                                var array_type = (ArrayType) local.variable_type;
@@ -2311,7 +2311,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                                }
                                emit_context.closure_variable_count_map.set (local.name, count + 1);
 
-                               closure_struct.add_field (get_ccode_name (local.variable_type), 
get_local_cname (local) + get_ccode_declarator_suffix (local.variable_type));
+                               closure_struct.add_field (get_ccode_name (local.variable_type), 
get_local_cname (local), get_ccode_declarator_suffix (local.variable_type));
                        } else {
                                var cvar = new CCodeVariableDeclarator (get_local_cname (local), null, 
get_ccode_declarator_suffix (local.variable_type));
 
@@ -6309,16 +6309,16 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                return blurb;
        }
 
-       public static string get_ccode_declarator_suffix (DataType type) {
+       public CCodeDeclaratorSuffix? get_ccode_declarator_suffix (DataType type) {
                var array_type = type as ArrayType;
                if (array_type != null) {
                        if (array_type.fixed_length) {
-                               return "[%d]".printf (array_type.length);
+                               return new CCodeDeclaratorSuffix.with_array (get_ccodenode 
(array_type.length));
                        } else if (array_type.inline_allocated) {
-                               return "[]";
+                               return new CCodeDeclaratorSuffix.with_array ();
                        }
                }
-               return "";
+               return null;
        }
 
        public CCodeConstant get_signal_canonical_constant (Signal sig, string? detail = null) {
diff --git a/codegen/valaccodestructmodule.vala b/codegen/valaccodestructmodule.vala
index 86b1b9b..fe2a7c2 100644
--- a/codegen/valaccodestructmodule.vala
+++ b/codegen/valaccodestructmodule.vala
@@ -75,7 +75,12 @@ public abstract class Vala.CCodeStructModule : CCodeBaseModule {
                        if (f.binding == MemberBinding.INSTANCE)  {
                                generate_type_declaration (f.variable_type, decl_space);
 
-                               instance_struct.add_field (field_ctype, get_ccode_name (f) + 
get_ccode_declarator_suffix (f.variable_type), f.deprecated ? " G_GNUC_DEPRECATED" : null);
+                               var suffix = get_ccode_declarator_suffix (f.variable_type);
+                               if (suffix != null) {
+                                       suffix.deprecated = f.deprecated;
+                               }
+
+                               instance_struct.add_field (field_ctype, get_ccode_name (f), suffix);
                                if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
                                        // create fields to store array dimensions
                                        var array_type = (ArrayType) f.variable_type;
diff --git a/codegen/valagirwriter.vala b/codegen/valagirwriter.vala
index e654509..e38b0ad 100644
--- a/codegen/valagirwriter.vala
+++ b/codegen/valagirwriter.vala
@@ -1262,8 +1262,9 @@ public class Vala.GIRWriter : CodeVisitor {
 
                        write_indent ();
                        buffer.append_printf ("<array");
-                       if (array_type.fixed_length) {
-                               buffer.append_printf (" fixed-size=\"%i\"", array_type.length);
+                       if (array_type.fixed_length && array_type.length is IntegerLiteral) {
+                               var lit = (IntegerLiteral) array_type.length;
+                               buffer.append_printf (" fixed-size=\"%i\"", int.parse (lit.value));
                        } else if (index != -1) {
                                buffer.append_printf (" length=\"%i\"", index);
                        }
diff --git a/tests/basic-types/arrays.vala b/tests/basic-types/arrays.vala
index 4a6a006..00a7164 100644
--- a/tests/basic-types/arrays.vala
+++ b/tests/basic-types/arrays.vala
@@ -84,6 +84,7 @@ void test_array_pass () {
        assert (b[0] == 42);
 }
 
+const int FOO = 2;
 void test_static_array () {
        int a[2];
        assert (a.length == 2);
@@ -91,6 +92,9 @@ void test_static_array () {
        assert (a[1] == 23);
        a = { 23, 34 };
        assert (a[0] == 23 && a[1] == 34);
+
+       int b[FOO * 1 << 3];
+       assert (b.length == FOO * 1 << 3);
 }
 
 void test_reference_transfer () {
diff --git a/vala/valaarraytype.vala b/vala/valaarraytype.vala
index 852342c..e1bf8d0 100644
--- a/vala/valaarraytype.vala
+++ b/vala/valaarraytype.vala
@@ -46,7 +46,15 @@ public class Vala.ArrayType : ReferenceType {
        /**
         * The length of this fixed-length array.
         */
-       public int length { get; set; }
+       public Expression? length {
+               get { return _length; }
+               set {
+                       _length = value;
+                       if (_length != null) {
+                               _length.parent_node = this;
+                       }
+               }
+       }
 
        /**
         * The rank of this array.
@@ -54,6 +62,7 @@ public class Vala.ArrayType : ReferenceType {
        public int rank { get; set; }
 
        private DataType _element_type;
+       private Expression _length;
 
        private ArrayLengthField length_field;
        private ArrayResizeMethod resize_method;
@@ -231,6 +240,16 @@ public class Vala.ArrayType : ReferenceType {
                        error = true;
                        return false;
                }
+
+               if (fixed_length && length != null) {
+                       length.check (context);
+
+                       if (length.value_type == null || !(length.value_type is IntegerType) || 
!length.is_constant ()) {
+                               Report.error (length.source_reference, "Expression of constant integer type 
expected");
+                               return false;
+                       }
+               }
+
                return element_type.check (context);
        }
 
diff --git a/vala/valacodewriter.vala b/vala/valacodewriter.vala
index 7f64fa2..0cfa469 100644
--- a/vala/valacodewriter.vala
+++ b/vala/valacodewriter.vala
@@ -1456,7 +1456,9 @@ public class Vala.CodeWriter : CodeVisitor {
        private void write_type_suffix (DataType type) {
                var array_type = type as ArrayType;
                if (array_type != null && array_type.fixed_length) {
-                       write_string ("[%d]".printf (array_type.length));
+                       write_string ("[");
+                       array_type.length.accept (this);
+                       write_string ("]");
                }
        }
 
diff --git a/vala/valagenieparser.vala b/vala/valagenieparser.vala
index f479905..7abd943 100644
--- a/vala/valagenieparser.vala
+++ b/vala/valagenieparser.vala
@@ -602,21 +602,16 @@ public class Vala.Genie.Parser : CodeVisitor {
 
                // inline-allocated array
                if (type != null && accept (TokenType.OPEN_BRACKET)) {
-                       int array_length = -1;
+                       Expression array_length = null;
 
                        if (current () != TokenType.CLOSE_BRACKET) {
-                               if (current () != TokenType.INTEGER_LITERAL) {
-                                       throw new ParseError.SYNTAX (get_error ("expected `]' or integer 
literal"));
-                               }
-
-                               var length_literal = (IntegerLiteral) parse_literal ();
-                               array_length = int.parse (length_literal.value);
+                               array_length = parse_expression ();
                        }
                        expect (TokenType.CLOSE_BRACKET);
 
                        var array_type = new ArrayType (type, 1, get_src (begin));
                        array_type.inline_allocated = true;
-                       if (array_length > 0) {
+                       if (array_length != null) {
                                array_type.fixed_length = true;
                                array_type.length = array_length;
                        }
diff --git a/vala/valaparser.vala b/vala/valaparser.vala
index a7ca9c0..3070cc0 100644
--- a/vala/valaparser.vala
+++ b/vala/valaparser.vala
@@ -499,21 +499,16 @@ public class Vala.Parser : CodeVisitor {
 
                // inline-allocated array
                if (type != null && accept (TokenType.OPEN_BRACKET)) {
-                       int array_length = -1;
+                       Expression array_length = null;
 
                        if (current () != TokenType.CLOSE_BRACKET) {
-                               if (current () != TokenType.INTEGER_LITERAL) {
-                                       throw new ParseError.SYNTAX (get_error ("expected `]' or integer 
literal"));
-                               }
-
-                               var length_literal = (IntegerLiteral) parse_literal ();
-                               array_length = int.parse (length_literal.value);
+                               array_length = parse_expression ();
                        }
                        expect (TokenType.CLOSE_BRACKET);
 
                        var array_type = new ArrayType (type, 1, get_src (begin));
                        array_type.inline_allocated = true;
-                       if (array_length > 0) {
+                       if (array_length != null) {
                                array_type.fixed_length = true;
                                array_type.length = array_length;
                        }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]