valaclass.vala 13.4 KB
Newer Older
1
2
/* valaclass.vala
 *
3
 * Copyright (C) 2006-2007  Jürg Billeter
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 *
 * 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 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;
24
using Gee;
25

26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
 * Represents a class declaration in the source code.
 */
public class Vala.Class : DataType {
	/**
	 * Specifies the base class.
	 */
	public Class base_class { get; set; }
	
	/**
	 * Specifies whether this class is abstract. Abstract classes may not be
	 * instantiated.
	 */
	public bool is_abstract { get; set; }
40
41
42
43
44
45
46

	/**
	 * Specifies whether this class is static. Static classes may not be
	 * instantiated and may only contain static members.
	 */
	public bool is_static { get; set; }

47
48
49
50
51
52
	/**
	 * Specifies whether this class has private fields.
	 */
	public bool has_private_fields {
		get {
			return _has_private_fields;
53
		}
54
	}
55

56
	private string cname;
57
58
	private string const_cname;
	private string lower_case_cprefix;
59
	private string lower_case_csuffix;
60
	private string type_id;
61
62
63
64
65
66
67
68
	private string ref_function;
	private string unref_function;
	private string copy_function;
	private string free_function;
	private string marshaller_type_name;
	private string get_value_function;
	private string set_value_function;

69
70
	private bool _has_private_fields;
	
71
	private Gee.List<TypeParameter> type_parameters = new ArrayList<TypeParameter> ();
72

73
	private Gee.List<TypeReference> base_types = new ArrayList<TypeReference> ();
74

75
76
77
78
79
	private Gee.List<Constant> constants = new ArrayList<Constant> ();
	private Gee.List<Field> fields = new ArrayList<Field> ();
	private Gee.List<Method> methods = new ArrayList<Method> ();
	private Gee.List<Property> properties = new ArrayList<Property> ();
	private Gee.List<Signal> signals = new ArrayList<Signal> ();
80
81

	// inner types
82
83
	private Gee.List<Class> classes = new ArrayList<Class> ();
	private Gee.List<Struct> structs = new ArrayList<Struct> ();
84
	
85
86
87
88
89
	/**
	 * Specifies the default construction method.
	 */
	public Method default_construction_method { get; set; }
	
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
	/**
	 * Specifies the instance constructor.
	 */
	public Constructor constructor { get; set; }
	
	/**
	 * Specifies the instance destructor.
	 */
	public Destructor destructor { get; set; }
	
	/**
	 * Creates a new class.
	 *
	 * @param name   type name
	 * @param source reference to source code
	 * @return       newly created class
	 */
107
	public Class (construct string! name, construct SourceReference source_reference = null) {
108
	}
109

110
111
112
113
114
115
116
	/**
	 * Adds the specified class or interface to the list of base types of
	 * this class.
	 *
	 * @param type a class or interface reference
	 */
	public void add_base_type (TypeReference! type) {
117
		base_types.add (type);
118
119
120
121
122
123
124
	}

	/**
	 * Returns a copy of the base type list.
	 *
	 * @return list of base types
	 */
125
126
	public Collection<TypeReference> get_base_types () {
		return new ReadOnlyCollection<TypeReference> (base_types);
127
128
129
130
131
132
133
134
	}

	/**
	 * Appends the specified parameter to the list of type parameters.
	 *
	 * @param p a type parameter
	 */
	public void add_type_parameter (TypeParameter! p) {
135
		type_parameters.add (p);
136
		p.type = this;
137
		scope.add (p.name, p);
138
	}
139
140
141
142
143
144

	/**
	 * Returns a copy of the type parameter list.
	 *
	 * @return list of type parameters
	 */
145
146
	public Collection<TypeParameter> get_type_parameters () {
		return new ReadOnlyCollection<TypeParameter> (type_parameters);
147
148
	}

149
150
151
152
153
154
	/**
	 * Adds the specified constant as a member to this class.
	 *
	 * @param c a constant
	 */
	public void add_constant (Constant! c) {
155
		constants.add (c);
156
		scope.add (c.name, c);
157
158
159
160
161
162
163
164
	}
	
