glib-2.0: Add g_unichar_ismark binding
[vala-lang.git] / vala / valadatatype.vala
blob9521aee71cc9907d6050c02a693c7f8bad748797
1 /* valadatatype.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
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.
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.
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
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using GLib;
27 /**
28 * A reference to a data type. This is used to specify static types of
29 * expressions.
31 public abstract class Vala.DataType : CodeNode {
32 /**
33 * Specifies that the expression or variable owns the value.
35 public bool value_owned { get; set; }
37 /**
38 * Specifies that the expression may be null.
40 public bool nullable { get; set; }
42 /**
43 * The referred data type.
45 public weak TypeSymbol data_type { get; set; }
47 /**
48 * The referred generic type parameter.
50 public TypeParameter type_parameter { get; set; }
52 /**
53 * Specifies that the expression transfers a floating reference.
55 public bool floating_reference { get; set; }
57 /**
58 * Specifies that the type supports dynamic lookup.
60 public bool is_dynamic { get; set; }
62 private List<DataType> type_argument_list;
63 private static List<DataType> _empty_type_list;
65 /**
66 * Appends the specified type as generic type argument.
68 * @param arg a type reference
70 public void add_type_argument (DataType arg) {
71 if (type_argument_list == null) {
72 type_argument_list = new ArrayList<DataType> ();
74 type_argument_list.add (arg);
75 arg.parent_node = this;
78 /**
79 * Returns a copy of the list of generic type arguments.
81 * @return type argument list
83 public List<DataType> get_type_arguments () {
84 if (type_argument_list != null) {
85 return type_argument_list;
87 if (_empty_type_list == null) {
88 _empty_type_list = new ArrayList<DataType> ();
90 return _empty_type_list;
93 public bool has_type_arguments () {
94 if (type_argument_list == null) {
95 return false;
98 return type_argument_list.size > 0;
102 * Removes all generic type arguments.
104 public void remove_all_type_arguments () {
105 type_argument_list = null;
108 public override void accept (CodeVisitor visitor) {
109 if (type_argument_list != null && type_argument_list.size > 0) {
110 foreach (DataType type_arg in type_argument_list) {
111 type_arg.accept (visitor);
115 visitor.visit_data_type (this);
119 * Returns the name and qualifiers of this type as it is used in C code.
121 * @return the type string to be used in C code
123 public virtual string? get_cname () {
124 // raise error
125 Report.error (source_reference, "unresolved type reference");
126 return null;
129 public virtual string get_cdeclarator_suffix () {
130 return "";
134 * Returns the name and qualifiers of this type as it is used in C code
135 * in a const declaration.
137 * @return the type string to be used in C code const declarations
139 public string get_const_cname () {
140 string ptr;
141 TypeSymbol t;
142 // FIXME: workaround to make constant arrays possible
143 if (this is ArrayType) {
144 t = ((ArrayType) this).element_type.data_type;
145 } else {
146 t = data_type;
148 if (!t.is_reference_type ()) {
149 ptr = "";
150 } else {
151 ptr = "*";
154 return "const %s%s".printf (t.get_cname (), ptr);
158 * Returns the C name of this data type in lower case. Words are
159 * separated by underscores.
161 * @param infix a string to be placed between namespace and data type
162 * name or null
163 * @return the lower case name to be used in C code
165 public virtual string? get_lower_case_cname (string? infix = null) {
166 return data_type.get_lower_case_cname (infix);
169 public override string to_string () {
170 return to_qualified_string (null);
173 public virtual string to_qualified_string (Scope? scope = null) {
174 // logic temporarily duplicated in DelegateType class
176 string s;
178 if (data_type != null) {
179 Symbol global_symbol = data_type;
180 while (global_symbol.parent_symbol.name != null) {
181 global_symbol = global_symbol.parent_symbol;
184 Symbol sym = null;
185 Scope parent_scope = scope;
186 while (sym == null && parent_scope != null) {
187 sym = parent_scope.lookup (global_symbol.name);
188 parent_scope = parent_scope.parent_scope;
191 if (sym != null && global_symbol != sym) {
192 s = "global::" + data_type.get_full_name ();;
193 } else {
194 s = data_type.get_full_name ();
196 } else {
197 s = "null";
200 var type_args = get_type_arguments ();
201 if (type_args.size > 0) {
202 s += "<";
203 bool first = true;
204 foreach (DataType type_arg in type_args) {
205 if (!first) {
206 s += ",";
207 } else {
208 first = false;
210 if (!type_arg.value_owned) {
211 s += "weak ";
213 s += type_arg.to_qualified_string (scope);
215 s += ">";
217 if (nullable) {
218 s += "?";
221 return s;
225 * Creates a shallow copy of this type reference.
227 * @return copy of this type reference
229 public abstract DataType copy ();
232 * Checks two type references for equality. May only be used with
233 * resolved type references.
235 * @param type2 a type reference
236 * @return true if this type reference is equal to type2, false
237 * otherwise
239 public virtual bool equals (DataType type2) {
240 if (type2.is_disposable () != is_disposable ()) {
241 return false;
243 if (type2.nullable != nullable) {
244 return false;
246 if (type2.data_type != data_type) {
247 return false;
249 if (type2.type_parameter != null || type_parameter != null) {
250 if (type2.type_parameter == null || type_parameter == null) {
251 return false;
253 if (!type2.type_parameter.equals (type_parameter)) {
254 return false;
257 if (type2.floating_reference != floating_reference) {
258 return false;
261 return true;
265 * Checks whether this type reference is at least as strict as the
266 * specified type reference type2.
268 * @param type2 a type reference
269 * @return true if this type reference is stricter or equal
271 public virtual bool stricter (DataType type2) {
272 if (type2.is_disposable () != is_disposable ()) {
273 return false;
276 if (!type2.nullable && nullable) {
277 return false;
280 /* temporarily ignore type parameters */
281 if (type_parameter != null || type2.type_parameter != null) {
282 return true;
285 if (type2.data_type != data_type) {
286 // FIXME: allow this type reference to refer to a
287 // subtype of the type type2 is referring to
288 return false;
291 if (type2.floating_reference != floating_reference) {
292 return false;
295 return true;
298 public override void replace_type (DataType old_type, DataType new_type) {
299 if (type_argument_list != null) {
300 for (int i = 0; i < type_argument_list.size; i++) {
301 if (type_argument_list[i] == old_type) {
302 type_argument_list[i] = new_type;
303 return;
309 public virtual bool compatible (DataType target_type) {
310 if (CodeContext.get ().experimental_non_null && nullable && !target_type.nullable) {
311 return false;
314 if (target_type.get_type_id () == "G_TYPE_VALUE" && get_type_id () != null) {
315 // allow implicit conversion to GValue
316 return true;
319 if (target_type.get_type_id () == "G_TYPE_VARIANT") {
320 // allow implicit conversion to GVariant
321 return true;
324 if (this is ValueType && target_type.data_type != null && target_type.data_type.get_full_name () == "Dova.Value") {
325 // allow implicit conversion to Dova.Value
326 return true;
329 if (target_type is DelegateType && this is DelegateType) {
330 return ((DelegateType) target_type).delegate_symbol == ((DelegateType) this).delegate_symbol;
333 if (target_type is PointerType) {
334 /* any reference or array type or pointer type can be cast to a generic pointer */
335 if (type_parameter != null ||
336 (data_type != null && (
337 data_type.is_reference_type () ||
338 this is DelegateType))) {
339 return true;
342 return false;
345 /* temporarily ignore type parameters */
346 if (target_type.type_parameter != null) {
347 return true;
350 if (this is ArrayType != target_type is ArrayType) {
351 return false;
354 if (data_type is Enum && target_type.data_type is Struct && ((Struct) target_type.data_type).is_integer_type ()) {
355 return true;
358 if (data_type == target_type.data_type) {
359 // check compatibility of generic type arguments
360 if (type_argument_list != null
361 && type_argument_list.size > 0
362 && type_argument_list.size == target_type.get_type_arguments ().size) {
363 for (int i = 0; i < type_argument_list.size; i++) {
364 var type_arg = type_argument_list[i];
365 var target_type_arg = target_type.get_type_arguments ()[i];
366 // mutable generic types require type argument equality,
367 // not just one way compatibility
368 // as we do not currently have immutable generic container types,
369 // the additional check would be very inconvenient, so we
370 // skip the additional check for now
371 if (!type_arg.compatible (target_type_arg)) {
372 return false;
376 return true;
379 if (data_type is Struct && target_type.data_type is Struct) {
380 var expr_struct = (Struct) data_type;
381 var expect_struct = (Struct) target_type.data_type;
383 /* integer types may be implicitly cast to floating point types */
384 if (expr_struct.is_integer_type () && expect_struct.is_floating_type ()) {
385 return true;
388 if ((expr_struct.is_integer_type () && expect_struct.is_integer_type ()) ||
389 (expr_struct.is_floating_type () && expect_struct.is_floating_type ())) {
390 if (expr_struct.get_rank () <= expect_struct.get_rank ()) {
391 return true;
396 if (data_type != null && target_type.data_type != null && data_type.is_subtype_of (target_type.data_type)) {
397 return true;
400 return false;
404 * Returns whether instances of this type are invokable.
406 * @return true if invokable, false otherwise
408 public virtual bool is_invokable () {
409 return false;
413 * Returns the return type of this invokable.
415 * @return return type
417 public virtual DataType? get_return_type () {
418 return null;
422 * Returns copy of the list of invocation parameters.
424 * @return parameter list
426 public virtual List<Parameter>? get_parameters () {
427 return null;
430 public virtual bool is_reference_type_or_type_parameter () {
431 return (data_type != null &&
432 data_type.is_reference_type ()) ||
433 type_parameter != null;
436 public virtual bool is_array () {
437 return false;
440 // check whether this type is at least as accessible as the specified symbol
441 public virtual bool is_accessible (Symbol sym) {
442 if (data_type != null) {
443 return data_type.is_accessible (sym);
445 return true;
448 public virtual Symbol? get_member (string member_name) {
449 if (data_type != null) {
450 return SemanticAnalyzer.symbol_lookup_inherited (data_type, member_name);
452 return null;
455 public virtual Symbol? get_pointer_member (string member_name) {
456 return null;
460 * Checks whether this data type references a real struct. A real struct
461 * is a struct which is not a simple (fundamental) type.
463 public virtual bool is_real_struct_type () {
464 var s = data_type as Struct;
465 if (s != null && !s.is_simple_type ()) {
466 return true;
468 return false;
471 public bool is_real_non_null_struct_type () {
472 return is_real_struct_type () && !nullable;
475 public virtual string? get_type_id () {
476 if (data_type != null) {
477 return data_type.get_type_id ();
478 } else {
479 return null;
484 * Returns whether the value needs to be disposed, i.e. whether
485 * allocated memory or other resources need to be released when
486 * the value is no longer needed.
488 public virtual bool is_disposable () {
489 if (!value_owned) {
490 return false;
493 if (is_reference_type_or_type_parameter ()) {
494 return true;
496 return false;
499 public virtual DataType get_actual_type (DataType? derived_instance_type, MemberAccess? method_access, CodeNode node_reference) {
500 if (derived_instance_type == null && method_access == null) {
501 return this;
504 DataType result = this;
506 if (result is GenericType) {
507 result = SemanticAnalyzer.get_actual_type (derived_instance_type, method_access, (GenericType) result, node_reference);
508 // don't try to resolve type arguments of returned actual type
509 // they can never be resolved and are not related to the instance type
510 } else if (result.type_argument_list != null) {
511 // recursely get actual types for type arguments
512 result = result.copy ();
513 for (int i = 0; i < result.type_argument_list.size; i++) {
514 result.type_argument_list[i] = result.type_argument_list[i].get_actual_type (derived_instance_type, method_access, node_reference);
518 return result;
521 public bool is_weak () {
522 if (this.value_owned) {
523 return false;
524 } else if (this is VoidType || this is PointerType) {
525 return false;
526 } else if (this is ValueType) {
527 if (this.nullable) {
528 // nullable structs are heap allocated
529 return true;
532 // TODO return true for structs with destroy
533 return false;
536 return true;