codegen: Use temporary variable for string concatenation
[vala-lang.git] / vala / valaarraytype.vala
blob5ed4ff68377c9df0773be639ba24cbd2e1e3d30f
1 /* valaarraytype.vala
3 * Copyright (C) 2007-2010 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
25 /**
26 * An array type.
28 public class Vala.ArrayType : ReferenceType {
29 /**
30 * The element type.
32 public DataType element_type {
33 get { return _element_type; }
34 set {
35 _element_type = value;
36 _element_type.parent_node = this;
40 public bool invalid_syntax { get; set; }
42 public bool inline_allocated { get; set; }
44 public bool fixed_length { get; set; }
46 /**
47 * The length of this fixed-length array.
49 public int length { get; set; }
51 /**
52 * The rank of this array.
54 public int rank { get; set; }
56 private DataType _element_type;
58 private ArrayLengthField length_field;
59 private ArrayResizeMethod resize_method;
60 private ArrayMoveMethod move_method;
62 public ArrayType (DataType element_type, int rank, SourceReference? source_reference) {
63 this.element_type = element_type;
64 this.rank = rank;
65 this.source_reference = source_reference;
68 public override Symbol? get_member (string member_name) {
69 if (CodeContext.get ().profile == Profile.DOVA) {
70 return SemanticAnalyzer.symbol_lookup_inherited (CodeContext.get ().root.scope.lookup ("Dova").scope.lookup ("Array"), member_name);
71 } else if (member_name == "length") {
72 return get_length_field ();
73 } else if (member_name == "move") {
74 return get_move_method ();
75 } else if (member_name == "resize") {
76 return get_resize_method ();
78 return null;
81 private ArrayLengthField get_length_field () {
82 if (length_field == null) {
83 length_field = new ArrayLengthField (source_reference);
85 length_field.access = SymbolAccessibility.PUBLIC;
87 var root_symbol = source_reference.file.context.root;
88 if (rank > 1) {
89 // length is an int[] containing the dimensions of the array, starting at 0
90 ValueType integer = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
91 length_field.variable_type = new ArrayType (integer, 1, source_reference);
92 } else {
93 length_field.variable_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
97 return length_field;
100 private ArrayResizeMethod get_resize_method () {
101 if (resize_method == null) {
102 resize_method = new ArrayResizeMethod (source_reference);
104 resize_method.return_type = new VoidType ();
105 resize_method.access = SymbolAccessibility.PUBLIC;
107 resize_method.set_cname ("g_renew");
109 var root_symbol = source_reference.file.context.root;
110 var int_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
112 resize_method.add_parameter (new Parameter ("length", int_type));
114 resize_method.returns_modified_pointer = true;
116 return resize_method;
119 private ArrayMoveMethod get_move_method () {
120 if (move_method == null) {
121 move_method = new ArrayMoveMethod (source_reference);
123 move_method.return_type = new VoidType ();
124 move_method.access = SymbolAccessibility.PUBLIC;
126 move_method.set_cname ("_vala_array_move");
128 var root_symbol = source_reference.file.context.root;
129 var int_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
131 move_method.add_parameter (new Parameter ("src", int_type));
132 move_method.add_parameter (new Parameter ("dest", int_type));
133 move_method.add_parameter (new Parameter ("length", int_type));
135 return move_method;
138 public override DataType copy () {
139 var result = new ArrayType (element_type.copy (), rank, source_reference);
140 result.value_owned = value_owned;
141 result.nullable = nullable;
142 result.floating_reference = floating_reference;
144 result.inline_allocated = inline_allocated;
145 if (fixed_length) {
146 result.fixed_length = true;
147 result.length = length;
150 return result;
153 public override string? get_cname () {
154 if (inline_allocated) {
155 return element_type.get_cname ();
156 } else {
157 if (CodeContext.get ().profile == Profile.DOVA) {
158 return "DovaArray*";
159 } else {
160 return element_type.get_cname () + "*";
165 public override string get_cdeclarator_suffix () {
166 if (fixed_length) {
167 return "[%d]".printf (length);
168 } else if (inline_allocated) {
169 return "[]";
170 } else {
171 return "";
175 public override bool is_array () {
176 return true;
179 public override string to_qualified_string (Scope? scope) {
180 return "%s[%s]%s".printf (element_type.to_qualified_string (scope), string.nfill (rank - 1, ','), nullable ? "?" : "");
183 public override bool compatible (DataType target_type) {
184 if (target_type.get_type_id () == "G_TYPE_VALUE" && element_type.data_type == CodeContext.get ().root.scope.lookup ("string")) {
185 // allow implicit conversion from string[] to GValue
186 return true;
189 if (target_type.get_type_id () == "G_TYPE_VARIANT") {
190 // allow implicit conversion to GVariant
191 return true;
194 if (target_type is PointerType || (target_type.data_type != null && target_type.data_type.get_attribute ("PointerType") != null)) {
195 /* any array type can be cast to a generic pointer */
196 return true;
199 /* temporarily ignore type parameters */
200 if (target_type.type_parameter != null) {
201 return true;
204 var target_array_type = target_type as ArrayType;
205 if (target_array_type == null) {
206 return false;
209 if (target_array_type.rank != rank) {
210 return false;
213 if (element_type.compatible (target_array_type.element_type)
214 && target_array_type.element_type.compatible (element_type)) {
215 return true;
218 return false;
221 public override bool is_reference_type_or_type_parameter () {
222 return true;
225 public override void accept_children (CodeVisitor visitor) {
226 element_type.accept (visitor);
229 public override void replace_type (DataType old_type, DataType new_type) {
230 if (element_type == old_type) {
231 element_type = new_type;
235 public override bool is_accessible (Symbol sym) {
236 return element_type.is_accessible (sym);
239 public override bool check (CodeContext context) {
240 if (invalid_syntax) {
241 Report.error (source_reference, "syntax error, no expression allowed between array brackets");
242 error = true;
243 return false;
245 return element_type.check (context);
248 public override string? get_type_id () {
249 if (element_type.data_type == CodeContext.get ().root.scope.lookup ("string")) {
250 return "G_TYPE_STRV";
251 } else {
252 return null;
256 public override DataType get_actual_type (DataType? derived_instance_type, MemberAccess? method_access, CodeNode node_reference) {
257 if (derived_instance_type == null && method_access == null) {
258 return this;
261 ArrayType result = this;
263 if (element_type is GenericType || element_type.has_type_arguments ()) {
264 result = (ArrayType) result.copy ();
265 result.element_type = result.element_type.get_actual_type (derived_instance_type, method_access, node_reference);
268 return result;
271 public override bool is_disposable () {
272 if (fixed_length) {
273 return element_type.is_disposable ();
274 } else {
275 return base.is_disposable ();