	/**
	 * Adds the specified field as a member to this class.
	 *
	 * @param f a field
	 */
	public void add_field (Field! f) {
165
166
		// non_null fields not yet supported due to initialization issues
		f.type_reference.non_null = false;
167
		fields.add (f);
168
		if (f.access == SymbolAccessibility.PRIVATE && f.instance) {
169
			_has_private_fields = true;
170
		}
171
		scope.add (f.name, f);
172
173
174
175
176
177
178
	}
	
	/**
	 * Returns a copy of the list of fields.
	 *
	 * @return list of fields
	 */
179
180
	public Collection<Field> get_fields () {
		return new ReadOnlyCollection<Field> (fields);
181
182
183
184
185
186
187
188
	}
	
	/**
	 * Adds the specified method as a member to this class.
	 *
	 * @param m a method
	 */
	public void add_method (Method! m) {
189
		if (m.instance || m is CreationMethod) {
190
191
192
193
194
195
196
197
			m.this_parameter = new FormalParameter ("this", new TypeReference ());
			m.this_parameter.type_reference.data_type = this;
			m.scope.add (m.this_parameter.name, m.this_parameter);
		}
		if (m is CreationMethod && m.name == null) {
			default_construction_method = m;
		}

198
		methods.add (m);
199
		scope.add (m.name, m);
200
201
202
203
204
205
206
	}
	
	/**
	 * Returns a copy of the list of methods.
	 *
	 * @return list of methods
	 */
207
208
	public Collection<Method> get_methods () {
		return new ReadOnlyCollection<Method> (methods);
209
210
211
212
213
214
215
	}
	
	/**
	 * Adds the specified property as a member to this class.
	 *
	 * @param prop a property
	 */
216
	public void add_property (Property! prop, bool no_field = false) {
217
		properties.add (prop);
218
219
220
221
222
		scope.add (prop.name, prop);

		prop.this_parameter = new FormalParameter ("this", new TypeReference ());
		prop.this_parameter.type_reference.data_type = this;
		prop.scope.add (prop.this_parameter.name, prop.this_parameter);
223
		
224
		if (!no_field && prop.set_accessor != null && prop.set_accessor.body == null &&
225
		    source_reference != null && !source_reference.file.pkg) {
226
			/* automatic property accessor body generation */
227
228
229
230
			var field_type = prop.type_reference.copy ();
			// non_null fields not yet supported due to initialization issues
			field_type.non_null = false;
			var f = new Field ("_%s".printf (prop.name), field_type, null, prop.source_reference);
231
			f.access = SymbolAccessibility.PRIVATE;
232
			add_field (f);
233
		}
234
235
236
237
238
239
240
	}
	
	/**
	 * Returns a copy of the list of properties.
	 *
	 * @return list of properties
	 */
241
242
	public Collection<Property> get_properties () {
		return new ReadOnlyCollection<Property> (properties);
243
244
245
246
247
248
249
250
	}
	
	/**
	 * Adds the specified signal as a member to this class.
	 *
	 * @param sig a signal
	 */
	public void add_signal (Signal! sig) {
251
		signals.add (sig);
252
		scope.add (sig.name, sig);
253
254
255
256
257
258
259
	}
	
	/**
	 * Returns a copy of the list of signals.
	 *
	 * @return list of signals
	 */
260
261
	public Collection<Signal> get_signals () {
		return new ReadOnlyCollection<Signal> (signals);
262
	}
263

264
265
266
267
268
269
	/**
	 * Adds the specified class as an inner class.
	 *
	 * @param cl a class
	 */
	public void add_class (Class! cl) {
270
		classes.add (cl);
271
272
273
274
275
276
277
278
279
		scope.add (cl.name, cl);
	}

	/**
	 * Adds the specified struct as an inner struct.
	 *
	 * @param st a struct
	 */
	public void add_struct (Struct! st) {
280
		structs.add (st);
281
282
283
		scope.add (st.name, st);
	}

284
	public override void accept (CodeVisitor! visitor) {
285
286
287
288
		visitor.visit_class (this);
	}

