3 * Copyright (C) 2010 Florian Brosch
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 * Florian Brosch <flo.brosch@gmail.com>
27 * Resolves symbols by C-names
29 public class Valadoc
.CTypeResolver
: Visitor
{
30 private Vala
.Map
<string, Api
.TypeSymbol
> types
= new Vala
.HashMap
<string, Api
.TypeSymbol
> (str_hash
, str_equal
);
31 private Vala
.Map
<string, Api
.Node
> nodes
= new Vala
.HashMap
<string, Api
.Node
> (str_hash
, str_equal
);
32 private Api
.Tree tree
;
34 public CTypeResolver (Api
.Tree tree
) {
39 private string convert_array_to_camelcase (string[] elements
) {
40 StringBuilder builder
= new
StringBuilder ();
42 foreach (string element
in elements
) {
43 builder
.append_c (((char[])element
)[0].toupper ());
44 builder
.append (element
.next_char ().down ());
47 return (owned
) builder
.str
;
50 private bool is_capitalized_and_underscored (string name
) {
53 unichar c
= name
.get_char ();
56 if (c
< 'A' || c
> 'Z') {
60 bool last_was_underscore
= false;
61 for (c
= (pos
= name
).get_char (); c
!= '\0' ; c
= (pos
= pos
.next_char ()).get_char ()) {
62 if ((c
!= '_' && !(c
>= 'A' && c
<= 'Z')) || (last_was_underscore
&& c
== '_')) {
66 last_was_underscore
= (c
== '_');
69 return !last_was_underscore
;
72 private string?
translate_cname_to_g (string name
) {
73 if (is_capitalized_and_underscored (name
)) {
74 string[] segments
= name
.split ("_");
75 unowned
string last_segment
= segments
[segments
.length
- 1];
76 if (last_segment
!= "ERROR") {
80 return convert_array_to_camelcase (segments
);
83 int length
= name
.length
;
84 if (length
> 5 && name
.has_suffix ("Iface")) {
85 return name
.substring (0, length
- 5);
86 } else if (length
> 5 && name
.has_suffix ("Class")) {
87 return name
.substring (0, length
- 5);
93 public Api
.TypeSymbol?
resolve_symbol_type (string name
) {
94 TypeSymbol? symbol
= types
.get (name
);
99 if (is_capitalized_and_underscored (name
)) {
100 string[] segments
= name
.split ("_");
102 if (segments
[segments
.length
- 1] == "TYPE") {
103 segments
.resize (segments
.length
- 1);
104 return types
.get (convert_array_to_camelcase (segments
));
105 } else if (segments
.length
> 2 && segments
[1] == "TYPE") {
106 string[] _segments
= segments
[1:segments
.length
];
107 _segments
[0] = segments
[0];
108 return types
.get (convert_array_to_camelcase (_segments
));
116 * Resolves symbols by C-names
118 * @param _name a C-name
119 * @return the resolved node or null
121 public Api
.Node?
resolve_symbol (Api
.Node? element
, string _name
) {
122 string name
= _name
.replace ("->", ".").replace ("-", "_");
124 if (element
!= null && name
.has_prefix (":")) {
125 Item parent
= element
;
126 while (parent
!= null && !(parent is Class
|| parent is Interface
)) {
127 parent
= parent
.parent
;
130 if (parent is Class
&& ((Class
) parent
).get_cname () != null) {
131 name
= ((Class
) parent
).get_cname () + name
;
132 } else if (parent is Interface
&& ((Interface
) parent
).get_cname () != null) {
133 name
= ((Interface
) parent
).get_cname () + name
;
140 Api
.Node? node
= nodes
.get (name
);
145 string? alternative
= translate_cname_to_g (name
);
146 if (alternative
!= null) {
147 return nodes
.get (alternative
);
150 if (element
!= null && name
.has_prefix (":")) {
151 if (element is Class
&& ((Class
) element
).get_cname () != null) {
152 return nodes
.get (((Class
) element
).get_cname () + "." + name
);
153 } else if (element is Struct
&& ((Struct
) element
).get_cname () != null) {
154 return nodes
.get (((Struct
) element
).get_cname () + "." + name
);
158 if (name
== "dgettext") {
159 return nodes
.get ("g_dgettext");
160 } else if (name
== "printf") {
161 return this
.tree
.search_symbol_str (null, "GLib.FileStream.printf");
164 int dotpos
= name
.index_of_char ('.');
166 string fst
= name
.substring (0, dotpos
);
167 string snd
= name
.substring (dotpos
+ 1);
168 return nodes
.get (fst
+ ":" + snd
);
174 private void register_symbol_type (string? name
, Api
.TypeSymbol symbol
) {
176 types
.set (name
, symbol
);
180 private void register_symbol (string? name
, Api
.Node node
) {
182 nodes
.set (name
.replace ("-", "_"), node
);
186 private string?
get_parent_type_cname (Item item
) {
187 string parent_cname
= null;
188 if (item
.parent is Class
) {
189 parent_cname
= ((Class
) item
.parent
).get_cname ();
190 } else if (item
.parent is Interface
) {
191 parent_cname
= ((Interface
) item
.parent
).get_cname ();
192 } else if (item
.parent is Struct
) {
193 parent_cname
= ((Struct
) item
.parent
).get_cname ();
194 } else if (item
.parent is ErrorDomain
) {
195 parent_cname
= ((ErrorDomain
) item
.parent
).get_cname ();
196 } else if (item
.parent is Api
.Enum
) {
197 parent_cname
= ((Api
.Enum
) item
.parent
).get_cname ();
207 public override void visit_tree (Api
.Tree item
) {
208 item
.accept_children (this
);
214 public override void visit_package (Package item
) {
215 item
.accept_all_children (this
, false);
221 public override void visit_namespace (Namespace item
) {
222 item
.accept_all_children (this
, false);
228 public override void visit_interface (Interface item
) {
229 register_symbol (item
.get_cname (), item
);
230 item
.accept_all_children (this
, false);
236 public override void visit_class (Class item
) {
237 register_symbol_type (item
.get_type_id (), item
);
238 register_symbol (item
.get_cname (), item
);
239 item
.accept_all_children (this
, false);
245 public override void visit_struct (Struct item
) {
246 register_symbol_type (item
.get_type_id (), item
);
247 register_symbol (item
.get_cname (), item
);
248 item
.accept_all_children (this
, false);
254 public override void visit_property (Property item
) {
255 string parent_cname
= get_parent_type_cname (item
);
256 assert (parent_cname
!= null);
258 string cname
= item
.get_cname ();
259 register_symbol (parent_cname
+":"+cname
, item
);
262 Vala
.Collection
<Interface
> interfaces
;
263 Vala
.Collection
<Class
> classes
;
265 if (item
.parent is Interface
) {
266 interfaces
= ((Api
.Interface
) item
.parent
).get_known_related_interfaces ();
267 classes
= ((Api
.Interface
) item
.parent
).get_known_implementations ();
268 } else if (item
.parent is Class
) {
269 interfaces
= ((Api
.Class
) item
.parent
).get_known_derived_interfaces ();
270 classes
= ((Api
.Class
) item
.parent
).get_known_child_classes ();
271 } else if (item
.parent is Struct
) {
272 // Properties are allowed here, similar to compact classes
275 assert_not_reached ();
278 foreach (Interface iface
in interfaces
) {
279 register_symbol (iface
.get_cname () + ":" + cname
, item
);
282 foreach (Class cl
in classes
) {
283 register_symbol (cl
.get_cname () + ":" + cname
, item
);
290 public override void visit_field (Field item
) {
291 if (item
.parent is Namespace
|| item
.is_static
) {
292 register_symbol (item
.get_cname (), item
);
294 string parent_cname
= get_parent_type_cname (item
);
295 if (parent_cname
!= null) {
296 register_symbol (parent_cname
+ "." + item
.get_cname (), item
);
304 public override void visit_constant (Constant item
) {
305 register_symbol (item
.get_cname (), item
);
311 public override void visit_delegate (Delegate item
) {
312 register_symbol (item
.get_cname (), item
);
318 public override void visit_signal (Api
.Signal item
) {
319 string parent_cname
= get_parent_type_cname (item
);
320 assert (parent_cname
!= null);
322 string? default_impl_cname
= item
.get_default_impl_cname ();
323 string cname
= item
.get_cname ();
324 register_symbol (parent_cname
+"::"+cname
, item
);
326 if (item
.is_virtual
) {
327 // only supported by classes
328 register_symbol (parent_cname
+ "Class." + item
.name
, item
);
331 Vala
.Collection
<Interface
> interfaces
= null;
332 Vala
.Collection
<Class
> classes
= null;
334 if (item
.parent is Interface
) {
335 interfaces
= ((Api
.Interface
) item
.parent
).get_known_related_interfaces ();
336 classes
= ((Api
.Interface
) item
.parent
).get_known_implementations ();
337 } else if (item
.parent is Class
) {
338 interfaces
= ((Api
.Class
) item
.parent
).get_known_derived_interfaces ();
339 classes
= ((Api
.Class
) item
.parent
).get_known_child_classes ();
342 foreach (Interface iface
in interfaces
) {
343 register_symbol (iface
.get_cname () + "::" + cname
, item
);
346 foreach (Class cl
in classes
) {
347 register_symbol (cl
.get_cname () + "::" + cname
, item
);
350 if (default_impl_cname
!= null) {
351 register_symbol (default_impl_cname
, item
);
358 public override void visit_method (Method item
) {
359 if (item
.is_abstract
|| item
.is_virtual
|| item
.is_override
) {
360 string parent_cname
= get_parent_type_cname (item
);
362 if (item
.parent is Class
) {
363 register_symbol (parent_cname
+ "Class." + item
.name
, item
);
365 register_symbol (parent_cname
+ "Iface." + item
.name
, item
);
368 // Allow to resolve invalid links:
369 register_symbol (parent_cname
+ "." + item
.name
, item
);
372 register_symbol (item
.get_cname (), item
);
378 public override void visit_error_domain (ErrorDomain item
) {
379 register_symbol (item
.get_cname (), item
);
380 item
.accept_all_children (this
, false);
386 public override void visit_error_code (ErrorCode item
) {
387 register_symbol (item
.get_cname (), item
);
393 public override void visit_enum (Api
.Enum item
) {
394 register_symbol (item
.get_cname (), item
);
395 item
.accept_all_children (this
, false);
401 public override void visit_enum_value (Api
.EnumValue item
) {
402 register_symbol (item
.get_cname (), item
);