valaarraytype.vala 7.73 KB
Newer Older
1 2
/* valaarraytype.vala
 *
3
 * Copyright (C) 2007-2012  Jürg Billeter
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.

 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 * Author:
 * 	Jürg Billeter <j@bitron.ch>
 */

using GLib;

/**
 * An array type.
 */
28
public class Vala.ArrayType : ReferenceType {
29 30 31
	/**
	 * The element type.
	 */
32 33 34
	public DataType element_type {
		get { return _element_type; }
		set {
35
			_element_type = value;
36 37 38
			_element_type.parent_node = this;
		}
	}
39

40 41 42 43
	public bool invalid_syntax { get; set; }

	public bool inline_allocated { get; set; }

44 45 46 47 48
	public bool fixed_length { get; set; }

	/**
	 * The length of this fixed-length array.
	 */
49 50 51 52 53 54 55 56 57
	public Expression? length {
		get { return _length; }
		set {
			_length = value;
			if (_length != null) {
				_length.parent_node = this;
			}
		}
	}
58

Jürg Billeter's avatar
Jürg Billeter committed
59 60 61
	/**
	 * The rank of this array.
	 */
62 63 64
	public int rank { get; set; }

	private DataType _element_type;
65
	private Expression _length;
66

67 68 69
	private ArrayLengthField length_field;
	private ArrayResizeMethod resize_method;
	private ArrayMoveMethod move_method;
Jürg Billeter's avatar
Jürg Billeter committed
70

71
	public ArrayType (DataType element_type, int rank, SourceReference? source_reference) {
72 73 74
		this.element_type = element_type;
		this.rank = rank;
		this.source_reference = source_reference;
Jürg Billeter's avatar
Jürg Billeter committed
75 76
	}

77
	public override Symbol? get_member (string member_name) {
78
		if (member_name == "length") {
79 80 81 82
			return get_length_field ();
		} else if (member_name == "move") {
			return get_move_method ();
		} else if (member_name == "resize") {
83 84 85
			if (rank > 1) {
				return null;
			}
86
			return get_resize_method ();
Jürg Billeter's avatar
Jürg Billeter committed
87
		}
88 89 90 91 92 93 94 95 96 97 98 99
		return null;
	}

	private ArrayLengthField get_length_field () {
		if (length_field == null) {
			length_field = new ArrayLengthField (source_reference);

			length_field.access = SymbolAccessibility.PUBLIC;

			var root_symbol = source_reference.file.context.root;
			if (rank > 1) {
				// length is an int[] containing the dimensions of the array, starting at 0
100
				ValueType integer = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
Jürg Billeter's avatar
Jürg Billeter committed
101
				length_field.variable_type = new ArrayType (integer, 1, source_reference);
102
			} else {
Jürg Billeter's avatar
Jürg Billeter committed
103
				length_field.variable_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
104 105 106 107 108 109 110 111 112 113 114 115 116
			}

		}
		return length_field;
	}

	private ArrayResizeMethod get_resize_method () {
		if (resize_method == null) {
			resize_method = new ArrayResizeMethod (source_reference);

			resize_method.return_type = new VoidType ();
			resize_method.access = SymbolAccessibility.PUBLIC;

117
			resize_method.set_attribute_string ("CCode", "cname", "g_renew");
118 119
			
			var root_symbol = source_reference.file.context.root;
120
			var int_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
121

122
			resize_method.add_parameter (new Parameter ("length", int_type));
123 124 125 126 127 128 129 130 131 132 133 134 135
			
			resize_method.returns_modified_pointer = true;
		}
		return resize_method;
	}

	private ArrayMoveMethod get_move_method () {
		if (move_method == null) {
			move_method = new ArrayMoveMethod (source_reference);

			move_method.return_type = new VoidType ();
			move_method.access = SymbolAccessibility.PUBLIC;

136
			move_method.set_attribute_string ("CCode", "cname", "_vala_array_move");
137 138

			var root_symbol = source_reference.file.context.root;
139
			var int_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
140

141 142 143
			move_method.add_parameter (new Parameter ("src", int_type));
			move_method.add_parameter (new Parameter ("dest", int_type));
			move_method.add_parameter (new Parameter ("length", int_type));
144 145
		}
		return move_method;
Jürg Billeter's avatar
Jürg Billeter committed
146 147
	}

148
	public override DataType copy () {
149
		var result = new ArrayType (element_type.copy (), rank, source_reference);
150
		result.value_owned = value_owned;
Jürg Billeter's avatar
Jürg Billeter committed
151 152
		result.nullable = nullable;
		result.floating_reference = floating_reference;
153

154
		result.inline_allocated = inline_allocated;
155 156 157 158 159
		if (fixed_length) {
			result.fixed_length = true;
			result.length = length;
		}

Jürg Billeter's avatar
Jürg Billeter committed
160 161 162 163 164
		return result;
	}

