Line data Source code
1 : /* valasymbol.vala
2 : *
3 : * Copyright (C) 2006-2010 Jürg Billeter
4 : *
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.
9 :
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.
14 :
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
18 : *
19 : * Author:
20 : * Jürg Billeter <j@bitron.ch>
21 : */
22 :
23 : using GLib;
24 :
25 : /**
26 : * Represents a node in the symbol tree.
27 : */
28 1538 : public abstract class Vala.Symbol : CodeNode {
29 : /**
30 : * The parent of this symbol.
31 : */
32 : public weak Symbol? parent_symbol {
33 370545137 : get {
34 370545137 : if (owner == null) {
35 49341363 : return null;
36 : } else {
37 321203774 : return owner.owner;
38 : }
39 : }
40 : }
41 :
42 : /**
43 : * The scope this symbol is a part of
44 : */
45 : public weak Scope owner {
46 695940773 : get {
47 695940773 : return _owner;
48 : }
49 29039353 : set {
50 29039353 : _owner = value;
51 29039353 : _scope.parent_scope = value;
52 : }
53 : }
54 :
55 : /**
56 : * The symbol name.
57 : */
58 303076706 : public string? name { get; set; }
59 :
60 : /**
61 : * Specifies whether this symbol is active.
62 : *
63 : * Symbols may become inactive when they only apply to a part of a
64 : * scope. This is used for local variables not declared at the beginning
65 : * of the block to determine which variables need to be freed before
66 : * jump statements.
67 : */
68 26402324 : public bool active { get; set; default = true; }
69 :
70 : /**
71 : * Specifies whether this symbol has been accessed.
72 : */
73 23194294 : public bool used { get; set; }
74 :
75 : /**
76 : * Specifies whether this symbol is anonymous and has no public definition.
77 : */
78 57912 : public bool anonymous { get; set; }
79 :
80 : /**
81 : * Specifies the accessibility of this symbol. Public accessibility
82 : * doesn't limit access. Default accessibility limits access to this
83 : * program or library. Private accessibility limits access to instances
84 : * of the contained type.
85 : */
86 45019276 : public SymbolAccessibility access { get; set; }
87 :
88 120517084 : public Comment? comment { get; set; }
89 :
90 :
91 60047056 : private VersionAttribute _version;
92 :
93 : /**
94 : * The associated [Version] attribute
95 : */
96 : public VersionAttribute version {
97 1768563 : get {
98 1768563 : if (_version == null) {
99 643926 : _version = new VersionAttribute (this);
100 : }
101 :
102 1768563 : return _version;
103 : }
104 : }
105 :
106 : /**
107 : * Specifies whether this method explicitly hides a member of a base
108 : * type.
109 : */
110 3627006 : public bool hides { get; set; }
111 :
112 : /**
113 : * Check if this symbol is just internal API (and therefore doesn't need
114 : * to be listed in header files for instance) by traversing parent symbols
115 : * and checking their accessibility.
116 : */
117 5472707 : public bool is_internal_symbol () {
118 5472707 : if (!external && external_package) {
119 : // non-external symbols in VAPI files are internal symbols
120 129435 : return true;
121 : }
122 :
123 46637128 : for (Symbol sym = this; null != sym; sym = sym.parent_symbol) {
124 41172898 : if (sym.access == SymbolAccessibility.PRIVATE
125 20567410 : || sym.access == SymbolAccessibility.INTERNAL) {
126 50232 : return true;
127 : }
128 : }
129 :
130 5472707 : return false;
131 : }
132 :
133 34341 : public bool is_private_symbol () {
134 34341 : if (!external && external_package) {
135 : // non-external symbols in VAPI files are private symbols
136 4479 : return true;
137 : }
138 :
139 263255 : for (Symbol sym = this; null != sym; sym = sym.parent_symbol) {
140 90419 : if (sym.access == SymbolAccessibility.PRIVATE) {
141 4001 : return true;
142 : }
143 : }
144 :
145 34341 : return false;
146 : }
147 :
148 : /**
149 : * The scope this symbol opens.
150 : */
151 : public Scope scope {
152 51056541 : get { return _scope; }
153 : }
154 :
155 6409633 : public bool is_extern { get; set; }
156 :
157 : /**
158 : * Specifies whether the implementation is external, for example in
159 : * a separate C source file or in an external library.
160 : */
161 : public bool external {
162 12360139 : get {
163 12360139 : if (_external != null) {
164 798808 : return _external;
165 : }
166 11561331 : return is_extern || external_package;
167 : }
168 678813 : set {
169 1357626 : _external = value;
170 : }
171 : }
172 :
173 : /**
174 : * Specifies whether the implementation is in an external library.
175 : */
176 : public bool external_package {
177 60278735 : get {
178 60278735 : return source_type == SourceFileType.PACKAGE;
179 : }
180 : }
181 :
182 : /**
183 : * Specifies whether the implementation came from the commandline.
184 : */
185 : public bool from_commandline {
186 20154 : get {
187 20154 : if (source_reference != null) {
188 20154 : return source_reference.file.from_commandline;
189 : } else {
190 0 : return false;
191 : }
192 : }
193 : }
194 :
195 : /**
196 : * Gets the SourceFileType of the source file that this symbol
197 : * came from, or SourceFileType.NONE.
198 : */
199 : public SourceFileType source_type {
200 61849608 : get {
201 61849608 : if (source_reference != null) {
202 61846743 : return source_reference.file.file_type;
203 : } else {
204 2865 : return SourceFileType.NONE;
205 : }
206 : }
207 : }
208 :
209 : private weak Scope _owner;
210 60047056 : private Scope _scope;
211 60047056 : private bool? _external;
212 :
213 60047066 : protected Symbol (string? name, SourceReference? source_reference = null, Comment? comment = null) {
214 60047066 : this.name = name;
215 60047066 : this.source_reference = source_reference;
216 60047066 : this.comment = comment;
217 60047066 : _scope = new Scope (this);
218 : }
219 :
220 : /**
221 : * Returns the fully expanded name of this symbol for use in
222 : * human-readable messages.
223 : *
224 : * @return full name
225 : */
226 118990 : public string get_full_name () {
227 118990 : if (parent_symbol == null) {
228 99164 : return name;
229 : }
230 :
231 69408 : if (name == null) {
232 93 : return parent_symbol.get_full_name ();
233 : }
234 :
235 69315 : if (parent_symbol.get_full_name () == null) {
236 99158 : return name;
237 : }
238 :
239 19736 : if (name.has_prefix (".")) {
240 3 : return "%s%s".printf (parent_symbol.get_full_name (), name);
241 : } else {
242 19733 : return "%s.%s".printf (parent_symbol.get_full_name (), name);
243 : }
244 : }
245 :
246 : /**
247 : * Converts a string from CamelCase to lower_case.
248 : *
249 : * @param camel_case a string in camel case
250 : * @return the specified string converted to lower case
251 : */
252 23562 : public static string camel_case_to_lower_case (string camel_case) {
253 23562 : if ("_" in camel_case) {
254 : // do not insert additional underscores if input is not real camel case
255 2178 : return camel_case.ascii_down ();
256 : }
257 :
258 21384 : var result_builder = new StringBuilder ("");
259 :
260 21384 : weak string i = camel_case;
261 :
262 21384 : bool first = true;
263 162840 : while (i.length > 0) {
264 141456 : unichar c = i.get_char ();
265 141456 : if (c.isupper () && !first) {
266 : /* current character is upper case and
267 : * we're not at the beginning */
268 10143 : weak string t = i.prev_char ();
269 10143 : bool prev_upper = t.get_char ().isupper ();
270 10143 : t = i.next_char ();
271 10143 : bool next_upper = t.get_char ().isupper ();
272 10143 : if (!prev_upper || (i.length >= 2 && !next_upper)) {
273 : /* previous character wasn't upper case or
274 : * next character isn't upper case*/
275 8464 : long len = result_builder.str.length;
276 8464 : if (len != 1 && result_builder.str.get_char (len - 2) != '_') {
277 : /* we're not creating 1 character words */
278 7829 : result_builder.append_c ('_');
279 : }
280 : }
281 : }
282 :
283 141456 : result_builder.append_unichar (c.tolower ());
284 :
285 141456 : first = false;
286 141456 : i = i.next_char ();
287 : }
288 :
289 42768 : return result_builder.str;
290 : }
291 :
292 : /**
293 : * Converts a string from lower_case to CamelCase.
294 : *
295 : * @param lower_case a string in lower case
296 : * @return the specified string converted to camel case
297 : */
298 1126 : public static string lower_case_to_camel_case (string lower_case) {
299 1126 : var result_builder = new StringBuilder ("");
300 :
301 1126 : weak string i = lower_case;
302 :
303 1126 : bool last_underscore = true;
304 13119 : while (i.length > 0) {
305 11993 : unichar c = i.get_char ();
306 11993 : if (c == '_') {
307 : last_underscore = true;
308 10583 : } else if (c.isupper ()) {
309 : // original string is not lower_case, don't apply transformation
310 0 : return lower_case;
311 10583 : } else if (last_underscore) {
312 2509 : result_builder.append_unichar (c.toupper ());
313 2509 : last_underscore = false;
314 : } else {
315 8074 : result_builder.append_unichar (c);
316 : }
317 :
318 11993 : i = i.next_char ();
319 : }
320 :
321 2252 : return result_builder.str;
322 : }
323 :
324 : /**
325 : * Implementation of GLib.EqualFunc to use with e.g. HashMap
326 : *
327 : * @param a a symbol
328 : * @param b a symbol
329 : * @return whether the given instances represent the same symbol
330 : */
331 0 : public static bool equal_func (Symbol a, Symbol b) {
332 0 : return str_equal (a.get_full_name (), b.get_full_name ());
333 : }
334 :
335 : /**
336 : * Implementation of GLib.HashFunc to use with e.g. HashMap
337 : *
338 : * @param s a symbol
339 : * @return a hash value
340 : */
341 4 : public static uint hash_func (Symbol s) {
342 4 : return str_hash (s.get_full_name ());
343 : }
344 :
345 : // get the top scope from where this symbol is still accessible
346 156053703 : public Scope? get_top_accessible_scope (bool is_internal = false) {
347 156053703 : if (access == SymbolAccessibility.PRIVATE) {
348 : // private symbols are accessible within the scope where the symbol has been declared
349 564393 : return owner;
350 : }
351 :
352 155509873 : if (access == SymbolAccessibility.INTERNAL) {
353 20566 : is_internal = true;
354 : }
355 :
356 155509873 : if (parent_symbol == null) {
357 : // this is the root symbol
358 43648016 : if (is_internal) {
359 : // only accessible within the same library
360 : // return root scope
361 41126 : return scope;
362 : } else {
363 : // unlimited access
364 43627453 : return null;
365 : }
366 : }
367 :
368 : // if this is a public symbol, it's equally accessible as the parent symbol
369 111861857 : return parent_symbol.get_top_accessible_scope (is_internal);
370 : }
371 :
372 343 : public virtual bool is_instance_member () {
373 343 : bool instance = true;
374 411 : if (this is Field) {
375 68 : var f = (Field) this;
376 68 : instance = (f.binding == MemberBinding.INSTANCE);
377 275 : } else if (this is Method) {
378 0 : var m = (Method) this;
379 0 : if (!(m is CreationMethod)) {
380 0 : instance = (m.binding == MemberBinding.INSTANCE);
381 : }
382 284 : } else if (this is Property) {
383 9 : var prop = (Property) this;
384 9 : instance = (prop.binding == MemberBinding.INSTANCE);
385 266 : } else if (this is EnumValue) {
386 : instance = false;
387 9 : } else if (this is ErrorCode) {
388 343 : instance = false;
389 : }
390 :
391 343 : return instance;
392 : }
393 :
394 63 : public virtual bool is_class_member () {
395 63 : bool isclass = true;
396 102 : if (this is Field) {
397 39 : var f = (Field) this;
398 39 : isclass = (f.binding == MemberBinding.CLASS);
399 48 : } else if (this is Method) {
400 24 : var m = (Method) this;
401 24 : if (!(m is CreationMethod)) {
402 24 : isclass = (m.binding == MemberBinding.CLASS);
403 : }
404 0 : } else if (this is Property) {
405 0 : var prop = (Property) this;
406 0 : isclass = (prop.binding == MemberBinding.CLASS);
407 0 : } else if (this is EnumValue) {
408 : isclass = false;
409 0 : } else if (this is ErrorCode) {
410 63 : isclass = false;
411 : }
412 :
413 63 : return isclass;
414 : }
415 :
416 8496 : public Symbol? get_hidden_member () {
417 8496 : Symbol sym = null;
418 :
419 8496 : if (parent_symbol is Class) {
420 4468 : var cl = ((Class) parent_symbol).base_class;
421 12378 : while (cl != null) {
422 7924 : sym = cl.scope.lookup (name);
423 7924 : if (sym != null && sym.access != SymbolAccessibility.PRIVATE) {
424 14 : return sym;
425 : }
426 12434 : cl = cl.base_class;
427 : }
428 4028 : } else if (parent_symbol is Struct) {
429 306 : var st = ((Struct) parent_symbol).base_struct;
430 313 : while (st != null) {
431 7 : sym = st.scope.lookup (name);
432 7 : if (sym != null && sym.access != SymbolAccessibility.PRIVATE) {
433 0 : return sym;
434 : }
435 7 : st = st.base_struct;
436 : }
437 : }
438 :
439 4760 : return null;
440 : }
441 :
442 : // check whether this symbol is at least as accessible as the specified symbol
443 22095923 : public bool is_accessible (Symbol sym) {
444 22095923 : Scope sym_scope = sym.get_top_accessible_scope ();
445 22095923 : Scope this_scope = this.get_top_accessible_scope ();
446 22095923 : if ((sym_scope == null && this_scope != null)
447 22095909 : || (sym_scope != null && !sym_scope.is_subscope_of (this_scope))) {
448 14 : return false;
449 : }
450 :
451 22095909 : return true;
452 : }
453 :
454 77829 : public virtual void add_namespace (Namespace ns) {
455 0 : Report.error (ns.source_reference, "inner `%s' is not supported in `%s'", "namespace", get_full_name ());
456 : }
457 :
458 624567 : public virtual void add_class (Class cl) {
459 0 : Report.error (cl.source_reference, "inner `%s' types are not supported in `%s'", "class", get_full_name ());
460 : }
461 :
462 116017 : public virtual void add_interface (Interface iface) {
463 0 : Report.error (iface.source_reference, "inner `%s' types are not supported in `%s'", "interface", get_full_name ());
464 : }
465 :
466 180505 : public virtual void add_struct (Struct st) {
467 0 : Report.error (st.source_reference, "inner `%s' types are not supported in `%s'", "struct", get_full_name ());
468 : }
469 :
470 338025 : public virtual void add_enum (Enum en) {
471 0 : Report.error (en.source_reference, "inner `%s' types are not supported in `%s'", "enum", get_full_name ());
472 : }
473 :
474 39937 : public virtual void add_error_domain (ErrorDomain edomain) {
475 0 : Report.error (edomain.source_reference, "inner `%s' types are not supported in `%s'", "errordomain", get_full_name ());
476 : }
477 :
478 283923 : public virtual void add_delegate (Delegate d) {
479 0 : Report.error (d.source_reference, "inner `%s' types are not supported in `%s'", "delegate", get_full_name ());
480 : }
481 :
482 656309 : public virtual void add_constant (Constant constant) {
483 0 : Report.error (constant.source_reference, "constants are not allowed in `%s'", get_full_name ());
484 : }
485 :
486 581511 : public virtual void add_field (Field f) {
487 0 : Report.error (f.source_reference, "fields are not allowed in `%s'", get_full_name ());
488 : }
489 :
490 6589647 : public virtual void add_method (Method m) {
491 0 : Report.error (m.source_reference, "methods are not allowed in `%s'", get_full_name ());
492 : }
493 :
494 449363 : public virtual void add_property (Property prop) {
495 0 : Report.error (prop.source_reference, "properties are not allowed in `%s'", get_full_name ());
496 : }
497 :
498 136715 : public virtual void add_signal (Signal sig) {
499 0 : Report.error (sig.source_reference, "signals are not allowed in `%s'", get_full_name ());
500 : }
501 :
502 47 : public virtual void add_constructor (Constructor c) {
503 0 : Report.error (c.source_reference, "constructors are not allowed in `%s'", get_full_name ());
504 : }
505 :
506 26 : public virtual void add_destructor (Destructor d) {
507 0 : Report.error (d.source_reference, "destructors are not allowed in `%s'", get_full_name ());
508 : }
509 :
510 51 : public override string to_string () {
511 51 : var builder = new StringBuilder (get_full_name ());
512 :
513 51 : unowned List<TypeParameter>? type_params = null;
514 51 : if (this is GenericSymbol) {
515 51 : type_params = ((GenericSymbol) this).get_type_parameters ();
516 : }
517 51 : if (type_params != null && type_params.size > 0) {
518 46 : builder.append_c ('<');
519 46 : bool first = true;
520 113 : foreach (var type_param in type_params) {
521 67 : if (!first) {
522 21 : builder.append_c (',');
523 : } else {
524 : first = false;
525 : }
526 134 : builder.append (type_param.name);
527 : }
528 46 : builder.append_c ('>');
529 : }
530 :
531 102 : return builder.str;
532 : }
533 : }
534 :
535 : public enum Vala.SymbolAccessibility {
536 : PRIVATE,
537 : INTERNAL,
538 : PROTECTED,
539 : PUBLIC;
540 :
541 : public unowned string to_string () {
542 18800 : switch (this) {
543 18800 : case PROTECTED: return "protected";
544 9 : case INTERNAL: return "internal";
545 64 : case PRIVATE: return "private";
546 18454 : case PUBLIC: return "public";
547 0 : default: assert_not_reached ();
548 : }
549 : }
550 : }
551 :
552 : public enum Vala.MemberBinding {
553 : INSTANCE,
554 : CLASS,
555 : STATIC
556 : }
|