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
20 * Jürg Billeter <j@bitron.ch>
26 * Represents a node in the symbol tree.
28 public abstract class Vala
.Symbol
: CodeNode
{
30 * The parent of this symbol.
32 public weak Symbol? parent_symbol
{
43 * The scope this symbol opens.
45 public weak Scope owner
{
51 _scope
.parent_scope
= value
;
58 public string? gir_name
{
60 return _gir_name
== null ? name
: _gir_name
;
70 public string? name
{ get; set; }
73 * Specifies whether this symbol is active.
75 * Symbols may become inactive when they only apply to a part of a
76 * scope. This is used for local variables not declared at the beginning
77 * of the block to determine which variables need to be freed before
80 public bool active
{ get; set; default = true; }
83 * Specifies whether this symbol has been deprecated.
85 public bool deprecated
{ get; set; default = false; }
88 * Specifies what version this symbol has been deprecated since.
90 public string? deprecated_since
{ get; set; default = null; }
93 * Specifies the replacement if this symbol has been deprecated.
95 public string? replacement
{ get; set; default = null; }
98 * Specifies whether this symbol has been accessed.
100 public bool used
{ get; set; }
103 * Specifies the accessibility of this symbol. Public accessibility
104 * doesn't limit access. Default accessibility limits access to this
105 * program or library. Private accessibility limits access to instances
106 * of the contained type.
108 public SymbolAccessibility access
{ get; set; }
110 public Comment? comment
{ get; set; }
112 private List
<string> cheader_filenames
;
115 * Specifies whether this method explicitly hides a member of a base
118 public bool hides
{ get; set; }
121 * Check if this symbol is just internal API (and therefore doesn't need
122 * to be listed in header files for instance) by traversing parent symbols
123 * and checking their accessibility.
125 public bool is_internal_symbol () {
126 if (!external
&& external_package
) {
127 // non-external symbols in VAPI files are internal symbols
131 for (Symbol sym
= this
; null != sym
; sym
= sym
.parent_symbol
) {
132 if (sym
.access
== SymbolAccessibility
.PRIVATE
133 || sym
.access
== SymbolAccessibility
.INTERNAL
) {
141 public bool is_private_symbol () {
142 if (!external
&& external_package
) {
143 // non-external symbols in VAPI files are private symbols
147 for (Symbol sym
= this
; null != sym
; sym
= sym
.parent_symbol
) {
148 if (sym
.access
== SymbolAccessibility
.PRIVATE
) {
157 get { return _scope
; }
161 * Specifies whether the implementation is external, for example in
162 * a separate C source file or in an external library.
164 public bool external
{ get; set; }
167 * Specifies whether the implementation is in an external library.
169 public bool external_package
{
171 return source_type
== SourceFileType
.PACKAGE
;
176 * Gets the SourceFileType of the source file that this symbol
177 * came from, or SourceFileType.NONE.
179 public SourceFileType source_type
{
181 if (source_reference
!= null) {
182 return source_reference
.file
.file_type
;
184 return SourceFileType
.NONE
;
189 private weak Scope _owner
;
190 private Scope _scope
;
191 private string? _gir_name
= null;
193 public Symbol (string? name
, SourceReference? source_reference
, Comment? comment
= null) {
195 this
.source_reference
= source_reference
;
196 this
.comment
= comment
;
197 _scope
= new
Scope (this
);
201 * Returns the fully expanded GIR name of this symbol
203 * @return full GIR name
205 public string get_full_gir_name () {
206 if (parent_symbol
== null) {
211 return parent_symbol
.get_full_gir_name ();
214 if (parent_symbol
.get_full_gir_name () == null) {
218 string parent_gir_name
= parent_symbol
.get_full_gir_name ();
219 string self_gir_name
= gir_name
.has_prefix (".") ? gir_name
.substring (1) : gir_name
;
220 if ("." in parent_gir_name
) {
221 return "%s%s".printf (parent_gir_name
, self_gir_name
);
223 return "%s.%s".printf (parent_gir_name
, self_gir_name
);
228 * Returns the fully expanded name of this symbol for use in
229 * human-readable messages.
233 public string get_full_name () {
234 if (parent_symbol
== null) {
239 return parent_symbol
.get_full_name ();
242 if (parent_symbol
.get_full_name () == null) {
246 if (name
.has_prefix (".")) {
247 return "%s%s".printf (parent_symbol
.get_full_name (), name
);
249 return "%s.%s".printf (parent_symbol
.get_full_name (), name
);
254 * Returns the camel case string to be prepended to the name of members
255 * of this symbol when used in C code.
257 * @return the camel case prefix to be used in C code
259 public virtual string get_cprefix () {
268 * Returns the C name of this symbol in lower case. Words are
269 * separated by underscores. The lower case C name of the parent symbol
270 * is prefix of the result, if there is one.
272 * @param infix a string to be placed between namespace and data type
274 * @return the lower case name to be used in C code
276 public virtual string?
get_lower_case_cname (string? infix
= null) {
281 * Returns the string to be prefixed to members of this symbol in
282 * lower case when used in C code.
284 * @return the lower case prefix to be used in C code
286 public virtual string get_lower_case_cprefix () {
290 static List
<string> _empty_string_list
;
293 * Returns a list of C header filenames users of this symbol must
296 * @return list of C header filenames for this symbol
298 public virtual List
<string> get_cheader_filenames () {
299 if (cheader_filenames
== null || cheader_filenames
.size
== 0) {
300 // parent_symbol can be null on incremental parsing
301 if (parent_symbol
!= null) {
302 /* default to header filenames of the namespace */
303 var parent_header_filenames
= parent_symbol
.get_cheader_filenames ();
304 if (parent_header_filenames
.size
> 0) {
305 return parent_header_filenames
;
309 if (source_reference
!= null && !external_package
) {
310 // don't add default include directives for VAPI files
311 add_cheader_filename (source_reference
.file
.get_cinclude_filename ());
313 if (_empty_string_list
== null) {
314 _empty_string_list
= new ArrayList
<string> ();
316 return _empty_string_list
;
319 return cheader_filenames
;
323 * Converts a string from CamelCase to lower_case.
325 * @param camel_case a string in camel case
326 * @return the specified string converted to lower case
328 public static string camel_case_to_lower_case (string camel_case
) {
329 if ("_" in camel_case
) {
330 // do not insert additional underscores if input is not real camel case
331 return camel_case
.down ();
334 var result_builder
= new
StringBuilder ("");
336 weak string i
= camel_case
;
339 while (i
.length
> 0) {
340 unichar c
= i
.get_char ();
341 if (c
.isupper () && !first
) {
342 /* current character is upper case and
343 * we're not at the beginning */
344 weak string t
= i
.prev_char ();
345 bool prev_upper
= t
.get_char ().isupper ();
347 bool next_upper
= t
.get_char ().isupper ();
348 if (!prev_upper
|| (i
.length
>= 2 && !next_upper
)) {
349 /* previous character wasn't upper case or
350 * next character isn't upper case*/
351 long len
= result_builder
.str
.length
;
352 if (len
!= 1 && result_builder
.str
.get_char (len
- 2) != '_') {
353 /* we're not creating 1 character words */
354 result_builder
.append_c ('_');
359 result_builder
.append_unichar (c
.tolower ());
365 return result_builder
.str
;
369 * Converts a string from lower_case to CamelCase.
371 * @param lower_case a string in lower case
372 * @return the specified string converted to camel case
374 public static string lower_case_to_camel_case (string lower_case
) {
375 var result_builder
= new
StringBuilder ("");
377 weak string i
= lower_case
;
379 bool last_underscore
= true;
380 while (i
.length
> 0) {
381 unichar c
= i
.get_char ();
383 last_underscore
= true;
384 } else if (c
.isupper ()) {
385 // original string is not lower_case, don't apply transformation
387 } else if (last_underscore
) {
388 result_builder
.append_unichar (c
.toupper ());
389 last_underscore
= false;
391 result_builder
.append_unichar (c
);
397 return result_builder
.str
;
400 // get the top scope from where this symbol is still accessible
401 public Scope?
get_top_accessible_scope (bool is_internal
= false) {
402 if (access
== SymbolAccessibility
.PRIVATE
) {
403 // private symbols are accessible within the scope where the symbol has been declared
407 if (access
== SymbolAccessibility
.INTERNAL
) {
411 if (parent_symbol
== null) {
412 // this is the root symbol
414 // only accessible within the same library
423 // if this is a public symbol, it's equally accessible as the parent symbol
424 return parent_symbol
.get_top_accessible_scope (is_internal
);
427 public virtual bool is_instance_member () {
428 bool instance
= true;
430 var f
= (Field
) this
;
431 instance
= (f
.binding
== MemberBinding
.INSTANCE
);
432 } else if (this is Method
) {
433 var m
= (Method
) this
;
434 if (!(m is CreationMethod
)) {
435 instance
= (m
.binding
== MemberBinding
.INSTANCE
);
437 } else if (this is Property
) {
438 var prop
= (Property
) this
;
439 instance
= (prop
.binding
== MemberBinding
.INSTANCE
);
440 } else if (this is EnumValue
) {
442 } else if (this is ErrorCode
) {
449 public virtual bool is_class_member () {
452 var f
= (Field
) this
;
453 isclass
= (f
.binding
== MemberBinding
.CLASS
);
454 } else if (this is Method
) {
455 var m
= (Method
) this
;
456 if (!(m is CreationMethod
)) {
457 isclass
= (m
.binding
== MemberBinding
.CLASS
);
459 } else if (this is Property
) {
460 var prop
= (Property
) this
;
461 isclass
= (prop
.binding
== MemberBinding
.CLASS
);
462 } else if (this is EnumValue
) {
464 } else if (this is ErrorCode
) {
472 * Process a [Deprecated] attribute
474 public virtual void process_deprecated_attribute (Attribute attr
) {
475 if (attr
.name
!= "Deprecated") {
481 if (attr
.has_argument ("since")) {
482 deprecated_since
= attr
.get_string ("since");
484 if (attr
.has_argument ("replacement")) {
485 replacement
= attr
.get_string ("replacement");
490 * Check to see if the symbol has been deprecated, and emit a warning
493 public bool check_deprecated (SourceReference? source_ref
= null) {
495 if (!CodeContext
.get ().deprecated
) {
496 Report
.deprecated (source_ref
, "%s %s%s".printf (get_full_name (), (deprecated_since
== null) ?
"is deprecated" : "has been deprecated since %s".printf (deprecated_since
), (replacement
== null) ?
"" : ". Use %s".printf (replacement
)));
505 * Sets the C header filename of this namespace to the specified
508 * @param cheader_filename header filename
510 public void set_cheader_filename (string cheader_filename
) {
511 cheader_filenames
= new ArrayList
<string> ();
512 cheader_filenames
.add (cheader_filename
);
516 * Adds a filename to the list of C header filenames users of this data
519 * @param filename a C header filename
521 public void add_cheader_filename (string filename
) {
522 if (cheader_filenames
== null) {
523 cheader_filenames
= new ArrayList
<string> ();
525 cheader_filenames
.add (filename
);
528 public Symbol?
get_hidden_member () {
531 if (parent_symbol is Class
) {
532 var cl
= ((Class
) parent_symbol
).base_class
;
534 sym
= cl
.scope
.lookup (name
);
535 if (sym
!= null && sym
.access
!= SymbolAccessibility
.PRIVATE
) {
540 } else if (parent_symbol is Struct
) {
541 var st
= ((Struct
) parent_symbol
).base_struct
;
543 sym
= st
.scope
.lookup (name
);
544 if (sym
!= null && sym
.access
!= SymbolAccessibility
.PRIVATE
) {
554 // check whether this symbol is at least as accessible as the specified symbol
555 public bool is_accessible (Symbol sym
) {
556 Scope sym_scope
= sym
.get_top_accessible_scope ();
557 Scope this_scope
= this
.get_top_accessible_scope ();
558 if ((sym_scope
== null && this_scope
!= null)
559 || (sym_scope
!= null && !sym_scope
.is_subscope_of (this_scope
))) {
566 public virtual void add_namespace (Namespace ns
) {
567 Report
.error (ns
.source_reference
, "unexpected declaration");
570 public virtual void add_class (Class cl
) {
571 Report
.error (cl
.source_reference
, "unexpected declaration");
574 public virtual void add_interface (Interface iface
) {
575 Report
.error (iface
.source_reference
, "unexpected declaration");
578 public virtual void add_struct (Struct st
) {
579 Report
.error (st
.source_reference
, "unexpected declaration");
582 public virtual void add_enum (Enum en
) {
583 Report
.error (en
.source_reference
, "unexpected declaration");
586 public virtual void add_error_domain (ErrorDomain edomain
) {
587 Report
.error (edomain
.source_reference
, "unexpected declaration");
590 public virtual void add_delegate (Delegate d
) {
591 Report
.error (d
.source_reference
, "unexpected declaration");
594 public virtual void add_constant (Constant constant
) {
595 Report
.error (constant
.source_reference
, "unexpected declaration");
598 public virtual void add_field (Field f
) {
599 Report
.error (f
.source_reference
, "unexpected declaration");
602 public virtual void add_method (Method m
) {
603 Report
.error (m
.source_reference
, "unexpected declaration");
606 public virtual void add_property (Property prop
) {
607 Report
.error (prop
.source_reference
, "unexpected declaration");
610 public virtual void add_signal (Signal sig
) {
611 Report
.error (sig
.source_reference
, "unexpected declaration");
614 public virtual void add_constructor (Constructor c
) {
615 Report
.error (c
.source_reference
, "unexpected declaration");
618 public virtual void add_destructor (Destructor d
) {
619 Report
.error (d
.source_reference
, "unexpected declaration");
623 public enum Vala
.SymbolAccessibility
{
630 public enum Vala
.MemberBinding
{