	public override bool is_array () {
		return true;
165
	}
166

167
	public override string to_qualified_string (Scope? scope) {
168
		var elem_str = element_type.to_qualified_string (scope);
169
		if (element_type.is_weak () && !(parent_node is Constant)) {
170 171 172
			elem_str = "(unowned %s)".printf (elem_str);
		}
		
173
		if (!fixed_length) {
174
			return "%s[%s]%s".printf (elem_str, string.nfill (rank - 1, ','), nullable ? "?" : "");
175
		} else {
176
			return elem_str;
177
		}
178 179
	}

180
	public override bool compatible (DataType target_type) {
Jürg Billeter's avatar
Jürg Billeter committed
181
		if (target_type.data_type != null) {
182 183 184 185
			if (target_type.data_type.is_subtype_of (CodeContext.get ().analyzer.gvalue_type.data_type) && element_type.data_type == CodeContext.get ().root.scope.lookup ("string")) {
				// allow implicit conversion from string[] to GValue
				return true;
			}
186

187 188 189 190
			if (target_type.data_type.is_subtype_of (CodeContext.get ().analyzer.gvariant_type.data_type)) {
				// allow implicit conversion to GVariant
				return true;
			}
191 192
		}

193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
		if (target_type is PointerType || (target_type.data_type != null && target_type.data_type.get_attribute ("PointerType") != null)) {
			/* any array type can be cast to a generic pointer */
			return true;
		}

		/* temporarily ignore type parameters */
		if (target_type.type_parameter != null) {
			return true;
		}

		var target_array_type = target_type as ArrayType;
		if (target_array_type == null) {
			return false;
		}

208 209 210 211
		if (target_array_type.rank != rank) {
			return false;
		}

212
		if (element_type is ValueType && element_type.nullable != target_array_type.element_type.nullable) {
213 214 215
			return false;
		}

216 217 218 219 220 221 222 223 224 225 226
		if (element_type.compatible (target_array_type.element_type)
		    && target_array_type.element_type.compatible (element_type)) {
			return true;
		}

		return false;
	}

	public override bool is_reference_type_or_type_parameter () {
		return true;
	}
227

228 229 230 231 232 233 234 235 236
	public override void accept_children (CodeVisitor visitor) {
		element_type.accept (visitor);
	}

	public override void replace_type (DataType old_type, DataType new_type) {
		if (element_type == old_type) {
			element_type = new_type;
		}
	}
237

238 239
	public override bool is_accessible (Symbol sym) {
		return element_type.is_accessible (sym);
240
	}
241

242
	public override bool check (CodeContext context) {
243 244 245 246 247
		if (invalid_syntax) {
			Report.error (source_reference, "syntax error, no expression allowed between array brackets");
			error = true;
			return false;
		}
248 249 250 251 252 253 254 255 256 257

		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;
			}
		}

258
		return element_type.check (context);
259
	}
260

261
	public override DataType get_actual_type (DataType? derived_instance_type, MemberAccess? method_access, CodeNode node_reference) {
262 263
		ArrayType result = (ArrayType) this.copy ();

264
		if (derived_instance_type == null && method_access == null) {
265
			return result;
266 267 268 269 270 271 272 273 274
		}

		if (element_type is GenericType || element_type.has_type_arguments ()) {
			result.element_type = result.element_type.get_actual_type (derived_instance_type, method_access, node_reference);
		}

		return result;
	}

275 276 277 278 279 280 281
	public override bool is_disposable () {
		if (fixed_length) {
			return element_type.is_disposable ();
		} else {
			return base.is_disposable ();
		}
	}
282
}