	public override void accept_children (CodeVisitor! visitor) {
289
290
		foreach (TypeReference type in base_types) {
			type.accept (visitor);
291
		}
292
293
294

		foreach (TypeParameter p in type_parameters) {
			p.accept (visitor);
295
296
		}
		
297
298
		foreach (Field f in fields) {
			f.accept (visitor);
299
300
		}
		
301
302
		foreach (Constant c in constants) {
			c.accept (visitor);
303
304
		}
		
305
306
		foreach (Method m in methods) {
			m.accept (visitor);
307
308
		}
		
309
310
		foreach (Property prop in properties) {
			prop.accept (visitor);
Jürg Billeter's avatar
Jürg Billeter committed
311
312
		}
		
313
314
		foreach (Signal sig in signals) {
			sig.accept (visitor);
315
316
		}
		
317
318
		if (constructor != null) {
			constructor.accept (visitor);
319
320
		}

321
322
		if (destructor != null) {
			destructor.accept (visitor);
323
		}
324
325
326
327
328
329
330
331
332
333
334
335
		
		foreach (Class cl in classes) {
			cl.accept (visitor);
		}
		
		foreach (Struct st in structs) {
			st.accept (visitor);
		}
	}

	public override string! get_cprefix () {
		return get_cname ();
336
	}
337

338
	public override string get_cname (bool const_type = false) {
339
340
341
342
		if (const_type && const_cname != null) {
			return const_cname;
		}

343
		if (cname == null) {
344
			cname = "%s%s".printf (parent_symbol.get_cprefix (), name);
345
		}
346
347
348
349
350
351
352
353
354
355
356
357
		return cname;
	}
	
	/**
	 * Sets the name of this class as it is used in C code.
	 *
	 * @param cname the name to be used in C code
	 */
	public void set_cname (string! cname) {
		this.cname = cname;
	}
	
358
	private string get_lower_case_csuffix () {
359
		if (lower_case_csuffix == null) {
360
			lower_case_csuffix = camel_case_to_lower_case (name);
361
		}
362
363
		return lower_case_csuffix;
	}
364

365
	public override string get_lower_case_cname (string infix) {
366
367
		if (infix == null) {
			infix = "";
368
		}
369
		return "%s%s%s".printf (parent_symbol.get_lower_case_cprefix (), infix, get_lower_case_csuffix ());
370
371
	}
	
372
	public override string! get_lower_case_cprefix () {
373
374
375
376
		if (lower_case_cprefix == null) {
			lower_case_cprefix = "%s_".printf (get_lower_case_cname (null));
		}
		return lower_case_cprefix;
377
378
	}
	
379
	public override string get_upper_case_cname (string infix) {
380
381
		return get_lower_case_cname (infix).up ();
	}
382

383
384
385
386
387
	public override bool is_reference_type () {
		return true;
	}
	
	private void process_ccode_attribute (Attribute! a) {
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
		if (a.has_argument ("ref_function")) {
			set_ref_function (a.get_string ("ref_function"));
		}
		if (a.has_argument ("unref_function")) {
			set_unref_function (a.get_string ("unref_function"));
		}
		if (a.has_argument ("copy_function")) {
			set_dup_function (a.get_string ("copy_function"));
		}
		if (a.has_argument ("free_function")) {
			set_free_function (a.get_string ("free_function"));
		}
		if (a.has_argument ("type_id")) {
			type_id = a.get_string ("type_id");
		}
		if (a.has_argument ("marshaller_type_name")) {
			marshaller_type_name = a.get_string ("marshaller_type_name");
		}
		if (a.has_argument ("get_value_function")) {
			get_value_function = a.get_string ("get_value_function");
		}
		if (a.has_argument ("set_value_function")) {
			set_value_function = a.get_string ("set_value_function");
		}

413
414
415
		if (a.has_argument ("cname")) {
			set_cname (a.get_string ("cname"));
		}
416
417
418
419
420
421
		if (a.has_argument ("const_cname")) {
			const_cname = a.get_string ("const_cname");
		}
		if (a.has_argument ("cprefix")) {
			lower_case_cprefix = a.get_string ("cprefix");
		}
422
423
424
		if (a.has_argument ("lower_case_csuffix")) {
			lower_case_csuffix = a.get_string ("lower_case_csuffix");
		}
425
426
427
428
		if (a.has_argument ("cheader_filename")) {
			var val = a.get_string ("cheader_filename");
			foreach (string filename in val.split (",")) {
				add_cheader_filename (filename);
429
430
			}
		}
431
432
433
434
435
436
437
438
439
	}
	
