1/* valaarraycreationexpression.vala 2 * 3 * Copyright (C) 2006-2010 Jürg Billeter 4 * Copyright (C) 2006-2008 Raffaele Sandrini 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * 20 * Author: 21 * Raffaele Sandrini <raffaele@sandrini.ch> 22 * Jürg Billeter <j@bitron.ch> 23 */ 24 25using GLib; 26 27/** 28 * Represents an array creation expression. 29 * 30 * {{{ new int[] { 1, 2, 3 } }}} 31 */ 32public class Vala.ArrayCreationExpression : Expression { 33 /** 34 * The type of the elements of the array. 35 */ 36 public DataType element_type { 37 get { return _element_type; } 38 set { 39 _element_type = value; 40 _element_type.parent_node = this; 41 } 42 } 43 44 /** 45 * The length type. 46 */ 47 public DataType? length_type { 48 get { return _length_type; } 49 set { 50 _length_type = value; 51 if (_length_type != null) { 52 _length_type.parent_node = this; 53 } 54 } 55 } 56 57 /** 58 * The rank of the array. 59 */ 60 public int rank { get; set; } 61 62 /** 63 * The size for each dimension ascending from left to right. 64 */ 65 private List<Expression> sizes = new ArrayList<Expression> (); 66 67 /** 68 * The root array initializer list. 69 */ 70 public InitializerList? initializer_list { 71 get { return _initializer_list; } 72 set { 73 _initializer_list = value; 74 if (_initializer_list != null) { 75 _initializer_list.parent_node = this; 76 } 77 } 78 } 79 80 private DataType _element_type; 81 private DataType _length_type; 82 private InitializerList? _initializer_list; 83 84 /** 85 * Add a size expression. 86 */ 87 public void append_size (Expression size) { 88 sizes.add (size); 89 if (size != null) { 90 size.parent_node = this; 91 } 92 } 93 94 /** 95 * Get the sizes for all dimensions ascending from left to right. 96 */ 97 public unowned List<Expression> get_sizes () { 98 return sizes; 99 } 100 101 public ArrayCreationExpression (DataType element_type, int rank, InitializerList? initializer_list, SourceReference? source_reference = null) { 102 this.element_type = element_type; 103 this.rank = rank; 104 this.initializer_list = initializer_list; 105 this.source_reference = source_reference; 106 } 107 108 public override void accept_children (CodeVisitor visitor) { 109 if (element_type != null) { 110 element_type.accept (visitor); 111 } 112 113 if (length_type != null) { 114 length_type.accept (visitor); 115 } 116 117 foreach (Expression e in sizes) { 118 e.accept (visitor); 119 } 120 121 if (initializer_list != null) { 122 initializer_list.accept (visitor); 123 } 124 } 125 126 public override void accept (CodeVisitor visitor) { 127 visitor.visit_array_creation_expression (this); 128 129 visitor.visit_expression (this); 130 } 131 132 public override bool is_pure () { 133 return false; 134 } 135 136 public override bool is_accessible (Symbol sym) { 137 if (element_type != null && !element_type.is_accessible (sym)) { 138 return false; 139 } 140 141 if (length_type != null && !length_type.is_accessible (sym)) { 142 return false; 143 } 144 145 foreach (Expression e in sizes) { 146 if (!e.is_accessible (sym)) { 147 return false; 148 } 149 } 150 151 if (initializer_list != null) { 152 return initializer_list.is_accessible (sym); 153 } 154 155 return true; 156 } 157 158 public override string to_string () { 159 var builder = new StringBuilder ("new "); 160 builder.append_printf ("%s[", element_type.to_string ()); 161 bool first = true; 162 foreach (var size in sizes) { 163 if (first) { 164 builder.append (size.to_string ()); 165 first = false; 166 } else { 167 builder.append_printf (", %s", size.to_string ()); 168 } 169 } 170 builder.append_c (']'); 171 if (initializer_list != null) { 172 builder.append (initializer_list.to_string ()); 173 } 174 return builder.str; 175 } 176 177 public override void replace_expression (Expression old_node, Expression new_node) { 178 for (int i = 0; i < sizes.size; i++) { 179 if (sizes[i] == old_node) { 180 sizes[i] = new_node; 181 new_node.parent_node = this; 182 return; 183 } 184 } 185 } 186 187 public override void replace_type (DataType old_type, DataType new_type) { 188 if (element_type == old_type) { 189 element_type = new_type; 190 } 191 if (length_type == old_type) { 192 length_type = new_type; 193 } 194 } 195 196 private int create_sizes_from_initializer_list (CodeContext context, InitializerList il, int rank, List<Literal> sl) { 197 if (sl.size == (this.rank - rank)) { 198 // only add size if this is the first initializer list of the current dimension 199 var init = new IntegerLiteral (il.size.to_string (), il.source_reference); 200 init.check (context); 201 sl.add (init); 202 } 203 204 int subsize = -1; 205 foreach (Expression e in il.get_initializers ()) { 206 if (e is InitializerList && e.target_type is ArrayType) { 207 if (rank == 1) { 208 il.error = true; 209 e.error = true; 210 Report.error (e.source_reference, "Expected array element, got array initializer list"); 211 return -1; 212 } 213 int size = create_sizes_from_initializer_list (context, (InitializerList) e, rank - 1, sl); 214 if (size == -1) { 215 return -1; 216 } 217 if (subsize >= 0 && subsize != size) { 218 il.error = true; 219 Report.error (il.source_reference, "Expected initializer list of size %d, got size %d".printf (subsize, size)); 220 return -1; 221 } else { 222 subsize = size; 223 } 224 } else { 225 if (rank != 1) { 226 il.error = true; 227 e.error = true; 228 Report.error (e.source_reference, "Expected array initializer list, got array element"); 229 return -1; 230 } 231 } 232 } 233 return il.size; 234 } 235 236 public override bool check (CodeContext context) { 237 if (checked) { 238 return !error; 239 } 240 241 checked = true; 242 243 List<Expression> sizes = get_sizes (); 244 var initlist = initializer_list; 245 246 if (element_type != null) { 247 element_type.check (context); 248 249 // check whether there is the expected amount of type-arguments 250 if (!element_type.check_type_arguments (context, true)) { 251 error = true; 252 return false; 253 } 254 } 255 256 if (length_type == null) { 257 // Make sure that "int" is still picked up as default 258 length_type = context.analyzer.int_type.copy (); 259 } else { 260 length_type.check (context); 261 if (!(length_type is IntegerType) || length_type.nullable) { 262 error = true; 263 Report.error (length_type.source_reference, "Expected integer type as length type of array"); 264 } 265 } 266 267 foreach (Expression e in sizes) { 268 e.check (context); 269 } 270 271 var calc_sizes = new ArrayList<Literal> (); 272 if (initlist != null) { 273 initlist.target_type = new ArrayType (element_type, rank, source_reference); 274 ((ArrayType) initlist.target_type).length_type = length_type.copy (); 275 276 if (!initlist.check (context)) { 277 error = true; 278 } 279 280 var ret = create_sizes_from_initializer_list (context, initlist, rank, calc_sizes); 281 if (ret == -1) { 282 error = true; 283 } 284 285 if (calc_sizes.size != rank) { 286 error = true; 287 var actual_type = new ArrayType (element_type, calc_sizes.size, source_reference); 288 ((ArrayType) actual_type).length_type = length_type; 289 Report.error (initlist.source_reference, "Expected initializer for `%s' but got `%s'".printf (target_type.to_string (), actual_type.to_string ())); 290 } 291 } 292 293 if (sizes.size > 0) { 294 /* check for errors in the size list */ 295 foreach (Expression e in sizes) { 296 if (e.value_type == null) { 297 /* return on previous error */ 298 return false; 299 } else if (!(e.value_type is IntegerType || e.value_type is EnumValueType)) { 300 error = true; 301 Report.error (e.source_reference, "Expression of integer type expected"); 302 } 303 } 304 } else { 305 if (initlist == null) { 306 error = true; 307 /* this is an internal error because it is already handled by the parser */ 308 Report.error (source_reference, "internal error: initializer list expected"); 309 } else { 310 foreach (Expression size in calc_sizes) { 311 append_size (size); 312 } 313 } 314 } 315 316 if (error) { 317 return false; 318 } 319 320 /* check for wrong elements inside the initializer */ 321 if (initializer_list != null && initializer_list.value_type == null) { 322 return false; 323 } 324 325 /* try to construct the type of the array */ 326 if (element_type == null) { 327 error = true; 328 Report.error (source_reference, "Cannot determine the element type of the created array"); 329 return false; 330 } 331 332 value_type = new ArrayType (element_type, rank, source_reference); 333 ((ArrayType) value_type).length_type = length_type.copy (); 334 if (formal_target_type is ArrayType) { 335 ((ArrayType) value_type).fixed_length = ((ArrayType) formal_target_type).fixed_length; 336 ((ArrayType) value_type).inline_allocated = ((ArrayType) formal_target_type).inline_allocated; 337 } 338 value_type.value_owned = true; 339 340 if (!value_type.check (context)) { 341 return false; 342 } 343 344 return !error; 345 } 346 347 public override void emit (CodeGenerator codegen) { 348 foreach (Expression e in sizes) { 349 e.emit (codegen); 350 } 351 352 if (initializer_list != null) { 353 initializer_list.emit (codegen); 354 } 355 356 codegen.visit_array_creation_expression (this); 357 358 codegen.visit_expression (this); 359 } 360 361 public override void get_used_variables (Collection<Variable> collection) { 362 foreach (Expression e in sizes) { 363 e.get_used_variables (collection); 364 } 365 366 if (initializer_list != null) { 367 initializer_list.get_used_variables (collection); 368 } 369 } 370} 371