Commit 5938a38b authored by Simon Werbeck's avatar Simon Werbeck Committed by Luca Bruno

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
parent d9dff687
......@@ -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);
......
......@@ -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");
}
}
}
......@@ -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);
}
......
......@@ -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));
......
......@@ -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) {
......
......@@ -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;
......
......@@ -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);
}
......
......@@ -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 () {
......
......@@ -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);
}
......
......@@ -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 ("]");
}
}
......
......@@ -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;
}
......
......@@ -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;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment