Add experimental support for main blocks
[vala-lang.git] / vala / valafield.vala
blobed7e091bf34e462e346e9036cf05fbd3faafb456
1 /* valafield.vala
3 * Copyright (C) 2006-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 * Represents a type or namespace field.
28 public class Vala.Field : Member, Lockable {
29 /**
30 * The data type of this field.
32 public DataType field_type {
33 get { return _data_type; }
34 set {
35 _data_type = value;
36 _data_type.parent_node = this;
40 /**
41 * Specifies the expression to be used to initialize this field.
43 public Expression? initializer {
44 get { return _initializer; }
45 set {
46 _initializer = value;
47 if (_initializer != null) {
48 _initializer.parent_node = this;
53 /**
54 * Specifies whether this field may only be accessed with an instance of
55 * the contained type.
57 public MemberBinding binding { get; set; default = MemberBinding.INSTANCE; }
59 /**
60 * Specifies whether the field is volatile. Volatile fields are
61 * necessary to allow multi-threaded access.
63 public bool is_volatile { get; set; }
65 /**
66 * Specifies whether an array length field should implicitly be created
67 * if the field type is an array.
69 public bool no_array_length { get; set; }
71 /**
72 * Specifies whether a delegate target field should implicitly be created
73 * if the field type is a delegate.
75 public bool no_delegate_target { get; set; }
77 /**
78 * Specifies whether the array is null terminated.
80 public bool array_null_terminated { get; set; }
82 /**
83 * Specifies whether the array length field uses a custom name in C.
85 public bool has_array_length_cname {
86 get { return (array_length_cname != null); }
89 /**
90 * Specifies whether the array uses a custom C expression as length.
92 public bool has_array_length_cexpr {
93 get { return (array_length_cexpr != null); }
96 /**
97 * Specifies a custom type for the array length.
99 public string? array_length_type { get; set; default = null; }
101 private string? array_length_cname;
103 private string? array_length_cexpr;
105 private string cname;
107 private bool lock_used = false;
109 private Expression _initializer;
111 private DataType _data_type;
114 * Creates a new field.
116 * @param name field name
117 * @param type field type
118 * @param init initializer expression
119 * @param source reference to source code
120 * @return newly created field
122 public Field (string name, DataType field_type, Expression? initializer, SourceReference? source_reference = null, Comment? comment = null) {
123 base (name, source_reference, comment);
124 this.field_type = field_type;
125 this.initializer = initializer;
128 public override void accept (CodeVisitor visitor) {
129 visitor.visit_member (this);
131 visitor.visit_field (this);
134 public override void accept_children (CodeVisitor visitor) {
135 field_type.accept (visitor);
137 if (initializer != null) {
138 initializer.accept (visitor);
143 * Returns the name of this field as it is used in C code.
145 * @return the name to be used in C code
147 public string get_cname () {
148 if (cname == null) {
149 cname = get_default_cname ();
151 return cname;
155 * Sets the name of this field as it is used in C code.
157 * @param cname the name to be used in C code
159 public void set_cname (string cname) {
160 this.cname = cname;
164 * Returns the default name of this field as it is used in C code.
166 * @return the name to be used in C code by default
168 public string get_default_cname () {
169 if (binding == MemberBinding.STATIC) {
170 return parent_symbol.get_lower_case_cprefix () + name;
171 } else {
172 return name;
177 * Returns the name of the array length field as it is used in C code
179 * @return the name of the array length field to be used in C code
181 public string? get_array_length_cname () {
182 return this.array_length_cname;
186 * Sets the name of the array length field as it is used in C code
188 * @param array_length_cname the name of the array length field to be
189 * used in C code
191 public void set_array_length_cname (string? array_length_cname) {
192 this.array_length_cname = array_length_cname;
196 * Returns the array length expression as it is used in C code
198 * @return the array length expression to be used in C code
200 public string? get_array_length_cexpr () {
201 return this.array_length_cexpr;
206 * Sets the array length expression as it is used in C code
208 * @param array_length_cexpr the array length expression to be used in C
209 * code
211 public void set_array_length_cexpr (string? array_length_cexpr) {
212 this.array_length_cexpr = array_length_cexpr;
215 private void process_ccode_attribute (Attribute a) {
216 if (a.has_argument ("cname")) {
217 set_cname (a.get_string ("cname"));
219 if (a.has_argument ("cheader_filename")) {
220 var val = a.get_string ("cheader_filename");
221 foreach (string filename in val.split (",")) {
222 add_cheader_filename (filename);
225 if (a.has_argument ("array_length")) {
226 no_array_length = !a.get_bool ("array_length");
228 if (a.has_argument ("array_null_terminated")) {
229 array_null_terminated = a.get_bool ("array_null_terminated");
231 if (a.has_argument ("array_length_cname")) {
232 set_array_length_cname (a.get_string ("array_length_cname"));
234 if (a.has_argument ("array_length_cexpr")) {
235 set_array_length_cexpr (a.get_string ("array_length_cexpr"));
237 if (a.has_argument ("array_length_type")) {
238 array_length_type = a.get_string ("array_length_type");
240 if (a.has_argument ("delegate_target")) {
241 no_delegate_target = !a.get_bool ("delegate_target");
246 * Process all associated attributes.
248 public void process_attributes () {
249 foreach (Attribute a in attributes) {
250 if (a.name == "CCode") {
251 process_ccode_attribute (a);
252 } else if (a.name == "Deprecated") {
253 process_deprecated_attribute (a);
258 public bool get_lock_used () {
259 return lock_used;
262 public void set_lock_used (bool used) {
263 lock_used = used;
266 public override void replace_expression (Expression old_node, Expression new_node) {
267 if (initializer == old_node) {
268 initializer = new_node;
272 public override void replace_type (DataType old_type, DataType new_type) {
273 if (field_type == old_type) {
274 field_type = new_type;
278 public string? get_ctype () {
279 var attr = get_attribute ("CCode");
280 if (attr == null) {
281 return null;
283 return attr.get_string ("type");
286 public void set_ctype (string ctype) {
287 var attr = get_attribute ("CCode");
288 if (attr == null) {
289 attr = new Attribute ("CCode");
290 attributes.append (attr);
292 attr.add_argument ("type", new StringLiteral ("\"%s\"".printf (ctype)));
295 public override bool check (SemanticAnalyzer analyzer) {
296 if (checked) {
297 return !error;
300 checked = true;
302 var old_source_file = analyzer.current_source_file;
303 var old_symbol = analyzer.current_symbol;
305 if (source_reference != null) {
306 analyzer.current_source_file = source_reference.file;
308 analyzer.current_symbol = this;
310 field_type.check (analyzer);
312 // check whether field type is at least as accessible as the field
313 if (!analyzer.is_type_accessible (this, field_type)) {
314 error = true;
315 Report.error (source_reference, "field type `%s` is less accessible than field `%s`".printf (field_type.to_string (), get_full_name ()));
316 return false;
319 process_attributes ();
321 if (initializer != null) {
322 initializer.target_type = field_type;
324 if (!initializer.check (analyzer)) {
325 error = true;
326 return false;
329 if (initializer.value_type == null) {
330 error = true;
331 Report.error (source_reference, "expression type not allowed as initializer");
332 return false;
335 if (!initializer.value_type.compatible (field_type)) {
336 error = true;
337 Report.error (source_reference, "Cannot convert from `%s' to `%s'".printf (initializer.value_type.to_string (), field_type.to_string ()));
338 return false;
341 if (external) {
342 error = true;
343 Report.error (source_reference, "External fields cannot use initializers");
347 if (binding == MemberBinding.INSTANCE && parent_symbol is Interface) {
348 error = true;
349 Report.error (source_reference, "Interfaces may not have instance fields");
350 return false;
353 bool field_in_header = !is_internal_symbol ();
354 if (parent_symbol is Class) {
355 var cl = (Class) parent_symbol;
356 if (cl.is_compact && !cl.is_internal_symbol ()) {
357 // compact classes don't have priv structs
358 field_in_header = true;
362 if (!external_package && !hides && get_hidden_member () != null) {
363 Report.warning (source_reference, "%s hides inherited field `%s'. Use the `new' keyword if hiding was intentional".printf (get_full_name (), get_hidden_member ().get_full_name ()));
366 analyzer.current_source_file = old_source_file;
367 analyzer.current_symbol = old_symbol;
369 return !error;