	/**
	 * Process all associated attributes.
	 */
	public void process_attributes () {
		foreach (Attribute a in attributes) {
			if (a.name == "CCode") {
				process_ccode_attribute (a);
440
441
			}
		}
442
	}
443

444
445
446
447
448
449
450
451
	public override string get_type_id () {
		if (type_id == null) {
			type_id = get_upper_case_cname ("TYPE_");
		}
		
		return type_id;
	}

452
453
454
455
	public void set_type_id (string! type_id) {
		this.type_id = type_id;
	}

456
	public override string get_marshaller_type_name () {
457
		if (marshaller_type_name == null) {
458
459
			if (base_class != null) {
				marshaller_type_name = base_class.get_marshaller_type_name ();
460
461
462
463
464
465
			} else {
				marshaller_type_name = "POINTER";
			}
		}

		return marshaller_type_name;
466
467
	}

468
	public override string get_get_value_function () {
469
		if (get_value_function == null) {
470
471
			if (base_class != null) {
				get_value_function = base_class.get_get_value_function ();
472
473
474
475
476
477
			} else {
				get_value_function = "g_value_get_pointer";
			}
		}

		return get_value_function;
478
479
480
	}
	
	public override string get_set_value_function () {
481
		if (set_value_function == null) {
482
483
			if (base_class != null) {
				set_value_function = base_class.get_set_value_function ();
484
485
486
487
488
489
			} else {
				set_value_function = "g_value_set_pointer";
			}
		}

		return set_value_function;
490
491
	}

492
	public override bool is_reference_counting () {
493
		return get_ref_function () != null;
494
495
496
	}
	
	public override string get_ref_function () {
497
498
		if (ref_function == null && base_class != null) {
			return base_class.get_ref_function ();
499
500
501
		} else {
			return ref_function;
		}
502
	}
503
504
505
506
507

	public void set_ref_function (string! name) {
		this.ref_function = name;
	}

508
	public override string get_unref_function () {
509
510
		if (unref_function == null && base_class != null) {
			return base_class.get_unref_function ();
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
		} else {
			return unref_function;
		}
	}

	public void set_unref_function (string! name) {
		this.unref_function = name;
	}

	public override string get_dup_function () {
		return copy_function;
	}

	public void set_dup_function (string! name) {
		this.copy_function = name;
	}

	public string get_default_free_function () {
529
		return get_lower_case_cprefix () + "free";
530
531
532
533
534
535
536
537
538
539
540
	}

	public override string get_free_function () {
		if (free_function == null) {
			free_function = get_default_free_function ();
		}
		return free_function;
	}
	
	public void set_free_function (string! name) {
		this.free_function = name;
541
	}
542
543
544
545
546
547
548
549
550
551
552
	
	public override bool is_subtype_of (DataType! t) {
		foreach (TypeReference base_type in base_types) {
			if (base_type.data_type == t ||
			    base_type.data_type.is_subtype_of (t)) {
				return true;
			}
		}
		
		return false;
	}
553
554
555
556
557
558
559
560
561
562
563

	public override int get_type_parameter_index (string! name) {
		int i = 0;
		foreach (TypeParameter parameter in type_parameters) {
			if (parameter.name == name) {
				return i;
			}
			i++;
		}
		return -1;
	}
564
}
565