Release 0.41.92
[vala-gnome.git] / vala / valasymbol.vala
blob131969afbbc076765f40ca848611759c5b3fdeb9
1 /* valasymbol.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 node in the symbol tree.
28 public abstract class Vala.Symbol : CodeNode {
29 /**
30 * The parent of this symbol.
32 public weak Symbol? parent_symbol {
33 get {
34 if (owner == null) {
35 return null;
36 } else {
37 return owner.owner;
42 /**
43 * The scope this symbol is a part of
45 public weak Scope owner {
46 get {
47 return _owner;
49 set {
50 _owner = value;
51 _scope.parent_scope = value;
55 /**
56 * The symbol name.
58 public string? name { get; set; }
60 /**
61 * Specifies whether this symbol is active.
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.
68 public bool active { get; set; default = true; }
70 /**
71 * Specifies whether this symbol has been accessed.
73 public bool used { get; set; }
75 /**
76 * Specifies whether this symbol is anonymous and has no public defintion.
78 public bool anonymous { get; set; }
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.
86 public SymbolAccessibility access { get; set; }
88 public Comment? comment { get; set; }
91 private VersionAttribute _version;
93 /**
94 * The associated [Version] attribute
96 public VersionAttribute version {
97 get {
98 if (_version == null) {
99 _version = new VersionAttribute (this);
102 return _version;
107 * Specifies whether this method explicitly hides a member of a base
108 * type.
110 public bool hides { get; set; }
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.
117 public bool is_internal_symbol () {
118 if (!external && external_package) {
119 // non-external symbols in VAPI files are internal symbols
120 return true;
123 for (Symbol sym = this; null != sym; sym = sym.parent_symbol) {
124 if (sym.access == SymbolAccessibility.PRIVATE
125 || sym.access == SymbolAccessibility.INTERNAL) {
126 return true;
130 return false;
133 public bool is_private_symbol () {
134 if (!external && external_package) {
135 // non-external symbols in VAPI files are private symbols
136 return true;
139 for (Symbol sym = this; null != sym; sym = sym.parent_symbol) {
140 if (sym.access == SymbolAccessibility.PRIVATE) {
141 return true;
145 return false;
149 * The scope this symbol opens.
151 public Scope scope {
152 get { return _scope; }
156 * Specifies whether the implementation is external, for example in
157 * a separate C source file or in an external library.
159 public bool external { get; set; }
162 * Specifies whether the implementation is in an external library.
164 public bool external_package {
165 get {
166 return source_type == SourceFileType.PACKAGE;
171 * Specifies whether the implementation came from the commandline.
173 public bool from_commandline {
174 get {
175 if (source_reference != null) {
176 return source_reference.file.from_commandline;
177 } else {
178 return false;
184 * Gets the SourceFileType of the source file that this symbol
185 * came from, or SourceFileType.NONE.
187 public SourceFileType source_type {
188 get {
189 if (source_reference != null) {
190 return source_reference.file.file_type;
191 } else {
192 return SourceFileType.NONE;
197 private weak Scope _owner;
198 private Scope _scope;
200 public Symbol (string? name, SourceReference? source_reference, Comment? comment = null) {
201 this.name = name;
202 this.source_reference = source_reference;
203 this.comment = comment;
204 _scope = new Scope (this);
208 * Returns the fully expanded name of this symbol for use in
209 * human-readable messages.
211 * @return full name
213 public string get_full_name () {
214 if (parent_symbol == null) {
215 return name;
218 if (name == null) {
219 return parent_symbol.get_full_name ();
222 if (parent_symbol.get_full_name () == null) {
223 return name;
226 if (name.has_prefix (".")) {
227 return "%s%s".printf (parent_symbol.get_full_name (), name);
228 } else {
229 return "%s.%s".printf (parent_symbol.get_full_name (), name);
234 * Converts a string from CamelCase to lower_case.
236 * @param camel_case a string in camel case
237 * @return the specified string converted to lower case
239 public static string camel_case_to_lower_case (string camel_case) {
240 if ("_" in camel_case) {
241 // do not insert additional underscores if input is not real camel case
242 return camel_case.down ();
245 var result_builder = new StringBuilder ("");
247 weak string i = camel_case;
249 bool first = true;
250 while (i.length > 0) {
251 unichar c = i.get_char ();
252 if (c.isupper () && !first) {
253 /* current character is upper case and
254 * we're not at the beginning */
255 weak string t = i.prev_char ();
256 bool prev_upper = t.get_char ().isupper ();
257 t = i.next_char ();
258 bool next_upper = t.get_char ().isupper ();
259 if (!prev_upper || (i.length >= 2 && !next_upper)) {
260 /* previous character wasn't upper case or
261 * next character isn't upper case*/
262 long len = result_builder.str.length;
263 if (len != 1 && result_builder.str.get_char (len - 2) != '_') {
264 /* we're not creating 1 character words */
265 result_builder.append_c ('_');
270 result_builder.append_unichar (c.tolower ());
272 first = false;
273 i = i.next_char ();
276 return result_builder.str;
280 * Converts a string from lower_case to CamelCase.
282 * @param lower_case a string in lower case
283 * @return the specified string converted to camel case
285 public static string lower_case_to_camel_case (string lower_case) {
286 var result_builder = new StringBuilder ("");
288 weak string i = lower_case;
290 bool last_underscore = true;
291 while (i.length > 0) {
292 unichar c = i.get_char ();
293 if (c == '_') {
294 last_underscore = true;
295 } else if (c.isupper ()) {
296 // original string is not lower_case, don't apply transformation
297 return lower_case;
298 } else if (last_underscore) {
299 result_builder.append_unichar (c.toupper ());
300 last_underscore = false;
301 } else {
302 result_builder.append_unichar (c);
305 i = i.next_char ();
308 return result_builder.str;
311 // get the top scope from where this symbol is still accessible
312 public Scope? get_top_accessible_scope (bool is_internal = false) {
313 if (access == SymbolAccessibility.PRIVATE) {
314 // private symbols are accessible within the scope where the symbol has been declared
315 return owner;
318 if (access == SymbolAccessibility.INTERNAL) {
319 is_internal = true;
322 if (parent_symbol == null) {
323 // this is the root symbol
324 if (is_internal) {
325 // only accessible within the same library
326 // return root scope
327 return scope;
328 } else {
329 // unlimited access
330 return null;
334 // if this is a public symbol, it's equally accessible as the parent symbol
335 return parent_symbol.get_top_accessible_scope (is_internal);
338 public virtual bool is_instance_member () {
339 bool instance = true;
340 if (this is Field) {
341 var f = (Field) this;
342 instance = (f.binding == MemberBinding.INSTANCE);
343 } else if (this is Method) {
344 var m = (Method) this;
345 if (!(m is CreationMethod)) {
346 instance = (m.binding == MemberBinding.INSTANCE);
348 } else if (this is Property) {
349 var prop = (Property) this;
350 instance = (prop.binding == MemberBinding.INSTANCE);
351 } else if (this is EnumValue) {
352 instance = false;
353 } else if (this is ErrorCode) {
354 instance = false;
357 return instance;
360 public virtual bool is_class_member () {
361 bool isclass = true;
362 if (this is Field) {
363 var f = (Field) this;
364 isclass = (f.binding == MemberBinding.CLASS);
365 } else if (this is Method) {
366 var m = (Method) this;
367 if (!(m is CreationMethod)) {
368 isclass = (m.binding == MemberBinding.CLASS);
370 } else if (this is Property) {
371 var prop = (Property) this;
372 isclass = (prop.binding == MemberBinding.CLASS);
373 } else if (this is EnumValue) {
374 isclass = false;
375 } else if (this is ErrorCode) {
376 isclass = false;
379 return isclass;
382 public Symbol? get_hidden_member () {
383 Symbol sym = null;
385 if (parent_symbol is Class) {
386 var cl = ((Class) parent_symbol).base_class;
387 while (cl != null) {
388 sym = cl.scope.lookup (name);
389 if (sym != null && sym.access != SymbolAccessibility.PRIVATE) {
390 return sym;
392 cl = cl.base_class;
394 } else if (parent_symbol is Struct) {
395 var st = ((Struct) parent_symbol).base_struct;
396 while (st != null) {
397 sym = st.scope.lookup (name);
398 if (sym != null && sym.access != SymbolAccessibility.PRIVATE) {
399 return sym;
401 st = st.base_struct;
405 return null;
408 // check whether this symbol is at least as accessible as the specified symbol
409 public bool is_accessible (Symbol sym) {
410 Scope sym_scope = sym.get_top_accessible_scope ();
411 Scope this_scope = this.get_top_accessible_scope ();
412 if ((sym_scope == null && this_scope != null)
413 || (sym_scope != null && !sym_scope.is_subscope_of (this_scope))) {
414 return false;
417 return true;
420 public virtual void add_namespace (Namespace ns) {
421 Report.error (ns.source_reference, "unexpected declaration");
424 public virtual void add_class (Class cl) {
425 Report.error (cl.source_reference, "unexpected declaration");
428 public virtual void add_interface (Interface iface) {
429 Report.error (iface.source_reference, "unexpected declaration");
432 public virtual void add_struct (Struct st) {
433 Report.error (st.source_reference, "unexpected declaration");
436 public virtual void add_enum (Enum en) {
437 Report.error (en.source_reference, "unexpected declaration");
440 public virtual void add_error_domain (ErrorDomain edomain) {
441 Report.error (edomain.source_reference, "unexpected declaration");
444 public virtual void add_delegate (Delegate d) {
445 Report.error (d.source_reference, "unexpected declaration");
448 public virtual void add_constant (Constant constant) {
449 Report.error (constant.source_reference, "unexpected declaration");
452 public virtual void add_field (Field f) {
453 Report.error (f.source_reference, "unexpected declaration");
456 public virtual void add_method (Method m) {
457 Report.error (m.source_reference, "unexpected declaration");
460 public virtual void add_property (Property prop) {
461 Report.error (prop.source_reference, "unexpected declaration");
464 public virtual void add_signal (Signal sig) {
465 Report.error (sig.source_reference, "unexpected declaration");
468 public virtual void add_constructor (Constructor c) {
469 Report.error (c.source_reference, "unexpected declaration");
472 public virtual void add_destructor (Destructor d) {
473 Report.error (d.source_reference, "unexpected declaration");
477 public enum Vala.SymbolAccessibility {
478 PRIVATE,
479 INTERNAL,
480 PROTECTED,
481 PUBLIC
484 public enum Vala.MemberBinding {
485 INSTANCE,
486 CLASS,
487 STATIC