Line data Source code
1 : /* valagidlparser.vala
2 : *
3 : * Copyright (C) 2006-2010 Jürg Billeter
4 : * Copyright (C) 2006-2008 Raffaele Sandrini
5 : *
6 : * This library is free software; you can redistribute it and/or
7 : * modify it under the terms of the GNU Lesser General Public
8 : * License as published by the Free Software Foundation; either
9 : * version 2.1 of the License, or (at your option) any later version.
10 :
11 : * This library is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * Lesser General Public License for more details.
15 :
16 : * You should have received a copy of the GNU Lesser General Public
17 : * License along with this library; if not, write to the Free Software
18 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 : *
20 : * Author:
21 : * Jürg Billeter <j@bitron.ch>
22 : * Raffaele Sandrini <raffaele@sandrini.ch>
23 : */
24 :
25 : using GLib;
26 :
27 : /**
28 : * Code visitor parsing all GIDL files.
29 : */
30 213 : public class Vala.GIdlParser : CodeVisitor {
31 71 : private CodeContext context;
32 :
33 71 : private SourceFile current_source_file;
34 :
35 71 : private SourceReference current_source_reference;
36 :
37 71 : private Namespace current_namespace;
38 71 : private TypeSymbol current_data_type;
39 71 : private Map<string,string> codenode_attributes_map;
40 71 : private Map<PatternSpec*,string> codenode_attributes_patterns;
41 71 : private Set<string> current_type_symbol_set;
42 :
43 71 : private Map<string,TypeSymbol> cname_type_map;
44 :
45 : static GLib.Regex type_from_string_regex;
46 :
47 : /**
48 : * Parse all source files in the specified code context and build a
49 : * code tree.
50 : *
51 : * @param context a code context
52 : */
53 71 : public void parse (CodeContext context) {
54 71 : cname_type_map = new HashMap<string,TypeSymbol> (str_hash, str_equal);
55 :
56 71 : this.context = context;
57 71 : context.accept (this);
58 :
59 71 : cname_type_map = null;
60 : }
61 :
62 3305 : public override void visit_namespace (Namespace ns) {
63 3305 : ns.accept_children (this);
64 : }
65 :
66 20843 : public override void visit_class (Class cl) {
67 20843 : visit_type (cl);
68 : }
69 :
70 8066 : public override void visit_struct (Struct st) {
71 8066 : visit_type (st);
72 : }
73 :
74 2840 : public override void visit_interface (Interface iface) {
75 2840 : visit_type (iface);
76 : }
77 :
78 12608 : public override void visit_enum (Enum en) {
79 12608 : visit_type (en);
80 : }
81 :
82 1513 : public override void visit_error_domain (ErrorDomain ed) {
83 1513 : visit_type (ed);
84 : }
85 :
86 10813 : public override void visit_delegate (Delegate d) {
87 10813 : visit_type (d);
88 : }
89 :
90 56683 : private void visit_type (TypeSymbol t) {
91 56683 : if (!cname_type_map.contains (get_cname (t))) {
92 54215 : cname_type_map[get_cname (t)] = t;
93 : }
94 : }
95 :
96 577 : public override void visit_source_file (SourceFile source_file) {
97 577 : if (source_file.filename.has_suffix (".gi")) {
98 25 : parse_file (source_file);
99 : }
100 : }
101 :
102 50 : private void parse_file (SourceFile source_file) {
103 25 : string metadata_filename = "%s.metadata".printf (source_file.filename.substring (0, source_file.filename.length - ".gi".length));
104 :
105 25 : current_source_file = source_file;
106 :
107 25 : codenode_attributes_map = new HashMap<string,string> (str_hash, str_equal);
108 25 : codenode_attributes_patterns = new HashMap<PatternSpec*,string> (direct_hash, (EqualFunc<PatternSpec>) PatternSpec.equal);
109 :
110 25 : if (FileUtils.test (metadata_filename, FileTest.EXISTS)) {
111 25 : try {
112 : string metadata;
113 25 : FileUtils.get_contents (metadata_filename, out metadata, null);
114 :
115 2432 : foreach (unowned string line in metadata.split ("\n")) {
116 2357 : if (line.has_prefix ("#")) {
117 : // ignore comment lines
118 26 : continue;
119 : }
120 :
121 2331 : var tokens = line.split (" ", 2);
122 :
123 2331 : if (null == tokens[0]) {
124 200 : continue;
125 : }
126 :
127 2231 : if (-1 != tokens[0].index_of_char ('*')) {
128 48 : PatternSpec* pattern = new PatternSpec (tokens[0]);
129 48 : codenode_attributes_patterns[pattern] = tokens[0];
130 : }
131 :
132 2231 : codenode_attributes_map[tokens[0]] = tokens[1];
133 : }
134 : } catch (FileError e) {
135 0 : Report.error (null, "Unable to read metadata file: %s", e.message);
136 : }
137 : }
138 :
139 75 : try {
140 25 : var modules = Idl.parse_file (source_file.filename);
141 :
142 25 : current_source_reference = new SourceReference (source_file, SourceLocation (null, 0, 0), SourceLocation (null, 0, 0));
143 :
144 50 : foreach (weak IdlModule module in modules) {
145 25 : var ns = parse_module (module);
146 25 : if (ns != null) {
147 9 : context.root.add_namespace (ns);
148 : }
149 : }
150 : } catch (MarkupError e) {
151 0 : Report.error (null, "Unable to parse GIDL file: %s", e.message);
152 : }
153 : }
154 :
155 1272 : private string fix_type_name (string type_name, Symbol container) {
156 1272 : var attributes = get_attributes (type_name);
157 1272 : if (attributes != null) {
158 791 : foreach (string attr in attributes) {
159 208 : var nv = attr.split ("=", 2);
160 208 : if (nv[0] == "name") {
161 0 : return eval (nv[1]);
162 : }
163 : }
164 : }
165 :
166 1280 : if (type_name.has_prefix (container.name)) {
167 1250 : return type_name.substring (container.name.length);
168 : } else {
169 22 : var cprefix = get_cprefix (container);
170 22 : if (type_name.has_prefix (cprefix)) {
171 14 : return type_name.substring (cprefix.length);;
172 : }
173 : }
174 :
175 16 : return type_name;
176 : }
177 :
178 2628 : private string fix_const_name (string const_name, Symbol container) {
179 2628 : var pref = get_lower_case_cprefix (container).ascii_up ();
180 2628 : if (const_name.has_prefix (pref)) {
181 2579 : return const_name.substring (pref.length);
182 : }
183 98 : return const_name;
184 : }
185 :
186 9185 : private string get_cheader_filename (Symbol sym) {
187 9185 : var cheader_filename = sym.get_attribute_string ("CCode", "cheader_filename");
188 9185 : if (cheader_filename != null) {
189 9185 : return cheader_filename;
190 : }
191 4896 : if (sym.parent_symbol != null) {
192 3995 : return get_cheader_filename (sym.parent_symbol);
193 901 : } else if (sym.source_reference != null) {
194 0 : return sym.source_reference.file.get_cinclude_filename ();
195 : }
196 901 : return "";
197 : }
198 :
199 135537 : private string get_cname (Symbol sym, Symbol? container = null) {
200 135537 : if (container == null) {
201 128055 : container = sym.parent_symbol;
202 : }
203 135537 : var cname = sym.get_attribute_string ("CCode", "cname");
204 135537 : if (cname != null) {
205 135537 : return cname;
206 : }
207 120903 : if (sym is Method) {
208 7482 : var name = sym.name;
209 7482 : if (sym is CreationMethod) {
210 435 : if (name == null || name == ".new") {
211 287 : name = "new";
212 : } else {
213 148 : name = "new_%s".printf (name);
214 : }
215 : }
216 7482 : if (container != null) {
217 7482 : return "%s%s".printf (get_lower_case_cprefix (container), name);
218 : } else {
219 0 : return name;
220 : }
221 : } else {
222 113421 : if (container != null) {
223 113421 : return "%s%s".printf (get_cprefix (container), sym.name);
224 : } else {
225 0 : return sym.name;
226 : }
227 : }
228 : }
229 :
230 0 : private string get_finish_cname (Method m) {
231 0 : var finish_cname = m.get_attribute_string ("CCode", "finish_name");
232 0 : if (finish_cname != null) {
233 0 : return finish_cname;
234 : }
235 0 : var result = get_cname (m);
236 0 : if (result.has_suffix ("_async")) {
237 0 : result = result.substring (0, result.length - "_async".length);
238 : }
239 0 : return result + "_finish";
240 : }
241 :
242 15767 : private string get_lower_case_cname (Symbol sym) {
243 15767 : var lower_case_csuffix = Symbol.camel_case_to_lower_case (sym.name);
244 15767 : if (sym is ObjectTypeSymbol) {
245 : // remove underscores in some cases to avoid conflicts of type macros
246 6329 : if (lower_case_csuffix.has_prefix ("type_")) {
247 0 : lower_case_csuffix = "type" + lower_case_csuffix.substring ("type_".length);
248 6329 : } else if (lower_case_csuffix.has_prefix ("is_")) {
249 0 : lower_case_csuffix = "is" + lower_case_csuffix.substring ("is_".length);
250 : }
251 6329 : if (lower_case_csuffix.has_suffix ("_class")) {
252 0 : lower_case_csuffix = lower_case_csuffix.substring (0, lower_case_csuffix.length - "_class".length) + "class";
253 : }
254 : }
255 15767 : if (sym.parent_symbol != null) {
256 14779 : return "%s%s".printf (get_lower_case_cprefix (sym.parent_symbol), lower_case_csuffix);
257 : } else {
258 15767 : return lower_case_csuffix;
259 : }
260 : }
261 :
262 25314 : private string get_lower_case_cprefix (Symbol sym) {
263 25314 : if (sym.name == null) {
264 5971 : return "";
265 : }
266 : string cprefix;
267 19343 : cprefix = sym.get_attribute_string ("CCode", "lower_case_cprefix");
268 19343 : if (cprefix == null && (sym is ObjectTypeSymbol || sym is Struct)) {
269 6498 : cprefix = sym.get_attribute_string ("CCode", "cprefix");
270 : }
271 19343 : if (cprefix != null) {
272 25314 : return cprefix;
273 : }
274 15767 : return get_lower_case_cname (sym) + "_";
275 : }
276 :
277 122100 : public string get_cprefix (Symbol sym) {
278 122100 : if (sym is ObjectTypeSymbol) {
279 0 : return get_cname (sym);
280 122100 : } else if (sym is Enum || sym is ErrorDomain) {
281 0 : return "%s_".printf (get_lower_case_cname (sym).ascii_up ());
282 122100 : } else if (sym is Namespace) {
283 122100 : if (sym.name != null) {
284 112875 : var cprefix = sym.get_attribute_string ("CCode", "cprefix");
285 112875 : if (cprefix != null) {
286 122100 : return cprefix;
287 : }
288 10499 : if (sym.parent_symbol != null) {
289 8657 : return "%s%s".printf (get_cprefix (sym.parent_symbol), sym.name);
290 : } else {
291 3684 : return sym.name;
292 : }
293 : } else {
294 9225 : return "";
295 : }
296 0 : } else if (sym.name != null) {
297 0 : return sym.name;
298 : }
299 0 : return "";
300 : }
301 :
302 7734 : private string[] get_attributes_for_node (IdlNode node) {
303 : string name;
304 :
305 7734 : if (node.type == IdlNodeTypeId.FUNCTION) {
306 3094 : name = ((IdlNodeFunction) node).symbol;
307 6187 : } else if (node.type == IdlNodeTypeId.SIGNAL) {
308 0 : name = "%s::%s".printf (get_cname (current_data_type), node.name);
309 6187 : } else if (node.type == IdlNodeTypeId.PROPERTY) {
310 0 : name = "%s:%s".printf (get_cname (current_data_type), node.name);
311 6187 : } else if (node.type == IdlNodeTypeId.FIELD) {
312 0 : name = "%s.%s".printf (get_cname (current_data_type), node.name);
313 : } else {
314 12374 : name = node.name;
315 : }
316 :
317 7734 : return get_attributes (name);
318 : }
319 :
320 5195 : private void add_symbol_to_container (Symbol container, Symbol sym) {
321 5195 : if (container is Class) {
322 0 : unowned Class cl = (Class) container;
323 :
324 0 : if (sym is Class) {
325 0 : cl.add_class ((Class) sym);
326 0 : } else if (sym is Constant) {
327 0 : cl.add_constant ((Constant) sym);
328 0 : } else if (sym is Enum) {
329 0 : cl.add_enum ((Enum) sym);
330 0 : } else if (sym is Field) {
331 0 : cl.add_field ((Field) sym);
332 0 : } else if (sym is Method) {
333 0 : cl.add_method ((Method) sym);
334 0 : } else if (sym is Property) {
335 0 : cl.add_property ((Property) sym);
336 0 : } else if (sym is Signal) {
337 0 : cl.add_signal ((Signal) sym);
338 0 : } else if (sym is Struct) {
339 0 : cl.add_struct ((Struct) sym);
340 : }
341 5195 : } else if (container is Enum) {
342 0 : unowned Enum en = (Enum) container;
343 :
344 0 : if (sym is EnumValue) {
345 0 : en.add_value ((EnumValue) sym);
346 0 : } else if (sym is Constant) {
347 0 : en.add_constant ((Constant) sym);
348 0 : } else if (sym is Method) {
349 0 : en.add_method ((Method) sym);
350 : }
351 5195 : } else if (container is Interface) {
352 0 : unowned Interface iface = (Interface) container;
353 :
354 0 : if (sym is Class) {
355 0 : iface.add_class ((Class) sym);
356 0 : } else if (sym is Constant) {
357 0 : iface.add_constant ((Constant) sym);
358 0 : } else if (sym is Enum) {
359 0 : iface.add_enum ((Enum) sym);
360 0 : } else if (sym is Field) {
361 0 : iface.add_field ((Field) sym);
362 0 : } else if (sym is Method) {
363 0 : iface.add_method ((Method) sym);
364 0 : } else if (sym is Property) {
365 0 : iface.add_property ((Property) sym);
366 0 : } else if (sym is Signal) {
367 0 : iface.add_signal ((Signal) sym);
368 0 : } else if (sym is Struct) {
369 0 : iface.add_struct ((Struct) sym);
370 : }
371 5195 : } else if (container is Namespace) {
372 5195 : unowned Namespace ns = (Namespace) container;
373 :
374 5195 : if (sym is Namespace) {
375 5 : ns.add_namespace ((Namespace) sym);
376 5190 : } else if (sym is Class) {
377 553 : ns.add_class ((Class) sym);
378 4637 : } else if (sym is Constant) {
379 2628 : ns.add_constant ((Constant) sym);
380 2009 : } else if (sym is Delegate) {
381 166 : ns.add_delegate ((Delegate) sym);
382 1843 : } else if (sym is Enum) {
383 376 : ns.add_enum ((Enum) sym);
384 1467 : } else if (sym is ErrorDomain) {
385 7 : ns.add_error_domain ((ErrorDomain) sym);
386 1460 : } else if (sym is Field) {
387 0 : unowned Field field = (Field) sym;
388 0 : if (field.binding == MemberBinding.INSTANCE) {
389 0 : field.binding = MemberBinding.STATIC;
390 : }
391 0 : ns.add_field (field);
392 1460 : } else if (sym is Interface) {
393 17 : ns.add_interface ((Interface) sym);
394 1443 : } else if (sym is Method) {
395 1381 : unowned Method method = (Method) sym;
396 1381 : if (method.binding == MemberBinding.INSTANCE) {
397 0 : method.binding = MemberBinding.STATIC;
398 : }
399 1381 : ns.add_method (method);
400 62 : } else if (sym is Namespace) {
401 0 : ns.add_namespace ((Namespace) sym);
402 62 : } else if (sym is Struct) {
403 62 : ns.add_struct ((Struct) sym);
404 : }
405 0 : } else if (container is Struct) {
406 0 : unowned Struct st = (Struct) container;
407 :
408 0 : if (sym is Constant) {
409 0 : st.add_constant ((Constant) sym);
410 0 : } else if (sym is Field) {
411 0 : st.add_field ((Field) sym);
412 0 : } else if (sym is Method) {
413 0 : st.add_method ((Method) sym);
414 0 : } else if (sym is Property) {
415 0 : st.add_property ((Property) sym);
416 : }
417 : }
418 :
419 5195 : if (!(sym is Namespace) && container is Namespace) {
420 : // set C headers
421 5190 : sym.set_attribute_string ("CCode", "cheader_filename", get_cheader_filename (sym));
422 : }
423 : }
424 :
425 5439 : private void parse_node (IdlNode node, IdlModule module, Symbol container) {
426 5605 : if (node.type == IdlNodeTypeId.CALLBACK) {
427 170 : var cb = parse_delegate ((IdlNodeFunction) node);
428 170 : if (cb == null) {
429 : return;
430 : }
431 166 : cb.name = fix_type_name (cb.name, container);
432 166 : add_symbol_to_container (container, cb);
433 166 : current_source_file.add_node (cb);
434 : } else if (node.type == IdlNodeTypeId.STRUCT) {
435 364 : parse_struct ((IdlNodeStruct) node, container, module);
436 : } else if (node.type == IdlNodeTypeId.UNION) {
437 1 : parse_union ((IdlNodeUnion) node, container, module);
438 : } else if (node.type == IdlNodeTypeId.BOXED) {
439 34 : parse_boxed ((IdlNodeBoxed) node, container, module);
440 : } else if (node.type == IdlNodeTypeId.ENUM) {
441 318 : parse_enum ((IdlNodeEnum) node, container, module, false);
442 : } else if (node.type == IdlNodeTypeId.FLAGS) {
443 65 : parse_enum ((IdlNodeEnum) node, container, module, true);
444 : } else if (node.type == IdlNodeTypeId.OBJECT) {
445 301 : parse_object ((IdlNodeInterface) node, container, module);
446 : } else if (node.type == IdlNodeTypeId.INTERFACE) {
447 23 : parse_interface ((IdlNodeInterface) node, container, module);
448 2628 : } else if (node.type == IdlNodeTypeId.CONSTANT) {
449 2631 : var c = parse_constant ((IdlNodeConstant) node);
450 2631 : if (c != null) {
451 2628 : c.name = fix_const_name (c.name, container);
452 2628 : add_symbol_to_container (container, c);
453 2628 : current_source_file.add_node (c);
454 : }
455 1381 : } else if (node.type == IdlNodeTypeId.FUNCTION) {
456 1532 : var m = parse_function ((IdlNodeFunction) node);
457 1532 : if (m != null) {
458 1381 : if (!(m is CreationMethod)) {
459 1381 : m.binding = MemberBinding.STATIC;
460 : }
461 1381 : add_symbol_to_container (container, m);
462 1381 : current_source_file.add_node (m);
463 : }
464 : }
465 : }
466 :
467 2310 : private Symbol? get_container_from_name (string name) {
468 2310 : var path = name.split (".");
469 45352 : Symbol? cp = current_namespace;
470 2310 : if (cp.parent_symbol != context.root) {
471 30 : cp = cp.parent_symbol;
472 : }
473 : Symbol? cc = null;
474 :
475 4620 : foreach ( unowned string tok in path ) {
476 2310 : cc = cp.scope.lookup (tok);
477 2310 : if ( cc == null ) {
478 5 : cc = new Namespace (tok, current_source_reference);
479 5 : add_symbol_to_container (cp, cc);
480 : }
481 2310 : cp = cc;
482 : }
483 :
484 2310 : return cc;
485 : }
486 :
487 25 : private Namespace? parse_module (IdlModule module) {
488 25 : Symbol sym = context.root.scope.lookup (module.name);
489 : Namespace ns;
490 25 : if (sym is Namespace) {
491 16 : ns = (Namespace) sym;
492 16 : if (ns.external_package) {
493 25 : ns.attributes = null;
494 16 : ns.source_reference = current_source_reference;
495 : }
496 : } else {
497 9 : ns = new Namespace (module.name, current_source_reference);
498 : }
499 :
500 50 : current_namespace = ns;
501 :
502 25 : var attributes = get_attributes (ns.name);
503 25 : if (attributes != null) {
504 180 : foreach (string attr in attributes) {
505 52 : var nv = attr.split ("=", 2);
506 52 : if (nv[0] == "cheader_filename") {
507 24 : ns.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
508 28 : } else if (nv[0] == "cprefix") {
509 5 : ns.set_attribute_string ("CCode", "cprefix", eval (nv[1]));
510 23 : } else if (nv[0] == "lower_case_cprefix") {
511 5 : ns.set_attribute_string ("CCode", "lower_case_cprefix", eval (nv[1]));
512 18 : } else if (nv[0] == "gir_namespace") {
513 5 : ns.source_reference.file.gir_namespace = eval (nv[1]);
514 5 : ns.set_attribute_string ("CCode", "gir_namespace", eval (nv[1]));
515 13 : } else if (nv[0] == "gir_version") {
516 5 : ns.source_reference.file.gir_version = eval (nv[1]);
517 5 : ns.set_attribute_string ("CCode", "gir_version", eval (nv[1]));
518 8 : } else if (nv[0] == "deprecated") {
519 0 : if (eval (nv[1]) == "1") {
520 0 : ns.set_attribute_bool ("Version", "deprecated", true);
521 : }
522 8 : } else if (nv[0] == "replacement") {
523 8 : ns.set_attribute_string ("Version", "replacement", eval (nv[1]));
524 0 : } else if (nv[0] == "deprecated_since") {
525 0 : ns.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
526 : }
527 : }
528 : }
529 :
530 25 : var deferred = new ArrayList<unowned IdlNode> ();
531 :
532 10903 : foreach (weak IdlNode node in module.entries) {
533 5439 : bool is_deferred = false;
534 5439 : var child_attributes = get_attributes_for_node (node);
535 5439 : if (child_attributes != null) {
536 12591 : foreach (unowned string attr in child_attributes) {
537 4950 : var nv = attr.split ("=", 2);
538 4950 : if (nv[0] == "parent") {
539 2295 : deferred.add (node);
540 2295 : is_deferred = true;
541 : }
542 : }
543 : }
544 :
545 2691 : if (!is_deferred) {
546 3144 : parse_node (node, module, ns);
547 : }
548 : }
549 :
550 2320 : foreach (unowned IdlNode node in deferred) {
551 2295 : Symbol container = ns;
552 2295 : var child_attributes = get_attributes_for_node (node);
553 2295 : if (child_attributes != null) {
554 11239 : foreach (unowned string attr in child_attributes) {
555 4472 : var nv = attr.split ("=", 2);
556 4472 : if (nv[0] == "parent") {
557 2295 : container = get_container_from_name (eval (nv[1]));
558 : }
559 : }
560 : }
561 :
562 2295 : if (container is Namespace) {
563 2295 : current_namespace = (Namespace) container;
564 : } else {
565 0 : current_data_type = (TypeSymbol) container;
566 : }
567 2295 : parse_node (node, module, container);
568 4590 : current_namespace = ns;
569 2295 : current_data_type = null;
570 : }
571 :
572 25 : current_namespace = null;
573 :
574 25 : if (sym is Namespace) {
575 32 : return null;
576 : }
577 18 : return ns;
578 : }
579 :
580 170 : private Delegate? parse_delegate (IdlNodeFunction f_node) {
581 170 : weak IdlNode node = (IdlNode) f_node;
582 :
583 170 : var return_type = parse_param (f_node.result);
584 :
585 170 : var cb = new Delegate (node.name, return_type, current_source_reference);
586 170 : cb.access = SymbolAccessibility.PUBLIC;
587 170 : cb.has_target = false;
588 :
589 170 : bool check_has_target = true;
590 170 : bool suppress_throws = false;
591 170 : string? error_types = null;
592 :
593 170 : var attributes = get_attributes (node.name);
594 170 : if (attributes != null) {
595 48 : foreach (string attr in attributes) {
596 19 : var nv = attr.split ("=", 2);
597 19 : if (nv[0] == "hidden") {
598 4 : if (eval (nv[1]) == "1") {
599 12 : return null;
600 : }
601 15 : } else if (nv[0] == "cheader_filename") {
602 1 : cb.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
603 14 : } else if (nv[0] == "has_target") {
604 5 : if (eval (nv[1]) == "0") {
605 : check_has_target = false;
606 5 : } else if (eval (nv[1]) == "1") {
607 5 : cb.has_target = true;
608 : }
609 9 : } else if (nv[0] == "transfer_ownership") {
610 3 : if (eval (nv[1]) == "1") {
611 3 : return_type.value_owned = true;
612 : }
613 6 : } else if (nv[0] == "is_array") {
614 0 : if (eval (nv[1]) == "1") {
615 0 : return_type.value_owned = true;
616 0 : return_type = new ArrayType (return_type, 1, return_type.source_reference);
617 0 : cb.return_type = return_type;
618 : }
619 6 : } else if (nv[0] == "throws") {
620 0 : if (eval (nv[1]) == "0") {
621 15 : suppress_throws = true;
622 : }
623 6 : } else if (nv[0] == "error_types") {
624 0 : error_types = eval (nv[1]);
625 6 : } else if (nv[0] == "array_length_type") {
626 0 : cb.set_attribute_string ("CCode", "array_length_type", eval (nv[1]));
627 6 : } else if (nv[0] == "type_name") {
628 0 : cb.return_type = return_type = parse_type_from_string (eval (nv[1]), return_type.value_owned);
629 6 : } else if (nv[0] == "deprecated") {
630 1 : if (eval (nv[1]) == "1") {
631 1 : cb.set_attribute_bool ("Version", "deprecated", true);
632 : }
633 5 : } else if (nv[0] == "replacement") {
634 0 : cb.set_attribute_string ("Version", "replacement", eval (nv[1]));
635 5 : } else if (nv[0] == "deprecated_since") {
636 1 : cb.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
637 4 : } else if (nv[0] == "type_arguments") {
638 0 : parse_type_arguments_from_string (return_type, eval (nv[1]));
639 4 : } else if (nv[0] == "instance_pos") {
640 2 : cb.set_attribute_double ("CCode", "instance_pos", double.parse (eval (nv[1])));
641 2 : } else if (nv[0] == "type_parameters") {
642 0 : foreach (string type_param_name in eval (nv[1]).split (",")) {
643 0 : cb.add_type_parameter (new TypeParameter (type_param_name, current_source_reference));
644 : }
645 2 : } else if (nv[0] == "experimental") {
646 0 : if (eval (nv[1]) == "1") {
647 0 : cb.set_attribute_bool ("Version", "experimental", true);
648 : }
649 : }
650 : }
651 : }
652 :
653 166 : uint remaining_params = f_node.parameters.length ();
654 695 : foreach (weak IdlNodeParam param in f_node.parameters) {
655 529 : weak IdlNode param_node = (IdlNode) param;
656 :
657 969 : if (check_has_target && remaining_params == 1 && (param_node.name == "user_data" || param_node.name == "data")) {
658 : // hide user_data parameter for instance delegates
659 88 : cb.has_target = true;
660 : } else {
661 : // check for GError parameter
662 441 : if (suppress_throws == false && param_is_exception (param)) {
663 1 : if (error_types == null)
664 1 : cb.add_error_type (parse_type (param.type));
665 1 : remaining_params--;
666 1 : continue;
667 : }
668 :
669 440 : string param_name = param_node.name;
670 440 : if (param_name == "string") {
671 : // avoid conflict with string type
672 1 : param_name = "str";
673 439 : } else if (param_name == "self") {
674 : // avoid conflict with delegate target
675 0 : param_name = "_self";
676 : }
677 :
678 : ParameterDirection direction;
679 440 : var param_type = parse_param (param, out direction);
680 440 : var p = new Parameter (param_name, param_type, current_source_reference);
681 440 : p.direction = direction;
682 :
683 440 : bool hide_param = false;
684 440 : bool show_param = false;
685 440 : bool array_requested = false;
686 440 : bool out_requested = false;
687 880 : attributes = get_attributes ("%s.%s".printf (node.name, param_node.name));
688 440 : if (attributes != null) {
689 134 : foreach (string attr in attributes) {
690 37 : var nv = attr.split ("=", 2);
691 37 : if (nv[0] == "hidden") {
692 10 : if (eval (nv[1]) == "1") {
693 : hide_param = true;
694 0 : } else if (eval (nv[1]) == "0") {
695 0 : show_param = true;
696 : }
697 27 : } else if (nv[0] == "is_array") {
698 7 : if (eval (nv[1]) == "1") {
699 7 : param_type.value_owned = true;
700 7 : param_type = new ArrayType (param_type, 1, param_type.source_reference);
701 7 : p.variable_type = param_type;
702 7 : if (!out_requested) {
703 7 : p.direction = ParameterDirection.IN;
704 : }
705 : array_requested = true;
706 : }
707 20 : } else if (nv[0] == "is_out") {
708 2 : if (eval (nv[1]) == "1") {
709 2 : p.direction = ParameterDirection.OUT;
710 2 : out_requested = true;
711 2 : if (!array_requested && param_type is ArrayType) {
712 0 : var array_type = (ArrayType) param_type;
713 0 : param_type = array_type.element_type;
714 0 : p.variable_type = param_type;
715 : }
716 : }
717 18 : } else if (nv[0] == "is_ref") {
718 2 : if (eval (nv[1]) == "1") {
719 2 : p.direction = ParameterDirection.REF;
720 2 : if (!array_requested && param_type is ArrayType) {
721 0 : var array_type = (ArrayType) param_type;
722 0 : param_type = array_type.element_type;
723 0 : p.variable_type = param_type;
724 : }
725 : }
726 16 : } else if (nv[0] == "takes_ownership") {
727 0 : if (eval (nv[1]) == "1") {
728 0 : param_type.value_owned = true;
729 : }
730 16 : } else if (nv[0] == "nullable") {
731 3 : if (eval (nv[1]) == "1") {
732 3 : param_type.nullable = true;
733 : }
734 13 : } else if (nv[0] == "type_arguments") {
735 0 : parse_type_arguments_from_string (param_type, eval (nv[1]));
736 13 : } else if (nv[0] == "no_array_length") {
737 0 : if (eval (nv[1]) == "1") {
738 0 : p.set_attribute_bool ("CCode", "array_length", false);
739 : }
740 13 : } else if (nv[0] == "array_length_type") {
741 2 : p.set_attribute_string ("CCode", "array_length_type", eval (nv[1]));
742 11 : } else if (nv[0] == "array_null_terminated") {
743 1 : if (eval (nv[1]) == "1") {
744 1 : p.set_attribute_bool ("CCode", "array_length", false);
745 1 : p.set_attribute_bool ("CCode", "array_null_terminated", true);
746 : }
747 10 : } else if (nv[0] == "type_name") {
748 2 : p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
749 : }
750 : }
751 : }
752 :
753 440 : if (show_param || !hide_param) {
754 430 : cb.add_parameter (p);
755 : }
756 : }
757 :
758 528 : remaining_params--;
759 : }
760 :
761 166 : if (suppress_throws == false && error_types != null) {
762 0 : var type_args = eval (error_types).split (",");
763 0 : foreach (unowned string type_arg in type_args) {
764 0 : cb.add_error_type (parse_type_from_string (type_arg, true));
765 : }
766 : }
767 :
768 332 : return cb;
769 : }
770 :
771 399 : private bool is_reference_type (string cname) {
772 399 : var st_attributes = get_attributes (cname);
773 399 : if (st_attributes != null) {
774 321 : foreach (string attr in st_attributes) {
775 115 : var nv = attr.split ("=", 2);
776 115 : if (nv[0] == "is_value_type" && eval (nv[1]) == "1") {
777 136 : return false;
778 : }
779 : }
780 : }
781 331 : return true;
782 : }
783 :
784 702 : private void parse_struct (IdlNodeStruct st_node, Symbol container, IdlModule module) {
785 364 : weak IdlNode node = (IdlNode) st_node;
786 :
787 364 : if (st_node.deprecated) {
788 : return;
789 : }
790 :
791 364 : string name = fix_type_name (node.name, container);
792 :
793 702 : if (!is_reference_type (node.name)) {
794 61 : var st = container.scope.lookup (name) as Struct;
795 112 : if (st == null) {
796 56 : st = new Struct (name, current_source_reference);
797 56 : st.access = SymbolAccessibility.PUBLIC;
798 :
799 56 : var st_attributes = get_attributes (node.name);
800 56 : if (st_attributes != null) {
801 302 : foreach (string attr in st_attributes) {
802 82 : var nv = attr.split ("=", 2);
803 82 : if (nv[0] == "cheader_filename") {
804 1 : st.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
805 81 : } else if (nv[0] == "hidden") {
806 0 : if (eval (nv[1]) == "1") {
807 0 : return;
808 : }
809 81 : } else if (nv[0] == "base_type") {
810 0 : st.base_type = parse_type_string (eval (nv[1]));
811 81 : } else if (nv[0] == "rank") {
812 0 : st.rank = int.parse (eval (nv[1]));
813 81 : } else if (nv[0] == "simple_type") {
814 1 : if (eval (nv[1]) == "1") {
815 1 : st.set_simple_type (true);
816 : }
817 80 : } else if (nv[0] == "immutable") {
818 0 : if (eval (nv[1]) == "1") {
819 0 : st.set_attribute ("Immutable", true);
820 : }
821 80 : } else if (nv[0] == "has_type_id") {
822 20 : if (eval (nv[1]) == "0") {
823 20 : st.set_attribute_bool ("CCode", "has_type_id", false);
824 : }
825 60 : } else if (nv[0] == "type_id") {
826 0 : st.set_attribute_string ("CCode", "type_id", eval (nv[1]));
827 60 : } else if (nv[0] == "has_copy_function") {
828 1 : if (eval (nv[1]) == "0") {
829 1 : st.set_attribute_bool ("CCode", "has_copy_function", false);
830 : }
831 59 : } else if (nv[0] == "deprecated") {
832 1 : if (eval (nv[1]) == "1") {
833 1 : st.set_attribute_bool ("Version", "deprecated", true);
834 : }
835 58 : } else if (nv[0] == "replacement") {
836 0 : st.set_attribute_string ("Version", "replacement", eval (nv[1]));
837 58 : } else if (nv[0] == "deprecated_since") {
838 1 : st.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
839 57 : } else if (nv[0] == "has_destroy_function") {
840 1 : if (eval (nv[1]) == "0") {
841 1 : st.set_attribute_bool ("CCode", "has_destroy_function", false);
842 : }
843 56 : } else if (nv[0] == "experimental") {
844 0 : if (eval (nv[1]) == "1") {
845 0 : st.set_attribute_bool ("Version", "experimental", true);
846 : }
847 : }
848 : }
849 : }
850 :
851 56 : add_symbol_to_container (container, st);
852 56 : current_source_file.add_node (st);
853 : }
854 :
855 61 : current_data_type = st;
856 :
857 474 : foreach (weak IdlNode member in st_node.members) {
858 482 : if (member.type == IdlNodeTypeId.FUNCTION) {
859 74 : var m = parse_function ((IdlNodeFunction) member);
860 74 : if (m != null) {
861 69 : st.add_method (m);
862 : }
863 670 : } else if (member.type == IdlNodeTypeId.FIELD) {
864 339 : var f = parse_field ((IdlNodeField) member);
865 339 : if (f != null) {
866 331 : st.add_field (f);
867 : }
868 : }
869 : }
870 :
871 61 : current_data_type = null;
872 : } else {
873 303 : bool ref_function_void = false;
874 303 : string ref_function = null;
875 303 : string unref_function = null;
876 303 : string copy_function = null;
877 303 : string free_function = null;
878 :
879 303 : var cl = container.scope.lookup (name) as Class;
880 550 : if (cl == null) {
881 288 : string base_class = null;
882 288 : bool is_fundamental = false;
883 :
884 288 : cl = new Class (name, current_source_reference);
885 288 : cl.access = SymbolAccessibility.PUBLIC;
886 :
887 288 : var cl_attributes = get_attributes (node.name);
888 288 : if (cl_attributes != null) {
889 85 : foreach (string attr in cl_attributes) {
890 37 : var nv = attr.split ("=", 2);
891 37 : if (nv[0] == "cheader_filename") {
892 6 : cl.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
893 31 : } else if (nv[0] == "base_class") {
894 5 : base_class = eval (nv[1]);
895 26 : } else if (nv[0] == "hidden") {
896 26 : if (eval (nv[1]) == "1") {
897 78 : return;
898 : }
899 0 : } else if (nv[0] == "is_immutable") {
900 0 : if (eval (nv[1]) == "1") {
901 0 : cl.set_attribute ("Immutable", true);
902 : }
903 0 : } else if (nv[0] == "const_cname") {
904 0 : cl.set_attribute_string ("CCode", "const_cname", eval (nv[1]));
905 0 : } else if (nv[0] == "is_fundamental") {
906 0 : if (eval (nv[1]) == "1") {
907 11 : is_fundamental = true;
908 : }
909 0 : } else if (nv[0] == "abstract" && base_class != null) {
910 0 : if (eval (nv[1]) == "1") {
911 0 : cl.is_abstract = true;
912 : }
913 0 : } else if (nv[0] == "free_function") {
914 0 : free_function = eval (nv[1]);
915 0 : } else if (nv[0] == "ref_function") {
916 0 : ref_function = eval (nv[1]);
917 0 : } else if (nv[0] == "unref_function") {
918 0 : unref_function = eval (nv[1]);
919 0 : } else if (nv[0] == "copy_function") {
920 0 : copy_function = eval (nv[1]);
921 0 : } else if (nv[0] == "ref_function_void") {
922 0 : if (eval (nv[1]) == "1") {
923 11 : ref_function_void = true;
924 : }
925 0 : } else if (nv[0] == "deprecated") {
926 0 : if (eval (nv[1]) == "1") {
927 0 : cl.set_attribute_bool ("Version", "deprecated", true);
928 : }
929 0 : } else if (nv[0] == "replacement") {
930 0 : cl.set_attribute_string ("Version", "replacement", eval (nv[1]));
931 0 : } else if (nv[0] == "deprecated_since") {
932 0 : cl.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
933 0 : } else if (nv[0] == "type_parameters") {
934 0 : foreach (unowned string type_param_name in eval (nv[1]).split (",")) {
935 0 : cl.add_type_parameter (new TypeParameter (type_param_name, current_source_reference));
936 : }
937 0 : } else if (nv[0] == "experimental") {
938 0 : if (eval (nv[1]) == "1") {
939 0 : cl.set_attribute_bool ("Version", "experimental", true);
940 : }
941 0 : } else if (nv[0] == "delegate_target_cname") {
942 0 : cl.set_attribute_string ("CCode", "delegate_target_cname", eval (nv[1]));
943 : }
944 : }
945 : }
946 :
947 262 : add_symbol_to_container (container, cl);
948 262 : current_source_file.add_node (cl);
949 :
950 267 : if (base_class != null) {
951 5 : var parent = parse_type_string (base_class);
952 5 : cl.add_base_type (parent);
953 : }
954 519 : if (base_class == null && !is_fundamental) {
955 257 : cl.set_attribute ("Compact", true);
956 : }
957 : }
958 :
959 554 : current_data_type = cl;
960 :
961 3062 : foreach (weak IdlNode member in st_node.members) {
962 2785 : if (member.type == IdlNodeTypeId.FUNCTION) {
963 1617 : if ((ref_function == null) && (member.name == "ref")) {
964 38 : ref_function = ((IdlNodeFunction) member).symbol;
965 19 : ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
966 1598 : } else if ((unref_function == null) && (member.name == "unref")) {
967 40 : unref_function = ((IdlNodeFunction) member).symbol;
968 3046 : } else if ((free_function == null) && (member.name == "free" || member.name == "destroy")) {
969 100 : free_function = ((IdlNodeFunction) member).symbol;
970 : } else {
971 1528 : if ((copy_function == null) && (member.name == "copy")) {
972 24 : copy_function = ((IdlNodeFunction) member).symbol;
973 : }
974 1528 : var m = parse_function ((IdlNodeFunction) member);
975 1528 : if (m != null) {
976 1468 : cl.add_method (m);
977 : }
978 : }
979 2212 : } else if (member.type == IdlNodeTypeId.FIELD) {
980 1168 : var f = parse_field ((IdlNodeField) member);
981 1168 : if (f != null) {
982 1044 : cl.add_field (f);
983 : }
984 : }
985 : }
986 :
987 277 : if (ref_function != null) {
988 19 : cl.set_attribute_string ("CCode", "ref_function", ref_function);
989 19 : if (ref_function_void) {
990 4 : cl.set_attribute_bool ("CCode", "ref_function_void", ref_function_void);
991 : }
992 258 : } else if (copy_function != null) {
993 10 : cl.set_attribute_string ("CCode", "copy_function", copy_function);
994 : }
995 277 : if (unref_function != null) {
996 20 : cl.set_attribute_string ("CCode", "unref_function", unref_function);
997 257 : } else if (free_function != null && free_function != "%sfree".printf (get_lower_case_cprefix (cl))) {
998 33 : cl.set_attribute_string ("CCode", "free_function", free_function);
999 : }
1000 :
1001 277 : current_data_type = null;
1002 : }
1003 : }
1004 :
1005 2 : private void parse_union (IdlNodeUnion un_node, Symbol container, IdlModule module) {
1006 1 : weak IdlNode node = (IdlNode) un_node;
1007 :
1008 1 : if (un_node.deprecated) {
1009 : return;
1010 : }
1011 :
1012 1 : string name = fix_type_name (node.name, container);
1013 :
1014 2 : if (!is_reference_type (node.name)) {
1015 1 : var st = container.scope.lookup (name) as Struct;
1016 0 : if (st == null) {
1017 0 : st = new Struct (name, current_source_reference);
1018 0 : st.access = SymbolAccessibility.PUBLIC;
1019 :
1020 0 : var st_attributes = get_attributes (node.name);
1021 0 : if (st_attributes != null) {
1022 0 : foreach (string attr in st_attributes) {
1023 0 : var nv = attr.split ("=", 2);
1024 0 : if (nv[0] == "cheader_filename") {
1025 0 : st.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
1026 0 : } else if (nv[0] == "deprecated") {
1027 0 : if (eval (nv[1]) == "1") {
1028 0 : st.set_attribute_bool ("Version", "deprecated", true);
1029 : }
1030 0 : } else if (nv[0] == "replacement") {
1031 0 : st.set_attribute_string ("Version", "replacement", eval (nv[1]));
1032 0 : } else if (nv[0] == "deprecated_since") {
1033 0 : st.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
1034 0 : } else if (nv[0] == "hidden") {
1035 0 : if (eval (nv[1]) == "1") {
1036 0 : return;
1037 : }
1038 0 : } else if (nv[0] == "experimental") {
1039 0 : if (eval (nv[1]) == "1") {
1040 0 : st.set_attribute_bool ("Version", "experimental", true);
1041 : }
1042 : }
1043 : }
1044 : }
1045 :
1046 0 : add_symbol_to_container (container, st);
1047 0 : current_source_file.add_node (st);
1048 : }
1049 :
1050 1 : current_data_type = st;
1051 :
1052 4 : foreach (weak IdlNode member in un_node.members) {
1053 3 : if (member.type == IdlNodeTypeId.FUNCTION) {
1054 0 : var m = parse_function ((IdlNodeFunction) member);
1055 0 : if (m != null) {
1056 0 : st.add_method (m);
1057 : }
1058 3 : } else if (member.type == IdlNodeTypeId.FIELD) {
1059 3 : var f = parse_field ((IdlNodeField) member);
1060 3 : if (f != null) {
1061 0 : st.add_field (f);
1062 : }
1063 : }
1064 : }
1065 :
1066 1 : current_data_type = null;
1067 : } else {
1068 0 : var cl = container.scope.lookup (name) as Class;
1069 0 : if (cl == null) {
1070 0 : cl = new Class (name, current_source_reference);
1071 0 : cl.access = SymbolAccessibility.PUBLIC;
1072 0 : cl.set_attribute ("Compact", true);
1073 :
1074 0 : var cl_attributes = get_attributes (node.name);
1075 0 : if (cl_attributes != null) {
1076 0 : foreach (string attr in cl_attributes) {
1077 0 : var nv = attr.split ("=", 2);
1078 0 : if (nv[0] == "cheader_filename") {
1079 0 : cl.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
1080 0 : } else if (nv[0] == "hidden") {
1081 0 : if (eval (nv[1]) == "1") {
1082 0 : return;
1083 : }
1084 : }
1085 : }
1086 : }
1087 :
1088 0 : add_symbol_to_container (container, cl);
1089 0 : current_source_file.add_node (cl);
1090 : }
1091 :
1092 0 : current_data_type = cl;
1093 :
1094 0 : bool ref_function_void = false;
1095 0 : string ref_function = null;
1096 0 : string unref_function = null;
1097 0 : string copy_function = null;
1098 0 : string free_function = null;
1099 :
1100 0 : foreach (weak IdlNode member in un_node.members) {
1101 0 : if (member.type == IdlNodeTypeId.FUNCTION) {
1102 0 : if (member.name == "ref") {
1103 0 : ref_function = ((IdlNodeFunction) member).symbol;
1104 0 : ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
1105 0 : } else if (member.name == "unref") {
1106 0 : unref_function = ((IdlNodeFunction) member).symbol;
1107 0 : } else if (member.name == "free" || member.name == "destroy") {
1108 0 : free_function = ((IdlNodeFunction) member).symbol;
1109 : } else {
1110 0 : if (member.name == "copy") {
1111 0 : copy_function = ((IdlNodeFunction) member).symbol;
1112 : }
1113 0 : var m = parse_function ((IdlNodeFunction) member);
1114 0 : if (m != null) {
1115 0 : cl.add_method (m);
1116 : }
1117 : }
1118 0 : } else if (member.type == IdlNodeTypeId.FIELD) {
1119 0 : var f = parse_field ((IdlNodeField) member);
1120 0 : if (f != null) {
1121 0 : cl.add_field (f);
1122 : }
1123 : }
1124 : }
1125 :
1126 0 : if (ref_function != null) {
1127 0 : cl.set_attribute_string ("CCode", "ref_function", ref_function);
1128 0 : if (ref_function_void) {
1129 0 : cl.set_attribute_bool ("CCode", "ref_function_void", ref_function_void);
1130 : }
1131 0 : } else if (copy_function != null) {
1132 0 : cl.set_attribute_string ("CCode", "copy_function", copy_function);
1133 : }
1134 0 : if (unref_function != null) {
1135 0 : cl.set_attribute_string ("CCode", "unref_function", unref_function);
1136 0 : } else if (free_function != null && free_function != "%sfree".printf (get_lower_case_cprefix (cl))) {
1137 0 : cl.set_attribute_string ("CCode", "free_function", free_function);
1138 : }
1139 :
1140 0 : current_data_type = null;
1141 : }
1142 : }
1143 :
1144 102 : private void parse_boxed (IdlNodeBoxed boxed_node, Symbol container, IdlModule module) {
1145 34 : weak IdlNode node = (IdlNode) boxed_node;
1146 :
1147 34 : string name = fix_type_name (node.name, container);
1148 :
1149 34 : var node_attributes = get_attributes (node.name);
1150 34 : if (node_attributes != null) {
1151 53 : foreach (string attr in node_attributes) {
1152 14 : var nv = attr.split ("=", 2);
1153 14 : if (nv[0] == "hidden") {
1154 0 : return;
1155 : }
1156 : }
1157 : }
1158 :
1159 68 : if (!is_reference_type (node.name)) {
1160 6 : var st = container.scope.lookup (name) as Struct;
1161 12 : if (st == null) {
1162 6 : st = new Struct (name, current_source_reference);
1163 6 : st.access = SymbolAccessibility.PUBLIC;
1164 :
1165 6 : var st_attributes = get_attributes (node.name);
1166 6 : if (st_attributes != null) {
1167 24 : foreach (string attr in st_attributes) {
1168 6 : var nv = attr.split ("=", 2);
1169 6 : if (nv[0] == "cheader_filename") {
1170 0 : st.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
1171 6 : } else if (nv[0] == "deprecated") {
1172 0 : if (eval (nv[1]) == "1") {
1173 0 : st.set_attribute_bool ("Version", "deprecated", true);
1174 : }
1175 6 : } else if (nv[0] == "replacement") {
1176 0 : st.set_attribute_string ("Version", "replacement", eval (nv[1]));
1177 6 : } else if (nv[0] == "deprecated_since") {
1178 0 : st.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
1179 6 : } else if (nv[0] == "immutable") {
1180 0 : if (eval (nv[1]) == "1") {
1181 0 : st.set_attribute ("Immutable", true);
1182 : }
1183 6 : } else if (nv[0] == "has_copy_function") {
1184 0 : if (eval (nv[1]) == "0") {
1185 0 : st.set_attribute_bool ("CCode", "has_copy_function", false);
1186 : }
1187 6 : } else if (nv[0] == "has_destroy_function") {
1188 0 : if (eval (nv[1]) == "0") {
1189 0 : st.set_attribute_bool ("CCode", "has_destroy_function", false);
1190 : }
1191 6 : } else if (nv[0] == "experimental") {
1192 0 : if (eval (nv[1]) == "1") {
1193 0 : st.set_attribute_bool ("Version", "experimental", true);
1194 : }
1195 : }
1196 : }
1197 : }
1198 :
1199 6 : add_symbol_to_container (container, st);
1200 6 : current_source_file.add_node (st);
1201 : }
1202 :
1203 6 : current_data_type = st;
1204 :
1205 144 : foreach (weak IdlNode member in boxed_node.members) {
1206 238 : if (member.type == IdlNodeTypeId.FUNCTION) {
1207 106 : var m = parse_function ((IdlNodeFunction) member);
1208 106 : if (m != null) {
1209 100 : st.add_method (m);
1210 : }
1211 50 : } else if (member.type == IdlNodeTypeId.FIELD) {
1212 32 : var f = parse_field ((IdlNodeField) member);
1213 32 : if (f != null) {
1214 18 : st.add_field (f);
1215 : }
1216 : }
1217 : }
1218 :
1219 6 : current_data_type = null;
1220 : } else {
1221 28 : bool ref_function_void = false;
1222 28 : string ref_function = null;
1223 28 : string unref_function = null;
1224 28 : string copy_function = null;
1225 28 : string free_function = null;
1226 :
1227 28 : var cl = container.scope.lookup (name) as Class;
1228 75 : if (cl == null) {
1229 25 : string base_class = null;
1230 :
1231 25 : cl = new Class (name, current_source_reference);
1232 25 : cl.access = SymbolAccessibility.PUBLIC;
1233 25 : cl.set_attribute ("Compact", true);
1234 25 : if (boxed_node.gtype_init != null) {
1235 25 : cl.set_attribute_string ("CCode", "type_id", "%s ()".printf (boxed_node.gtype_init));
1236 : }
1237 :
1238 25 : var cl_attributes = get_attributes (node.name);
1239 25 : if (cl_attributes != null) {
1240 21 : foreach (string attr in cl_attributes) {
1241 8 : var nv = attr.split ("=", 2);
1242 8 : if (nv[0] == "cheader_filename") {
1243 1 : cl.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
1244 7 : } else if (nv[0] == "base_class") {
1245 0 : base_class = eval (nv[1]);
1246 7 : } else if (nv[0] == "is_immutable") {
1247 2 : if (eval (nv[1]) == "1") {
1248 2 : cl.set_attribute ("Immutable", true);
1249 : }
1250 5 : } else if (nv[0] == "deprecated") {
1251 0 : if (eval (nv[1]) == "1") {
1252 0 : cl.set_attribute_bool ("Version", "deprecated", true);
1253 : }
1254 5 : } else if (nv[0] == "replacement") {
1255 0 : cl.set_attribute_string ("Version", "replacement", eval (nv[1]));
1256 5 : } else if (nv[0] == "deprecated_since") {
1257 0 : cl.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
1258 5 : } else if (nv[0] == "const_cname") {
1259 1 : cl.set_attribute_string ("CCode", "const_cname", eval (nv[1]));
1260 4 : } else if (nv[0] == "free_function") {
1261 0 : free_function = eval (nv[1]);
1262 4 : } else if (nv[0] == "ref_function") {
1263 0 : ref_function = eval (nv[1]);
1264 4 : } else if (nv[0] == "unref_function") {
1265 0 : unref_function = eval (nv[1]);
1266 4 : } else if (nv[0] == "copy_function") {
1267 0 : copy_function = eval (nv[1]);
1268 4 : } else if (nv[0] == "ref_function_void") {
1269 0 : if (eval (nv[1]) == "1") {
1270 8 : ref_function_void = true;
1271 : }
1272 4 : } else if (nv[0] == "experimental") {
1273 0 : if (eval (nv[1]) == "1") {
1274 0 : cl.set_attribute_bool ("Version", "experimental", true);
1275 : }
1276 : }
1277 : }
1278 : }
1279 :
1280 25 : add_symbol_to_container (container, cl);
1281 25 : current_source_file.add_node (cl);
1282 :
1283 25 : if (base_class != null) {
1284 0 : var parent = parse_type_string (base_class);
1285 0 : cl.add_base_type (parent);
1286 : }
1287 : }
1288 :
1289 56 : current_data_type = cl;
1290 :
1291 447 : foreach (weak IdlNode member in boxed_node.members) {
1292 419 : if (member.type == IdlNodeTypeId.FUNCTION) {
1293 311 : if (member.name == "ref") {
1294 24 : ref_function = ((IdlNodeFunction) member).symbol;
1295 12 : ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
1296 299 : } else if (member.name == "unref") {
1297 24 : unref_function = ((IdlNodeFunction) member).symbol;
1298 553 : } else if (member.name == "free" || member.name == "destroy") {
1299 24 : free_function = ((IdlNodeFunction) member).symbol;
1300 : } else {
1301 275 : if (member.name == "copy") {
1302 30 : copy_function = ((IdlNodeFunction) member).symbol;
1303 : }
1304 275 : var m = parse_function ((IdlNodeFunction) member);
1305 275 : if (m != null) {
1306 266 : cl.add_method (m);
1307 : }
1308 : }
1309 212 : } else if (member.type == IdlNodeTypeId.FIELD) {
1310 108 : var f = parse_field ((IdlNodeField) member);
1311 108 : if (f != null) {
1312 104 : cl.add_field (f);
1313 : }
1314 : }
1315 : }
1316 :
1317 28 : if (ref_function != null) {
1318 12 : cl.set_attribute_string ("CCode", "ref_function", ref_function);
1319 12 : if (ref_function_void) {
1320 2 : cl.set_attribute_bool ("CCode", "ref_function_void", ref_function_void);
1321 : }
1322 16 : } else if (copy_function != null) {
1323 11 : cl.set_attribute_string ("CCode", "copy_function", copy_function);
1324 : }
1325 28 : if (unref_function != null) {
1326 12 : cl.set_attribute_string ("CCode", "unref_function", unref_function);
1327 16 : } else if (free_function != null && free_function != "%sfree".printf (get_lower_case_cprefix (cl))) {
1328 0 : cl.set_attribute_string ("CCode", "free_function", free_function);
1329 : }
1330 :
1331 28 : current_data_type = null;
1332 : }
1333 : }
1334 :
1335 1149 : private void parse_enum (IdlNodeEnum en_node, Symbol container, IdlModule module, bool is_flags) {
1336 383 : weak IdlNode node = (IdlNode) en_node;
1337 383 : string name = fix_type_name (node.name, container);
1338 383 : bool existing = true;
1339 :
1340 383 : var en = container.scope.lookup (name) as Enum;
1341 383 : if (en == null) {
1342 383 : en = new Enum (name, current_source_reference);
1343 383 : en.access = SymbolAccessibility.PUBLIC;
1344 383 : existing = false;
1345 : } else {
1346 : // ignore dummy enum values in -custom.vala files
1347 : // they exist for syntactical reasons
1348 0 : var dummy = (EnumValue) en.scope.lookup ("__DUMMY__");
1349 0 : if (dummy != null) {
1350 0 : en.get_values ().remove (dummy);
1351 0 : en.scope.remove ("__DUMMY__");
1352 : }
1353 : }
1354 :
1355 383 : if (en_node.gtype_name == null || en_node.gtype_name == "") {
1356 114 : en.set_attribute_bool ("CCode", "has_type_id", false);
1357 : }
1358 :
1359 383 : string common_prefix = null;
1360 :
1361 4945 : foreach (weak IdlNode value in en_node.values) {
1362 2281 : var val_attributes = get_attributes (value.name);
1363 2281 : bool is_hidden = false;
1364 2281 : if (val_attributes != null) {
1365 20 : foreach (string attr in val_attributes) {
1366 8 : var nv = attr.split ("=", 2);
1367 8 : if (nv[0] == "hidden" && eval(nv[1]) == "1") {
1368 8 : is_hidden = true;
1369 : }
1370 : }
1371 : }
1372 :
1373 4 : if (is_hidden) {
1374 0 : continue;
1375 : }
1376 :
1377 2281 : if (common_prefix == null) {
1378 766 : common_prefix = value.name;
1379 2459 : while (common_prefix.length > 0 && !common_prefix.has_suffix ("_")) {
1380 : // FIXME: could easily be made faster
1381 2076 : common_prefix = common_prefix.substring (0, common_prefix.length - 1);
1382 : }
1383 : } else {
1384 2372 : while (!value.name.has_prefix (common_prefix)) {
1385 474 : common_prefix = common_prefix.substring (0, common_prefix.length - 1);
1386 : }
1387 : }
1388 2297 : while (common_prefix.length > 0 && (!common_prefix.has_suffix ("_") ||
1389 2279 : (value.name.get_char (common_prefix.length).isdigit ()) && (value.name.length - common_prefix.length) <= 1)) {
1390 : // enum values may not consist solely of digits
1391 16 : common_prefix = common_prefix.substring (0, common_prefix.length - 1);
1392 : }
1393 : }
1394 :
1395 383 : bool is_errordomain = false;
1396 :
1397 383 : string cheader_filename = null;
1398 :
1399 383 : var en_attributes = get_attributes (node.name);
1400 383 : if (en_attributes != null) {
1401 49 : foreach (string attr in en_attributes) {
1402 17 : var nv = attr.split ("=", 2);
1403 17 : if (nv[0] == "common_prefix") {
1404 1 : common_prefix = eval (nv[1]);
1405 16 : } else if (nv[0] == "cheader_filename") {
1406 5 : cheader_filename = eval (nv[1]);
1407 5 : en.set_attribute_string ("CCode", "cheader_filename", cheader_filename);
1408 11 : } else if (nv[0] == "hidden") {
1409 0 : if (eval (nv[1]) == "1") {
1410 0 : return;
1411 : }
1412 11 : } else if (nv[0] == "deprecated") {
1413 0 : if (eval (nv[1]) == "1") {
1414 0 : en.set_attribute_bool ("Version", "deprecated", true);
1415 : }
1416 11 : } else if (nv[0] == "default_value") {
1417 0 : en.set_attribute_string ("CCode", "default_value", eval (nv[1]));
1418 11 : } else if (nv[0] == "replacement") {
1419 0 : en.set_attribute_string ("Version", "replacement", eval (nv[1]));
1420 11 : } else if (nv[0] == "deprecated_since") {
1421 0 : en.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
1422 11 : } else if (nv[0] == "rename_to") {
1423 0 : en.name = eval (nv[1]);
1424 11 : } else if (nv[0] == "errordomain") {
1425 7 : if (eval (nv[1]) == "1") {
1426 17 : is_errordomain = true;
1427 : }
1428 4 : } else if (nv[0] == "to_string") {
1429 0 : var return_type = new UnresolvedType ();
1430 0 : return_type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1431 0 : return_type.value_owned = false;
1432 0 : var m = new Method ("to_string", return_type, current_source_reference);
1433 0 : m.access = SymbolAccessibility.PUBLIC;
1434 0 : m.set_attribute_string ("CCode", "cname", eval(nv[1]));
1435 0 : en.add_method (m);
1436 4 : } else if (nv[0] == "experimental") {
1437 0 : if (eval (nv[1]) == "1") {
1438 0 : en.set_attribute_bool ("Version", "experimental", true);
1439 : }
1440 : }
1441 : }
1442 : }
1443 :
1444 383 : en.set_attribute_string ("CCode", "cprefix", common_prefix);
1445 :
1446 4945 : foreach (weak IdlNode value2 in en_node.values) {
1447 2281 : EnumValue ev = new EnumValue (value2.name.substring (common_prefix.length), null);
1448 :
1449 2281 : var val_attributes = get_attributes (value2.name);
1450 2281 : bool is_hidden = false;
1451 2281 : if (val_attributes != null) {
1452 28 : foreach (string attr in val_attributes) {
1453 8 : var nv = attr.split ("=", 2);
1454 8 : if (nv[0] == "hidden" && eval(nv[1]) == "1") {
1455 : is_hidden = true;
1456 8 : } else if (nv[0] == "deprecated") {
1457 0 : if (eval (nv[1]) == "1") {
1458 0 : ev.set_attribute_bool ("Version", "deprecated", true);
1459 : }
1460 8 : } else if (nv[0] == "replacement") {
1461 0 : ev.set_attribute_string ("Version", "replacement", eval (nv[1]));
1462 8 : } else if (nv[0] == "deprecated_since") {
1463 0 : ev.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
1464 : }
1465 : }
1466 : }
1467 :
1468 4 : if (!is_hidden) {
1469 2281 : en.add_value (ev);
1470 : }
1471 : }
1472 :
1473 390 : if (is_errordomain) {
1474 7 : var ed = new ErrorDomain (en.name, current_source_reference);
1475 7 : ed.access = SymbolAccessibility.PUBLIC;
1476 7 : ed.set_attribute_string ("CCode", "cprefix", common_prefix);
1477 :
1478 7 : if (cheader_filename != null) {
1479 0 : ed.set_attribute_string ("CCode", "cheader_filename", cheader_filename);
1480 : }
1481 :
1482 71 : foreach (EnumValue ev in en.get_values ()) {
1483 32 : ed.add_code (new ErrorCode (ev.name));
1484 : }
1485 :
1486 7 : current_source_file.add_node (ed);
1487 7 : if (!existing) {
1488 7 : add_symbol_to_container (container, ed);
1489 : }
1490 : } else {
1491 376 : en.set_attribute ("Flags", is_flags);
1492 376 : current_source_file.add_node (en);
1493 376 : if (!existing) {
1494 376 : add_symbol_to_container (container, en);
1495 : }
1496 : }
1497 : }
1498 :
1499 602 : private void parse_object (IdlNodeInterface node, Symbol container, IdlModule module) {
1500 301 : string name = fix_type_name (((IdlNode) node).name, container);
1501 :
1502 301 : string base_class = null;
1503 :
1504 301 : var cl = container.scope.lookup (name) as Class;
1505 532 : if (cl == null) {
1506 266 : cl = new Class (name, current_source_reference);
1507 266 : cl.access = SymbolAccessibility.PUBLIC;
1508 :
1509 266 : var attributes = get_attributes (node.gtype_name);
1510 266 : if (attributes != null) {
1511 118 : foreach (string attr in attributes) {
1512 30 : var nv = attr.split ("=", 2);
1513 30 : if (nv[0] == "cheader_filename") {
1514 20 : cl.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
1515 10 : } else if (nv[0] == "base_class") {
1516 1 : base_class = eval (nv[1]);
1517 9 : } else if (nv[0] == "hidden") {
1518 0 : if (eval (nv[1]) == "1") {
1519 0 : return;
1520 : }
1521 9 : } else if (nv[0] == "type_check_function") {
1522 3 : cl.set_attribute_string ("CCode", "type_check_function", eval (nv[1]));
1523 6 : } else if (nv[0] == "deprecated") {
1524 2 : if (eval (nv[1]) == "1") {
1525 2 : cl.set_attribute_bool ("Version", "deprecated", true);
1526 : }
1527 4 : } else if (nv[0] == "replacement") {
1528 0 : cl.set_attribute_string ("Version", "replacement", eval (nv[1]));
1529 4 : } else if (nv[0] == "deprecated_since") {
1530 2 : cl.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
1531 2 : } else if (nv[0] == "type_id") {
1532 0 : cl.set_attribute_string ("CCode", "type_id", eval (nv[1]));
1533 2 : } else if (nv[0] == "abstract") {
1534 2 : if (eval (nv[1]) == "1") {
1535 2 : cl.is_abstract = true;
1536 : }
1537 0 : } else if (nv[0] == "experimental") {
1538 0 : if (eval (nv[1]) == "1") {
1539 0 : cl.set_attribute_bool ("Version", "experimental", true);
1540 : }
1541 0 : } else if (nv[0] == "compact") {
1542 0 : if (eval (nv[1]) == "1") {
1543 0 : cl.set_attribute ("Compact", true);
1544 : }
1545 0 : } else if (nv[0] == "ref_function") {
1546 0 : cl.set_attribute_string ("CCode", "ref_function", eval (nv[1]));
1547 0 : } else if (nv[0] == "unref_function") {
1548 0 : cl.set_attribute_string ("CCode", "unref_function", eval (nv[1]));
1549 0 : } else if (nv[0] == "copy_function") {
1550 0 : cl.set_attribute_string ("CCode", "copy_function", eval (nv[1]));
1551 0 : } else if (nv[0] == "free_function") {
1552 0 : cl.set_attribute_string ("CCode", "free_function", eval (nv[1]));
1553 : }
1554 : }
1555 : }
1556 :
1557 266 : add_symbol_to_container (container, cl);
1558 266 : current_source_file.add_node (cl);
1559 : }
1560 :
1561 302 : if (base_class != null) {
1562 1 : var parent = parse_type_string (base_class);
1563 1 : cl.add_base_type (parent);
1564 300 : } else if (node.parent != null) {
1565 600 : if (!cl.is_compact) {
1566 300 : var parent = parse_type_string (node.parent);
1567 300 : cl.add_base_type (parent);
1568 : }
1569 : } else {
1570 0 : var gobject_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Object");
1571 0 : cl.add_base_type (new UnresolvedType.from_symbol (gobject_symbol));
1572 : }
1573 :
1574 1522 : foreach (string iface_name in node.interfaces) {
1575 407 : bool skip_iface = false;
1576 :
1577 407 : var attributes = get_attributes (iface_name);
1578 407 : if (attributes != null) {
1579 6 : foreach (string attr in attributes) {
1580 2 : var nv = attr.split ("=", 2);
1581 2 : if (nv[0] == "hidden") {
1582 0 : if (eval (nv[1]) == "1") {
1583 2 : skip_iface = true;
1584 : }
1585 : }
1586 : }
1587 : }
1588 :
1589 2 : if (skip_iface) {
1590 0 : continue;
1591 : }
1592 :
1593 407 : var iface = parse_type_string (iface_name);
1594 407 : cl.add_base_type (iface);
1595 : }
1596 :
1597 602 : current_data_type = cl;
1598 :
1599 301 : current_type_symbol_set = new HashSet<string> (str_hash, str_equal);
1600 301 : var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
1601 301 : var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
1602 :
1603 7270 : foreach (weak IdlNode member in node.members) {
1604 6969 : if (member.type == IdlNodeTypeId.FUNCTION) {
1605 3957 : current_type_func_map.set (member.name, (IdlNodeFunction) member);
1606 : }
1607 6969 : if (member.type == IdlNodeTypeId.VFUNC) {
1608 199 : current_type_vfunc_map.set (member.name, "1");
1609 : }
1610 : }
1611 :
1612 7270 : foreach (weak IdlNode member in node.members) {
1613 6969 : if (member.type == IdlNodeTypeId.FUNCTION) {
1614 : // Ignore if vfunc (handled below)
1615 7708 : if (!current_type_vfunc_map.contains (member.name)) {
1616 3890 : var m = parse_function ((IdlNodeFunction) member);
1617 3890 : if (m != null) {
1618 3751 : cl.add_method (m);
1619 : }
1620 : }
1621 3179 : } else if (member.type == IdlNodeTypeId.VFUNC) {
1622 199 : var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name));
1623 199 : if (m != null) {
1624 167 : cl.add_method (m);
1625 : }
1626 4181 : } else if (member.type == IdlNodeTypeId.PROPERTY) {
1627 1369 : var prop = parse_property ((IdlNodeProperty) member);
1628 1369 : if (prop != null) {
1629 1368 : cl.add_property (prop);
1630 : }
1631 1875 : } else if (member.type == IdlNodeTypeId.SIGNAL) {
1632 434 : var sig = parse_signal ((IdlNodeSignal) member);
1633 434 : if (sig != null) {
1634 431 : cl.add_signal (sig);
1635 : }
1636 : }
1637 : }
1638 :
1639 7270 : foreach (weak IdlNode member in node.members) {
1640 6969 : if (member.type == IdlNodeTypeId.FIELD) {
1641 1684 : if (!current_type_symbol_set.contains (member.name)) {
1642 731 : var f = parse_field ((IdlNodeField) member);
1643 731 : if (f != null) {
1644 674 : cl.add_field (f);
1645 : }
1646 : }
1647 : }
1648 : }
1649 :
1650 3037 : foreach (Property prop in cl.get_properties ()) {
1651 1368 : var getter = "get_%s".printf (prop.name);
1652 :
1653 1368 : if (prop.get_accessor != null && !current_type_symbol_set.contains (getter)) {
1654 744 : prop.set_attribute ("NoAccessorMethod", true);
1655 : }
1656 :
1657 1368 : var setter = "set_%s".printf (prop.name);
1658 :
1659 1368 : if (prop.set_accessor != null && prop.set_accessor.writable
1660 1188 : && !current_type_symbol_set.contains (setter)) {
1661 680 : prop.set_attribute ("NoAccessorMethod", true);
1662 : }
1663 :
1664 1368 : if (prop.has_attribute ("NoAccessorMethod") && prop.get_accessor != null) {
1665 768 : prop.get_accessor.value_type.value_owned = true;
1666 : }
1667 : }
1668 :
1669 301 : handle_async_methods (cl);
1670 :
1671 394 : if (cl.default_construction_method == null) {
1672 : // always provide constructor in generated bindings
1673 : // to indicate that implicit Object () chainup is allowed
1674 93 : var cm = new CreationMethod (null, null, cl.source_reference);
1675 93 : cm.has_construct_function = false;
1676 93 : cm.access = SymbolAccessibility.PROTECTED;
1677 93 : cl.add_method (cm);
1678 : }
1679 :
1680 301 : current_data_type = null;
1681 301 : current_type_symbol_set = null;
1682 : }
1683 :
1684 46 : private void parse_interface (IdlNodeInterface node, Symbol container, IdlModule module) {
1685 23 : string name = fix_type_name (node.gtype_name, container);
1686 :
1687 23 : var iface = container.scope.lookup (name) as Interface;
1688 34 : if (iface == null) {
1689 17 : iface = new Interface (name, current_source_reference);
1690 17 : iface.access = SymbolAccessibility.PUBLIC;
1691 :
1692 17 : var attributes = get_attributes (node.gtype_name);
1693 17 : if (attributes != null) {
1694 8 : foreach (string attr in attributes) {
1695 2 : var nv = attr.split ("=", 2);
1696 2 : if (nv[0] == "cheader_filename") {
1697 2 : iface.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
1698 0 : } else if (nv[0] == "hidden") {
1699 0 : if (eval (nv[1]) == "1") {
1700 0 : return;
1701 : }
1702 0 : } else if (nv[0] == "type_cname") {
1703 0 : iface.set_attribute_string ("CCode", "type_cname", eval (nv[1]));
1704 0 : } else if (nv[0] == "lower_case_csuffix") {
1705 0 : iface.set_attribute_string ("CCode", "lower_case_csuffix", eval (nv[1]));
1706 : }
1707 : }
1708 : }
1709 :
1710 49 : foreach (string prereq_name in node.prerequisites) {
1711 16 : var prereq = parse_type_string (prereq_name);
1712 16 : iface.add_prerequisite (prereq);
1713 : }
1714 :
1715 17 : add_symbol_to_container (container, iface);
1716 17 : current_source_file.add_node (iface);
1717 : }
1718 :
1719 23 : current_data_type = iface;
1720 :
1721 23 : current_type_symbol_set = new HashSet<string> (str_hash, str_equal);
1722 23 : var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
1723 23 : var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
1724 :
1725 561 : foreach (weak IdlNode member in node.members) {
1726 538 : if (member.type == IdlNodeTypeId.FUNCTION) {
1727 301 : current_type_func_map.set (member.name, (IdlNodeFunction) member);
1728 : }
1729 538 : if (member.type == IdlNodeTypeId.VFUNC) {
1730 150 : current_type_vfunc_map.set (member.name, "1");
1731 : }
1732 : }
1733 :
1734 561 : foreach (weak IdlNode member in node.members) {
1735 538 : if (member.type == IdlNodeTypeId.FUNCTION) {
1736 : // Ignore if vfunc (handled below)
1737 433 : if (!current_type_vfunc_map.contains (member.name)) {
1738 157 : var m = parse_function ((IdlNodeFunction) member, true);
1739 157 : if (m != null) {
1740 132 : iface.add_method (m);
1741 : }
1742 : }
1743 385 : } else if (member.type == IdlNodeTypeId.VFUNC) {
1744 150 : var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name), true);
1745 150 : if (m != null) {
1746 148 : iface.add_method (m);
1747 : }
1748 131 : } else if (member.type == IdlNodeTypeId.PROPERTY) {
1749 44 : var prop = parse_property ((IdlNodeProperty) member);
1750 44 : if (prop != null) {
1751 44 : iface.add_property (prop);
1752 : }
1753 86 : } else if (member.type == IdlNodeTypeId.SIGNAL) {
1754 43 : var sig = parse_signal ((IdlNodeSignal) member);
1755 43 : if (sig != null) {
1756 43 : iface.add_signal (sig);
1757 43 : sig.is_virtual = false;
1758 : }
1759 : }
1760 : }
1761 :
1762 111 : foreach (Property prop in iface.get_properties ()) {
1763 44 : var getter = "get_%s".printf (prop.name);
1764 :
1765 44 : if (prop.get_accessor != null && !current_type_symbol_set.contains (getter)) {
1766 15 : prop.set_attribute ("NoAccessorMethod", true);
1767 : }
1768 :
1769 44 : var setter = "set_%s".printf (prop.name);
1770 :
1771 44 : if (prop.set_accessor != null && prop.set_accessor.writable
1772 42 : && !current_type_symbol_set.contains (setter)) {
1773 15 : prop.set_attribute ("NoAccessorMethod", true);
1774 : }
1775 :
1776 44 : if (prop.has_attribute ("NoAccessorMethod") && prop.get_accessor != null) {
1777 15 : prop.get_accessor.value_type.value_owned = true;
1778 : }
1779 : }
1780 :
1781 23 : handle_async_methods (iface);
1782 :
1783 23 : current_data_type = null;
1784 : }
1785 :
1786 648 : void handle_async_methods (ObjectTypeSymbol type_symbol) {
1787 324 : Set<Method> finish_methods = new HashSet<Method> ();
1788 324 : var methods = type_symbol.get_methods ();
1789 :
1790 8902 : foreach (Method m in methods) {
1791 4291 : if (m.coroutine) {
1792 : string finish_method_base;
1793 2 : if (m.name.has_suffix ("_async")) {
1794 2 : finish_method_base = m.name.substring (0, m.name.length - "_async".length);
1795 : } else {
1796 0 : finish_method_base = m.name;
1797 : }
1798 2 : var finish_method = type_symbol.scope.lookup (finish_method_base + "_finish") as Method;
1799 :
1800 : // check if the method is using non-standard finish method name
1801 2 : if (finish_method == null) {
1802 0 : var method_cname = get_finish_cname (m);
1803 0 : foreach (Method method in type_symbol.get_methods ()) {
1804 0 : if (get_cname (method) == method_cname) {
1805 0 : finish_method = method;
1806 0 : break;
1807 : }
1808 : }
1809 : }
1810 :
1811 4 : if (finish_method != null) {
1812 2 : m.return_type = finish_method.return_type.copy ();
1813 2 : var a = finish_method.get_attribute ("CCode");
1814 0 : if (a != null && a.has_argument ("array_length")) {
1815 0 : m.set_attribute_bool ("CCode", "array_length", a.get_bool ("array_length"));
1816 : }
1817 2 : if (a != null && a.has_argument ("array_null_terminated")) {
1818 0 : m.set_attribute_bool ("CCode", "array_null_terminated", a.get_bool ("array_null_terminated"));
1819 : }
1820 6 : foreach (var param in finish_method.get_parameters ()) {
1821 2 : if (param.direction == ParameterDirection.OUT) {
1822 0 : var async_param = param.copy ();
1823 0 : if (m.scope.lookup (param.name) != null) {
1824 : // parameter name conflict
1825 0 : async_param.name += "_out";
1826 : }
1827 0 : m.add_parameter (async_param);
1828 : }
1829 : }
1830 2 : var error_types = new ArrayList<DataType> ();
1831 2 : finish_method.get_error_types (error_types, m.source_reference);
1832 6 : foreach (DataType error_type in error_types) {
1833 2 : m.add_error_type (error_type);
1834 : }
1835 2 : finish_methods.add (finish_method);
1836 : }
1837 : }
1838 : }
1839 :
1840 652 : foreach (Method m in finish_methods)
1841 : {
1842 2 : type_symbol.scope.remove (m.name);
1843 2 : methods.remove (m);
1844 : }
1845 : }
1846 :
1847 25673 : private DataType? parse_type (IdlNodeType type_node, out ParameterDirection direction = null) {
1848 25673 : direction = ParameterDirection.IN;
1849 :
1850 25673 : var type = new UnresolvedType ();
1851 25673 : if (type_node.tag == TypeTag.VOID) {
1852 4611 : if (type_node.is_pointer) {
1853 718 : return new PointerType (new VoidType ());
1854 : } else {
1855 3893 : return new VoidType ();
1856 : }
1857 : } else if (type_node.tag == TypeTag.BOOLEAN) {
1858 2300 : type.unresolved_symbol = new UnresolvedSymbol (null, "bool");
1859 : } else if (type_node.tag == TypeTag.INT8) {
1860 21 : type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1861 : } else if (type_node.tag == TypeTag.UINT8) {
1862 30 : type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1863 : } else if (type_node.tag == TypeTag.INT16) {
1864 4 : type.unresolved_symbol = new UnresolvedSymbol (null, "int16");
1865 : } else if (type_node.tag == TypeTag.UINT16) {
1866 53 : type.unresolved_symbol = new UnresolvedSymbol (null, "uint16");
1867 : } else if (type_node.tag == TypeTag.INT32) {
1868 0 : type.unresolved_symbol = new UnresolvedSymbol (null, "int32");
1869 : } else if (type_node.tag == TypeTag.UINT32) {
1870 90 : type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
1871 : } else if (type_node.tag == TypeTag.INT64) {
1872 5 : type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1873 : } else if (type_node.tag == TypeTag.UINT64) {
1874 4 : type.unresolved_symbol = new UnresolvedSymbol (null, "uint64");
1875 : } else if (type_node.tag == TypeTag.INT) {
1876 4356 : type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1877 : } else if (type_node.tag == TypeTag.UINT) {
1878 734 : type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1879 : } else if (type_node.tag == TypeTag.LONG) {
1880 7 : type.unresolved_symbol = new UnresolvedSymbol (null, "long");
1881 : } else if (type_node.tag == TypeTag.ULONG) {
1882 39 : type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1883 : } else if (type_node.tag == TypeTag.SSIZE) {
1884 19 : type.unresolved_symbol = new UnresolvedSymbol (null, "ssize_t");
1885 : } else if (type_node.tag == TypeTag.SIZE) {
1886 114 : type.unresolved_symbol = new UnresolvedSymbol (null, "size_t");
1887 : } else if (type_node.tag == TypeTag.FLOAT) {
1888 266 : type.unresolved_symbol = new UnresolvedSymbol (null, "float");
1889 : } else if (type_node.tag == TypeTag.DOUBLE) {
1890 514 : type.unresolved_symbol = new UnresolvedSymbol (null, "double");
1891 : } else if (type_node.tag == TypeTag.UTF8) {
1892 1737 : type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1893 : } else if (type_node.tag == TypeTag.FILENAME) {
1894 0 : type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1895 : } else if (type_node.tag == TypeTag.ARRAY) {
1896 72 : var element_type = parse_type (type_node.parameter_type1);
1897 144 : type = element_type as UnresolvedType;
1898 72 : if (type == null) {
1899 0 : return element_type;
1900 : }
1901 72 : element_type.value_owned = true;
1902 72 : return new ArrayType (element_type, 1, element_type.source_reference);
1903 : } else if (type_node.tag == TypeTag.LIST) {
1904 315 : type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "List");
1905 : } else if (type_node.tag == TypeTag.SLIST) {
1906 87 : type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "SList");
1907 : } else if (type_node.tag == TypeTag.HASH) {
1908 34 : type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "HashTable");
1909 : } else if (type_node.tag == TypeTag.ERROR) {
1910 182 : type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Error");
1911 10079 : } else if (type_node.unparsed.has_prefix ("cairo_device_t") || type_node.unparsed.has_prefix ("cairo_pattern_t") ||
1912 10078 : type_node.unparsed.has_prefix ("cairo_surface_t")) {
1913 6 : if (type_node.unparsed.has_prefix ("cairo_device_t")) {
1914 0 : type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "Cairo"), "Device");
1915 6 : } else if (type_node.unparsed.has_prefix ("cairo_pattern_t")) {
1916 1 : type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "Cairo"), "Pattern");
1917 5 : } else if (type_node.unparsed.has_prefix ("cairo_surface_t")) {
1918 5 : type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "Cairo"), "Surface");
1919 : }
1920 6 : if (type_node.unparsed.has_suffix ("**")) {
1921 20807 : direction = ParameterDirection.OUT;
1922 : }
1923 10073 : } else if (type_node.is_interface) {
1924 10073 : var n = type_node.@interface;
1925 :
1926 10073 : if (n == "") {
1927 0 : return null;
1928 : }
1929 :
1930 10073 : if (n.has_prefix ("const-")) {
1931 0 : n = n.substring ("const-".length);
1932 : }
1933 :
1934 10073 : if (type_node.is_pointer &&
1935 7212 : (n == "gchar" || n == "char")) {
1936 2182 : type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1937 2182 : if (type_node.unparsed.has_suffix ("**")) {
1938 9890 : direction = ParameterDirection.OUT;
1939 : }
1940 7891 : } else if (n == "gunichar") {
1941 5 : type.unresolved_symbol = new UnresolvedSymbol (null, "unichar");
1942 7886 : } else if (n == "gchar") {
1943 3 : type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1944 7883 : } else if (n == "guchar" || n == "guint8") {
1945 56 : type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1946 56 : if (type_node.is_pointer) {
1947 50 : type.value_owned = true;
1948 50 : return new ArrayType (type, 1, type.source_reference);
1949 : }
1950 7827 : } else if (n == "gushort") {
1951 1 : type.unresolved_symbol = new UnresolvedSymbol (null, "ushort");
1952 7826 : } else if (n == "gshort") {
1953 3 : type.unresolved_symbol = new UnresolvedSymbol (null, "short");
1954 7823 : } else if (n == "gconstpointer" || n == "void") {
1955 42 : return new PointerType (new VoidType ());
1956 7781 : } else if (n == "goffset" || n == "off_t") {
1957 0 : type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1958 7781 : } else if (n == "value_array") {
1959 0 : type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "ValueArray");
1960 7781 : } else if (n == "time_t") {
1961 53 : type.unresolved_symbol = new UnresolvedSymbol (null, "time_t");
1962 7728 : } else if (n == "socklen_t") {
1963 0 : type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
1964 7728 : } else if (n == "mode_t") {
1965 0 : type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1966 7728 : } else if (n == "gint" || n == "pid_t") {
1967 2 : type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1968 7726 : } else if (n == "unsigned" || n == "unsigned-int") {
1969 92 : type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1970 7634 : } else if (n == "FILE") {
1971 4 : type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "FileStream");
1972 7630 : } else if (n == "struct") {
1973 19 : return new PointerType (new VoidType ());
1974 7611 : } else if (n == "iconv_t") {
1975 0 : return new PointerType (new VoidType ());
1976 7611 : } else if (n == "GType") {
1977 71 : type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Type");
1978 71 : if (type_node.is_pointer) {
1979 8 : type.value_owned = true;
1980 8 : return new ArrayType (type, 1, type.source_reference);
1981 : }
1982 15016 : } else if (n == "GStrv") {
1983 9 : type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1984 9 : type.value_owned = true;
1985 9 : return new ArrayType (type, 1, type.source_reference);
1986 : } else {
1987 7531 : var named_type = parse_type_string (n);
1988 15007 : type = named_type as UnresolvedType;
1989 7531 : if (type == null) {
1990 55 : return named_type;
1991 : }
1992 7476 : if (is_simple_type (n)) {
1993 129 : if (type_node.is_pointer) {
1994 117 : direction = ParameterDirection.OUT;
1995 : }
1996 7347 : } else if (type_node.unparsed.has_suffix ("**")) {
1997 117 : direction = ParameterDirection.OUT;
1998 : }
1999 : }
2000 : } else {
2001 0 : print ("%d\n", type_node.tag);
2002 : }
2003 20807 : return type;
2004 : }
2005 :
2006 7476 : private bool is_simple_type (string type_name) {
2007 7476 : var st = cname_type_map[type_name] as Struct;
2008 462 : if (st != null && st.is_simple_type ()) {
2009 129 : return true;
2010 : }
2011 :
2012 7347 : return false;
2013 : }
2014 :
2015 8260 : private DataType parse_type_string (string n) {
2016 8260 : if (n == "va_list") {
2017 : // unsupported
2018 54 : return new PointerType (new VoidType ());
2019 : }
2020 :
2021 8206 : var type = new UnresolvedType ();
2022 :
2023 8206 : var dt = cname_type_map[n];
2024 8206 : if (dt != null) {
2025 3496 : UnresolvedSymbol parent_symbol = null;
2026 3496 : if (dt.parent_symbol.name != null) {
2027 3477 : parent_symbol = new UnresolvedSymbol (null, dt.parent_symbol.name);
2028 : }
2029 3496 : type.unresolved_symbol = new UnresolvedSymbol (parent_symbol, dt.name);
2030 3496 : return type;
2031 : }
2032 :
2033 4710 : var type_attributes = get_attributes (n);
2034 :
2035 4710 : string ns_name = null;
2036 :
2037 4710 : if (null != type_attributes) {
2038 4099 : foreach (string attr in type_attributes) {
2039 1105 : var nv = attr.split ("=", 2);
2040 :
2041 1105 : if (nv[0] == "cprefix") {
2042 0 : type.unresolved_symbol = new UnresolvedSymbol (null, n.substring (eval (nv[1]).length));
2043 1105 : } else if (nv[0] == "name") {
2044 1 : type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
2045 1104 : } else if (nv[0] == "namespace") {
2046 0 : ns_name = eval (nv[1]);
2047 1104 : } else if (nv[0] == "rename_to") {
2048 0 : type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
2049 : }
2050 : }
2051 : }
2052 :
2053 4710 : if (type.unresolved_symbol != null) {
2054 1 : if (type.unresolved_symbol.name == "pointer") {
2055 2 : return new PointerType (new VoidType ());
2056 : }
2057 0 : if (ns_name != null) {
2058 0 : type.unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
2059 : }
2060 0 : return type;
2061 : }
2062 :
2063 4709 : if (n.has_prefix (current_namespace.name)) {
2064 4636 : type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, current_namespace.name), n.substring (current_namespace.name.length));
2065 73 : } else if (current_namespace.parent_symbol != null && current_namespace.parent_symbol.name != null && n.has_prefix (current_namespace.parent_symbol.name)) {
2066 9 : type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, current_namespace.parent_symbol.name), n.substring (current_namespace.parent_symbol.name.length));
2067 114 : } else if (n.has_prefix ("G")) {
2068 14 : type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), n.substring (1));
2069 : } else {
2070 50 : var name_parts = n.split (".", 2);
2071 50 : if (name_parts[1] == null) {
2072 50 : type.unresolved_symbol = new UnresolvedSymbol (null, name_parts[0]);
2073 : } else {
2074 0 : type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, name_parts[0]), name_parts[1]);
2075 : }
2076 : }
2077 :
2078 4709 : return type;
2079 : }
2080 :
2081 18964 : private DataType? parse_param (IdlNodeParam param, out ParameterDirection direction = null) {
2082 18964 : var type = parse_type (param.type, out direction);
2083 :
2084 : // disable for now as null_ok not yet correctly set
2085 : // type.non_null = !param.null_ok;
2086 :
2087 18964 : return type;
2088 : }
2089 :
2090 189 : private UnresolvedSymbol? parse_symbol_from_string (string symbol_string, SourceReference? source_reference = null) {
2091 189 : UnresolvedSymbol? sym = null;
2092 593 : foreach (unowned string s in symbol_string.split (".")) {
2093 215 : sym = new UnresolvedSymbol (sym, s, source_reference);
2094 : }
2095 189 : if (sym == null) {
2096 0 : Report.error (source_reference, "a symbol must be specified");
2097 : }
2098 : return sym;
2099 : }
2100 :
2101 96 : private bool parse_type_arguments_from_string (DataType parent_type, string type_arguments, SourceReference? source_reference = null) {
2102 96 : int type_arguments_length = (int) type_arguments.length;
2103 96 : GLib.StringBuilder current = new GLib.StringBuilder.sized (type_arguments_length);
2104 :
2105 96 : int depth = 0;
2106 1137 : for (var c = 0 ; c < type_arguments_length ; c++) {
2107 1041 : if (type_arguments[c] == '<' || type_arguments[c] == '[') {
2108 0 : depth++;
2109 0 : current.append_unichar (type_arguments[c]);
2110 1041 : } else if (type_arguments[c] == '>' || type_arguments[c] == ']') {
2111 0 : depth--;
2112 0 : current.append_unichar (type_arguments[c]);
2113 1041 : } else if (type_arguments[c] == ',') {
2114 2 : if (depth == 0) {
2115 1 : var dt = parse_type_from_string (current.str, true, source_reference);
2116 1 : if (dt == null) {
2117 0 : return false;
2118 : }
2119 1 : parent_type.add_type_argument (dt);
2120 1 : current.truncate ();
2121 : } else {
2122 0 : current.append_unichar (type_arguments[c]);
2123 : }
2124 : } else {
2125 1040 : current.append_unichar (type_arguments[c]);
2126 : }
2127 : }
2128 :
2129 96 : var dt = parse_type_from_string (current.str, true, source_reference);
2130 96 : if (dt == null) {
2131 0 : return false;
2132 : }
2133 96 : parent_type.add_type_argument (dt);
2134 :
2135 96 : return true;
2136 : }
2137 :
2138 189 : private DataType? parse_type_from_string (string type_string, bool owned_by_default, SourceReference? source_reference = null) {
2139 189 : if (type_from_string_regex == null) {
2140 0 : try {
2141 13 : type_from_string_regex = new GLib.Regex ("^(?:(owned|unowned|weak) +)?([0-9a-zA-Z_\\.]+)(?:<(.+)>)?(\\*+)?(\\[(,*)?\\])?(\\?)?$", GLib.RegexCompileFlags.ANCHORED | GLib.RegexCompileFlags.DOLLAR_ENDONLY | GLib.RegexCompileFlags.OPTIMIZE);
2142 : } catch (GLib.RegexError e) {
2143 0 : GLib.error ("Unable to compile regex: %s", e.message);
2144 : }
2145 : }
2146 :
2147 : GLib.MatchInfo match;
2148 189 : if (!type_from_string_regex.match (type_string, 0, out match)) {
2149 0 : Report.error (source_reference, "unable to parse type");
2150 0 : return null;
2151 : }
2152 :
2153 189 : DataType? type = null;
2154 :
2155 189 : var ownership_data = match.fetch (1);
2156 189 : var type_name = match.fetch (2);
2157 189 : var type_arguments_data = match.fetch (3);
2158 189 : var pointers_data = match.fetch (4);
2159 189 : var array_data = match.fetch (5);
2160 189 : var array_dimension_data = match.fetch (6);
2161 189 : var nullable_data = match.fetch (7);
2162 :
2163 189 : var nullable = nullable_data != null && nullable_data.length > 0;
2164 :
2165 189 : if (ownership_data == null && type_name == "void") {
2166 0 : if (array_data == null && !nullable) {
2167 0 : type = new VoidType (source_reference);
2168 0 : if (pointers_data != null) {
2169 0 : for (int i=0; i < pointers_data.length; i++) {
2170 0 : type = new PointerType (type);
2171 : }
2172 : }
2173 0 : return type;
2174 : } else {
2175 0 : Report.error (source_reference, "invalid void type");
2176 0 : return null;
2177 : }
2178 : }
2179 :
2180 189 : bool value_owned = owned_by_default;
2181 :
2182 189 : if (ownership_data == "owned") {
2183 : value_owned = true;
2184 189 : } else if (ownership_data == "unowned") {
2185 25 : value_owned = false;
2186 : }
2187 :
2188 189 : var sym = parse_symbol_from_string (type_name, source_reference);
2189 189 : if (sym == null) {
2190 0 : return null;
2191 : }
2192 189 : type = new UnresolvedType.from_symbol (sym, source_reference);
2193 :
2194 189 : if (type_arguments_data != null && type_arguments_data.length > 0) {
2195 5 : if (!parse_type_arguments_from_string (type, type_arguments_data, source_reference)) {
2196 0 : return null;
2197 : }
2198 : }
2199 :
2200 189 : if (pointers_data != null) {
2201 191 : for (int i=0; i < pointers_data.length; i++) {
2202 2 : type = new PointerType (type);
2203 : }
2204 : }
2205 :
2206 189 : if (array_data != null && array_data.length > 0) {
2207 6 : type.value_owned = true;
2208 6 : type = new ArrayType (type, array_dimension_data.length + 1, source_reference);
2209 : }
2210 :
2211 189 : type.nullable = nullable;
2212 189 : type.value_owned = value_owned;
2213 189 : return type;
2214 : }
2215 :
2216 7911 : private Method? create_method (string name, string symbol, IdlNodeParam? res, GLib.List<IdlNodeParam>? parameters, bool is_constructor, bool is_interface) {
2217 7911 : DataType return_type = null;
2218 7911 : if (res != null) {
2219 7911 : return_type = parse_param (res);
2220 : }
2221 :
2222 : Method m;
2223 7911 : if (!is_interface && (is_constructor || name.has_prefix ("new"))) {
2224 469 : m = new CreationMethod (null, name, current_source_reference);
2225 469 : m.has_construct_function = false;
2226 469 : if (m.name == "new") {
2227 313 : m.name = null;
2228 156 : } else if (m.name.has_prefix ("new_")) {
2229 153 : m.name = m.name.substring ("new_".length);
2230 : }
2231 : // For classes, check whether a creation method return type equals to the
2232 : // type of the class created. If the types do not match (e.g. in most
2233 : // gtk widgets) add an attribute to the creation method indicating the used
2234 : // return type.
2235 469 : if (current_data_type is Class && res != null) {
2236 464 : if ("%s*".printf (get_cname (current_data_type)) != res.type.unparsed) {
2237 249 : m.set_attribute_string ("CCode", "type", res.type.unparsed);
2238 : }
2239 : }
2240 : } else {
2241 7442 : m = new Method (name, return_type, current_source_reference);
2242 : }
2243 7911 : m.access = SymbolAccessibility.PUBLIC;
2244 :
2245 7911 : if (current_type_symbol_set != null) {
2246 4411 : current_type_symbol_set.add (name);
2247 : }
2248 :
2249 20509 : if (current_data_type != null) {
2250 6379 : var sig_attributes = get_attributes ("%s::%s".printf (get_cname (current_data_type), name));
2251 6379 : if (sig_attributes != null) {
2252 186 : foreach (string attr in sig_attributes) {
2253 87 : var nv = attr.split ("=", 2);
2254 87 : if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
2255 240 : return null;
2256 : }
2257 : }
2258 : }
2259 : }
2260 :
2261 7831 : bool add_ellipsis = false;
2262 7831 : bool suppress_throws = false;
2263 7831 : string? error_types = null;
2264 7831 : Symbol? container = null;
2265 :
2266 7831 : var attributes = get_attributes (symbol);
2267 7831 : if (attributes != null) {
2268 2283 : foreach (string attr in attributes) {
2269 943 : var nv = attr.split ("=", 2);
2270 943 : if (nv[0] == "name") {
2271 15 : m.name = eval (nv[1]);
2272 928 : } else if (nv[0] == "hidden") {
2273 349 : if (eval (nv[1]) == "1") {
2274 1047 : return null;
2275 : }
2276 579 : } else if (nv[0] == "ellipsis") {
2277 22 : if (eval (nv[1]) == "1") {
2278 594 : add_ellipsis = true;
2279 : }
2280 557 : } else if (nv[0] == "printf_format") {
2281 4 : if (eval (nv[1]) == "1") {
2282 4 : m.set_attribute ("PrintfFormat", true);
2283 : }
2284 553 : } else if (nv[0] == "transfer_ownership") {
2285 213 : if (eval (nv[1]) == "1") {
2286 211 : return_type.value_owned = true;
2287 : }
2288 340 : } else if (nv[0] == "transfer_container") {
2289 1 : if (eval (nv[1]) == "1") {
2290 1 : return_type.value_owned = true;
2291 1 : if (return_type is ArrayType) {
2292 1 : ((ArrayType) return_type).element_type.value_owned = false;
2293 : }
2294 : }
2295 339 : } else if (nv[0] == "destroys_instance") {
2296 0 : if (eval (nv[1]) == "1") {
2297 0 : m.set_attribute ("DestroysInstance", true, m.source_reference);
2298 : }
2299 339 : } else if (nv[0] == "returns_floating_reference") {
2300 0 : if (eval (nv[1]) == "1") {
2301 0 : m.set_attribute_bool ("CCode", "returns_floating_reference", true);
2302 0 : m.return_type.value_owned = true;
2303 : }
2304 339 : } else if (nv[0] == "nullable") {
2305 52 : if (eval (nv[1]) == "1" && !(return_type is VoidType)) {
2306 52 : return_type.nullable = true;
2307 : }
2308 287 : } else if (nv[0] == "sentinel") {
2309 9 : m.set_attribute_string ("CCode", "sentinel", eval (nv[1]));
2310 278 : } else if (nv[0] == "is_array") {
2311 29 : if (eval (nv[1]) == "1") {
2312 29 : return_type.value_owned = true;
2313 29 : return_type = new ArrayType (return_type, 1, return_type.source_reference);
2314 29 : m.return_type = return_type;
2315 : }
2316 249 : } else if (nv[0] == "is_pointer") {
2317 0 : if (eval (nv[1]) == "1") {
2318 0 : return_type = new PointerType (return_type, return_type.source_reference);
2319 0 : m.return_type = return_type;
2320 : }
2321 249 : } else if (nv[0] == "throws") {
2322 0 : if (eval (nv[1]) == "0") {
2323 594 : suppress_throws = true;
2324 : }
2325 249 : } else if (nv[0] == "error_types") {
2326 0 : error_types = eval (nv[1]);
2327 249 : } else if (nv[0] == "no_array_length") {
2328 13 : if (eval (nv[1]) == "1") {
2329 13 : m.set_attribute_bool ("CCode", "array_length", false);
2330 : }
2331 236 : } else if (nv[0] == "array_null_terminated") {
2332 16 : if (eval (nv[1]) == "1") {
2333 16 : m.set_attribute_bool ("CCode", "array_length", false);
2334 16 : m.set_attribute_bool ("CCode", "array_null_terminated", true);;
2335 : }
2336 220 : } else if (nv[0] == "array_length_type") {
2337 7 : m.set_attribute_string ("CCode", "array_length_type", eval (nv[1]));
2338 213 : } else if (nv[0] == "type_name") {
2339 17 : m.return_type = return_type = parse_type_from_string (eval (nv[1]), return_type.value_owned);
2340 196 : } else if (nv[0] == "ctype") {
2341 1 : m.set_attribute_string ("CCode", "type", eval (nv[1]));
2342 195 : } else if (nv[0] == "type_arguments") {
2343 58 : parse_type_arguments_from_string (return_type, eval (nv[1]));
2344 137 : } else if (nv[0] == "deprecated") {
2345 42 : if (eval (nv[1]) == "1") {
2346 42 : m.set_attribute_bool ("Version", "deprecated", true);
2347 : }
2348 95 : } else if (nv[0] == "replacement") {
2349 1 : m.set_attribute_string ("Version", "replacement", eval (nv[1]));
2350 94 : } else if (nv[0] == "deprecated_since") {
2351 44 : m.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
2352 50 : } else if (nv[0] == "cheader_filename") {
2353 4 : m.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
2354 46 : } else if (nv[0] == "abstract") {
2355 2 : if (eval (nv[1]) == "1") {
2356 2 : m.is_abstract = true;
2357 : }
2358 44 : } else if (nv[0] == "virtual") {
2359 21 : if (eval (nv[1]) == "1") {
2360 18 : m.is_virtual = true;
2361 : }
2362 23 : } else if (nv[0] == "vfunc_name") {
2363 1 : m.set_attribute_string ("CCode", "vfunc_name", eval (nv[1]));
2364 22 : } else if (nv[0] == "finish_vfunc_name") {
2365 0 : m.set_attribute_string ("CCode", "finish_vfunc_name", eval (nv[1]));
2366 22 : } else if (nv[0] == "finish_name") {
2367 0 : m.set_attribute_string ("CCode", "finish_name", eval (nv[1]));
2368 22 : } else if (nv[0] == "async") {
2369 0 : if (eval (nv[1]) == "1") {
2370 : // force async function, even if it doesn't end in _async
2371 0 : m.coroutine = true;
2372 : }
2373 37 : } else if (nv[0] == "parent") {
2374 15 : container = get_container_from_name (eval (nv[1]));
2375 15 : var prefix = get_lower_case_cprefix (container);
2376 15 : if (symbol.has_prefix (prefix)) {
2377 15 : m.name = symbol.substring (prefix.length);
2378 : }
2379 7 : } else if (nv[0] == "experimental") {
2380 0 : if (eval (nv[1]) == "1") {
2381 0 : m.set_attribute_bool ("Version", "experimental", true);
2382 : }
2383 7 : } else if (nv[0] == "simple_generics") {
2384 0 : if (eval (nv[1]) == "1") {
2385 0 : m.set_attribute_bool ("CCode", "simple_generics", true);
2386 : }
2387 : }
2388 : }
2389 : }
2390 :
2391 7482 : bool first = true;
2392 7482 : Parameter last_param = null;
2393 7482 : DataType last_param_type = null;
2394 22341 : foreach (weak IdlNodeParam param in parameters) {
2395 14859 : weak IdlNode param_node = (IdlNode) param;
2396 :
2397 14859 : if (first) {
2398 6910 : first = false;
2399 6910 : if (!(m is CreationMethod) &&
2400 6608 : current_data_type != null &&
2401 5493 : param.type.is_interface &&
2402 5398 : (param_node.name == "self" ||
2403 5354 : param.type.@interface.has_suffix (get_cname (current_data_type)))) {
2404 : // instance method
2405 5346 : continue;
2406 1752 : } else if (!(m is CreationMethod) &&
2407 1450 : current_data_type != null &&
2408 335 : param.type.is_interface &&
2409 240 : (param_node.name == "klass" ||
2410 236 : param.type.@interface.has_suffix ("%sClass".printf(get_cname (current_data_type))))) {
2411 : // class method
2412 6 : m.binding = MemberBinding.CLASS;
2413 6 : if (m.name.has_prefix ("class_")) {
2414 5 : m.name = m.name.substring ("class_".length, m.name.length - "class_".length);
2415 : }
2416 6 : continue;
2417 1746 : } else if (!(m is CreationMethod)) {
2418 : // static method
2419 1444 : m.binding = MemberBinding.STATIC;
2420 : }
2421 : }
2422 :
2423 9695 : if (param.type.@interface == "GAsyncReadyCallback" && (symbol.has_suffix ("_async") || m.coroutine)) {
2424 : // async method
2425 2 : m.coroutine = true;
2426 2 : continue;
2427 : }
2428 :
2429 : // check for GError parameter
2430 9693 : if (suppress_throws == false && param_is_exception (param)) {
2431 180 : if (error_types == null)
2432 180 : m.add_error_type (parse_type (param.type));
2433 180 : continue;
2434 : }
2435 :
2436 9513 : string param_name = param_node.name;
2437 9513 : if (param_name == "result") {
2438 : // avoid conflict with generated result variable
2439 7 : param_name = "_result";
2440 9506 : } else if (param_name == "string") {
2441 : // avoid conflict with string type
2442 17 : param_name = "str";
2443 : }
2444 : ParameterDirection direction;
2445 9513 : var param_type = parse_param (param, out direction);
2446 9513 : var p = new Parameter (param_name, param_type, current_source_reference);
2447 9513 : p.direction = direction;
2448 :
2449 9513 : bool hide_param = false;
2450 9513 : bool show_param = false;
2451 9513 : bool set_array_length_pos = false;
2452 9513 : double array_length_pos = 0;
2453 9513 : bool set_delegate_target_pos = false;
2454 9513 : double delegate_target_pos = 0;
2455 9513 : bool array_requested = false;
2456 9513 : bool out_requested = false;
2457 19026 : attributes = get_attributes ("%s.%s".printf (symbol, param_node.name));
2458 9513 : if (attributes != null) {
2459 3456 : foreach (string attr in attributes) {
2460 1212 : var nv = attr.split ("=", 2);
2461 1212 : if (nv[0] == "is_array") {
2462 68 : if (eval (nv[1]) == "1") {
2463 68 : param_type.value_owned = true;
2464 68 : param_type = new ArrayType (param_type, 1, param_type.source_reference);
2465 68 : p.variable_type = param_type;
2466 68 : if (!out_requested) {
2467 65 : p.direction = ParameterDirection.IN;
2468 : }
2469 : array_requested = true;
2470 : }
2471 1144 : } else if (nv[0] == "is_pointer") {
2472 0 : if (eval (nv[1]) == "1") {
2473 0 : param_type = new PointerType (param_type, return_type.source_reference);
2474 0 : p.variable_type = param_type;
2475 0 : if (!out_requested) {
2476 0 : p.direction = ParameterDirection.IN;
2477 : }
2478 : }
2479 1144 : } else if (nv[0] == "is_out") {
2480 350 : if (eval (nv[1]) == "1") {
2481 350 : p.direction = ParameterDirection.OUT;
2482 350 : out_requested = true;
2483 351 : if (!array_requested && param_type is ArrayType) {
2484 1 : var array_type = (ArrayType) param_type;
2485 2 : param_type = array_type.element_type;
2486 1 : p.variable_type = param_type;
2487 : }
2488 : }
2489 794 : } else if (nv[0] == "is_ref") {
2490 62 : if (eval (nv[1]) == "1") {
2491 62 : p.direction = ParameterDirection.REF;
2492 62 : if (!array_requested && param_type is ArrayType) {
2493 0 : var array_type = (ArrayType) param_type;
2494 0 : param_type = array_type.element_type;
2495 0 : p.variable_type = param_type;
2496 : }
2497 : }
2498 732 : } else if (nv[0] == "nullable") {
2499 309 : if (eval (nv[1]) == "1" && !(param_type is VoidType)) {
2500 309 : param_type.nullable = true;
2501 : }
2502 423 : } else if (nv[0] == "transfer_ownership") {
2503 69 : if (eval (nv[1]) == "1") {
2504 68 : param_type.value_owned = true;
2505 : }
2506 354 : } else if (nv[0] == "takes_ownership") {
2507 2 : if (eval (nv[1]) == "1") {
2508 2 : param_type.value_owned = true;
2509 : }
2510 352 : } else if (nv[0] == "value_owned") {
2511 5 : if (eval (nv[1]) == "0") {
2512 0 : param_type.value_owned = false;
2513 5 : } else if (eval (nv[1]) == "1") {
2514 5 : param_type.value_owned = true;
2515 : }
2516 347 : } else if (nv[0] == "hidden") {
2517 151 : if (eval (nv[1]) == "1") {
2518 : hide_param = true;
2519 5 : } else if (eval (nv[1]) == "0") {
2520 1212 : show_param = true;
2521 : }
2522 196 : } else if (nv[0] == "no_array_length") {
2523 37 : if (eval (nv[1]) == "1") {
2524 37 : p.set_attribute_bool ("CCode", "array_length", false);
2525 : }
2526 159 : } else if (nv[0] == "array_length_type") {
2527 3 : p.set_attribute_string ("CCode", "array_length_type", eval (nv[1]));
2528 156 : } else if (nv[0] == "array_null_terminated") {
2529 13 : if (eval (nv[1]) == "1") {
2530 13 : p.set_attribute_bool ("CCode", "array_length", false);
2531 13 : p.set_attribute_bool ("CCode", "array_null_terminated", true);
2532 : }
2533 143 : } else if (nv[0] == "array_length_pos") {
2534 33 : set_array_length_pos = true;
2535 33 : array_length_pos = double.parse (eval (nv[1]));
2536 110 : } else if (nv[0] == "delegate_target_pos") {
2537 0 : set_delegate_target_pos = true;
2538 0 : delegate_target_pos = double.parse (eval (nv[1]));
2539 110 : } else if (nv[0] == "type_name") {
2540 26 : p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
2541 84 : } else if (nv[0] == "ctype") {
2542 7 : p.set_attribute_string ("CCode", "type", eval (nv[1]));
2543 77 : } else if (nv[0] == "scope") {
2544 10 : p.set_attribute_string ("CCode", "scope", eval (nv[1]));
2545 67 : } else if (nv[0] == "type_arguments") {
2546 25 : parse_type_arguments_from_string (param_type, eval (nv[1]));
2547 74 : } else if (nv[0] == "default_value") {
2548 32 : var val = eval (nv[1]);
2549 32 : if (val == "null") {
2550 17 : p.initializer = new NullLiteral (param_type.source_reference);
2551 15 : } else if (val == "true") {
2552 4 : p.initializer = new BooleanLiteral (true, param_type.source_reference);
2553 11 : } else if (val == "false") {
2554 1 : p.initializer = new BooleanLiteral (false, param_type.source_reference);
2555 10 : } else if (val == "") {
2556 0 : p.initializer = new StringLiteral ("\"\"", param_type.source_reference);
2557 : } else {
2558 10 : if (int64.try_parse (val)) {
2559 6 : p.initializer = new IntegerLiteral (val, param_type.source_reference);
2560 : } else {
2561 4 : if (double.try_parse (val)) {
2562 3 : p.initializer = new RealLiteral (val, param_type.source_reference);
2563 : } else {
2564 1 : if (val.has_prefix ("\"") && val.has_suffix ("\"")) {
2565 0 : p.initializer = new StringLiteral (val, param_type.source_reference);
2566 : } else {
2567 5 : foreach (unowned string member in val.split (".")) {
2568 3 : p.initializer = new MemberAccess (p.initializer, member, param_type.source_reference);
2569 : }
2570 : }
2571 : }
2572 : }
2573 : }
2574 : }
2575 : }
2576 : }
2577 :
2578 9513 : if (last_param != null && p.name == "n_" + last_param.name) {
2579 53 : if (!(last_param_type is ArrayType)) {
2580 : // last_param is array, p is array length
2581 41 : last_param_type.value_owned = true;
2582 41 : last_param_type = new ArrayType (last_param_type, 1, last_param_type.source_reference);
2583 41 : last_param.variable_type = last_param_type;
2584 41 : last_param.direction = ParameterDirection.IN;
2585 : }
2586 :
2587 : // hide array length param
2588 : hide_param = true;
2589 9460 : } else if (last_param != null && p.name == "user_data") {
2590 : // last_param is delegate
2591 :
2592 : // hide deleate target param
2593 91 : hide_param = true;
2594 : }
2595 :
2596 9513 : if (show_param || !hide_param) {
2597 9229 : m.add_parameter (p);
2598 9229 : if (set_array_length_pos) {
2599 33 : p.set_attribute_double ("CCode", "array_length_pos", array_length_pos);
2600 : }
2601 9229 : if (set_delegate_target_pos) {
2602 0 : p.set_attribute_double ("CCode", "delegate_target_pos", delegate_target_pos);
2603 : }
2604 : }
2605 :
2606 19026 : last_param = p;
2607 19026 : last_param_type = param_type;
2608 : }
2609 :
2610 7482 : if (suppress_throws == false && error_types != null) {
2611 0 : var type_args = eval (error_types).split (",");
2612 0 : foreach (unowned string type_arg in type_args) {
2613 0 : m.add_error_type (parse_type_from_string (type_arg, true));
2614 : }
2615 : }
2616 :
2617 7482 : if (first && !(m is CreationMethod)) {
2618 : // no parameters => static method
2619 439 : m.binding = MemberBinding.STATIC;
2620 : }
2621 :
2622 7482 : if (last_param != null && last_param.name.has_prefix ("first_")) {
2623 24 : last_param.ellipsis = true;
2624 7458 : } else if (add_ellipsis) {
2625 21 : m.add_parameter (new Parameter.with_ellipsis (current_source_reference));
2626 : }
2627 :
2628 7482 : if (container == null) {
2629 7467 : container = current_data_type;
2630 7467 : if (container == null) {
2631 1366 : container = current_namespace;
2632 : }
2633 : }
2634 7482 : if (symbol != get_cname (m, container)) {
2635 131 : m.set_attribute_string ("CCode", "cname", symbol);
2636 : }
2637 :
2638 14964 : return m;
2639 : }
2640 :
2641 10134 : private bool param_is_exception (IdlNodeParam param) {
2642 10134 : if (!param.type.is_error) {
2643 9953 : return false;
2644 : }
2645 182 : var s = param.type.unparsed.chomp ();
2646 182 : if (s.has_suffix ("**")) {
2647 181 : return true;
2648 : }
2649 1 : return false;
2650 : }
2651 :
2652 7562 : private Method? parse_function (IdlNodeFunction f, bool is_interface = false) {
2653 7562 : weak IdlNode node = (IdlNode) f;
2654 :
2655 7562 : if (f.deprecated) {
2656 0 : return null;
2657 : }
2658 :
2659 7562 : return create_method (node.name, f.symbol, f.result, f.parameters, f.is_constructor, is_interface);
2660 : }
2661 :
2662 349 : private Method parse_virtual (IdlNodeVFunc v, IdlNodeFunction? func, bool is_interface = false) {
2663 349 : weak IdlNode node = (IdlNode) v;
2664 349 : string symbol = "%s%s".printf (get_lower_case_cprefix (current_data_type), node.name);
2665 :
2666 349 : if (func != null) {
2667 422 : symbol = func.symbol;
2668 : }
2669 :
2670 349 : Method m = create_method (node.name, symbol, v.result, func != null ? func.parameters : v.parameters, false, is_interface);
2671 979 : if (m != null) {
2672 315 : m.binding = MemberBinding.INSTANCE;
2673 315 : m.is_virtual = !(m.is_abstract || is_interface);
2674 315 : m.is_abstract = m.is_abstract || is_interface;
2675 :
2676 315 : var attributes = get_attributes (symbol);
2677 315 : if (attributes != null) {
2678 195 : foreach (string attr in attributes) {
2679 51 : var nv = attr.split ("=", 2);
2680 51 : if (nv[0] == "virtual") {
2681 20 : if (eval (nv[1]) == "0") {
2682 3 : m.is_virtual = false;
2683 3 : m.is_abstract = false;
2684 : } else {
2685 17 : m.is_virtual = true;
2686 17 : m.is_abstract = false;
2687 : }
2688 : }
2689 : }
2690 : }
2691 :
2692 315 : if (func == null) {
2693 105 : m.set_attribute ("NoWrapper", true);
2694 : }
2695 : }
2696 :
2697 349 : return m;
2698 : }
2699 :
2700 1890 : private string fix_prop_name (string name) {
2701 1890 : var str = new StringBuilder ();
2702 :
2703 1890 : string i = name;
2704 :
2705 23515 : while (i.length > 0) {
2706 21625 : unichar c = i.get_char ();
2707 21625 : if (c == '-') {
2708 1714 : str.append_c ('_');
2709 : } else {
2710 19911 : str.append_unichar (c);
2711 : }
2712 :
2713 43250 : i = i.next_char ();
2714 : }
2715 :
2716 3780 : return str.str;
2717 : }
2718 :
2719 1413 : private Property? parse_property (IdlNodeProperty prop_node) {
2720 1413 : weak IdlNode node = (IdlNode) prop_node;
2721 :
2722 1413 : if (prop_node.deprecated) {
2723 1 : return null;
2724 : }
2725 :
2726 1413 : if (!prop_node.readable && !prop_node.writable) {
2727 : // buggy GIDL definition
2728 0 : prop_node.readable = true;
2729 0 : prop_node.writable = true;
2730 : }
2731 :
2732 1413 : var prop = new Property (fix_prop_name (node.name), parse_type (prop_node.type), null, null, current_source_reference);
2733 1413 : prop.access = SymbolAccessibility.PUBLIC;
2734 1413 : prop.interface_only = true;
2735 :
2736 1413 : if (prop_node.type.is_interface && prop_node.type.interface == "GStrv") {
2737 9 : prop.set_attribute_bool ("CCode", "array_length", false);
2738 9 : prop.set_attribute_bool ("CCode", "array_null_terminated", true);
2739 : }
2740 :
2741 1413 : if (prop_node.readable) {
2742 1358 : prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, null);
2743 : }
2744 1413 : if (prop_node.writable) {
2745 1330 : if (prop_node.construct_only) {
2746 100 : prop.set_accessor = new PropertyAccessor (false, false, true, prop.property_type.copy (), null, null);
2747 : } else {
2748 1230 : prop.set_accessor = new PropertyAccessor (false, true, prop_node.@construct, prop.property_type.copy (), null, null);
2749 : }
2750 : }
2751 :
2752 : // there is no information about the internal ownership so assume `owned` as default
2753 1413 : prop.property_type.value_owned = true;
2754 :
2755 1413 : var attributes = get_attributes ("%s:%s".printf (get_cname (current_data_type), node.name));
2756 1413 : if (attributes != null) {
2757 62 : foreach (string attr in attributes) {
2758 16 : var nv = attr.split ("=", 2);
2759 16 : if (nv[0] == "hidden") {
2760 1 : if (eval (nv[1]) == "1") {
2761 3 : return null;
2762 : }
2763 15 : } else if (nv[0] == "type_arguments") {
2764 1 : parse_type_arguments_from_string (prop.property_type, eval (nv[1]));
2765 14 : } else if (nv[0] == "deprecated") {
2766 0 : if (eval (nv[1]) == "1") {
2767 0 : prop.set_attribute_bool ("Version", "deprecated", true);
2768 : }
2769 14 : } else if (nv[0] == "replacement") {
2770 0 : prop.set_attribute_string ("Version", "replacement", eval (nv[1]));
2771 14 : } else if (nv[0] == "deprecated_since") {
2772 0 : prop.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
2773 14 : } else if (nv[0] == "accessor_method") {
2774 8 : if (eval (nv[1]) == "0") {
2775 8 : prop.set_attribute ("NoAccessorMethod", true);
2776 : }
2777 6 : } else if (nv[0] == "owned_get") {
2778 6 : if (eval (nv[1]) == "1") {
2779 6 : prop.get_accessor.value_type.value_owned = true;
2780 : }
2781 0 : } else if (nv[0] == "type_name") {
2782 0 : prop.property_type = parse_type_from_string (eval (nv[1]), false);
2783 0 : } else if (nv[0] == "experimental") {
2784 0 : if (eval (nv[1]) == "1") {
2785 0 : prop.set_attribute_bool ("Version", "experimental", true);
2786 : }
2787 0 : } else if (nv[0] == "nullable") {
2788 0 : if (eval (nv[1]) == "1" && !(prop.property_type is VoidType)) {
2789 0 : prop.property_type.nullable = true;
2790 : }
2791 0 : } else if (nv[0] == "abstract") {
2792 0 : if (eval (nv[1]) == "1") {
2793 0 : prop.is_abstract = true;
2794 : }
2795 : }
2796 : }
2797 : }
2798 :
2799 1412 : if (current_type_symbol_set != null) {
2800 1412 : current_type_symbol_set.add (prop.name);
2801 : }
2802 :
2803 1412 : return prop;
2804 : }
2805 :
2806 2631 : private Constant? parse_constant (IdlNodeConstant const_node) {
2807 2631 : weak IdlNode node = (IdlNode) const_node;
2808 :
2809 2631 : var type = parse_type (const_node.type);
2810 2631 : if (type == null) {
2811 3 : return null;
2812 : }
2813 :
2814 2631 : var c = new Constant (node.name, type, null, current_source_reference);
2815 2631 : c.external = true;
2816 :
2817 2631 : string[] attributes = get_attributes (node.name);
2818 2631 : if (attributes != null) {
2819 15655 : foreach (string attr in attributes) {
2820 4459 : var nv = attr.split ("=", 2);
2821 4459 : if (nv[0] == "cheader_filename") {
2822 2176 : c.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
2823 2283 : } else if (nv[0] == "deprecated") {
2824 0 : if (eval (nv[1]) == "1") {
2825 0 : c.set_attribute_bool ("Version", "deprecated", true);
2826 : }
2827 2283 : } else if (nv[0] == "replacement") {
2828 0 : c.set_attribute_string ("Version", "replacement", eval (nv[1]));
2829 2283 : } else if (nv[0] == "deprecated_since") {
2830 0 : c.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
2831 2283 : } else if (nv[0] == "hidden") {
2832 3 : if (eval (nv[1]) == "1") {
2833 9 : return null;
2834 : }
2835 2280 : } else if (nv[0] == "experimental") {
2836 0 : if (eval (nv[1]) == "1") {
2837 0 : c.set_attribute_bool ("Version", "experimental", true);
2838 : }
2839 : }
2840 : }
2841 : }
2842 :
2843 2628 : c.access = SymbolAccessibility.PUBLIC;
2844 :
2845 5256 : return c;
2846 : }
2847 :
2848 2381 : private Field? parse_field (IdlNodeField field_node) {
2849 2381 : weak IdlNode node = (IdlNode) field_node;
2850 2381 : bool unhidden = false;
2851 :
2852 2381 : var type = parse_type (field_node.type);
2853 2381 : if (type == null) {
2854 210 : return null;
2855 : }
2856 :
2857 2381 : string cheader_filename = null;
2858 2381 : string ctype = null;
2859 2381 : string array_length_cname = null;
2860 2381 : string array_length_type = null;
2861 2381 : bool array_null_terminated = false;
2862 2381 : bool deprecated = false;
2863 2381 : string deprecated_since = null;
2864 2381 : string replacement = null;
2865 2381 : bool experimental = false;
2866 2381 : bool no_delegate_target = false;
2867 :
2868 2381 : var attributes = get_attributes ("%s.%s".printf (get_cname (current_data_type), node.name));
2869 2381 : if (attributes != null) {
2870 388 : foreach (string attr in attributes) {
2871 167 : var nv = attr.split ("=", 2);
2872 167 : if (nv[0] == "hidden") {
2873 100 : if (eval (nv[1]) == "1") {
2874 300 : return null;
2875 : } else {
2876 : unhidden = true;
2877 : }
2878 67 : } else if (nv[0] == "is_array") {
2879 7 : if (eval (nv[1]) == "1") {
2880 7 : type.value_owned = true;
2881 7 : type = new ArrayType (type, 1, type.source_reference);
2882 : }
2883 60 : } else if (nv[0] == "weak") {
2884 31 : if (eval (nv[1]) == "0") {
2885 31 : type.value_owned = true;
2886 : }
2887 29 : } else if (nv[0] == "value_owned") {
2888 2 : if (eval (nv[1]) == "0") {
2889 2 : type.value_owned = false;
2890 0 : } else if (eval (nv[1]) == "1") {
2891 0 : type.value_owned = true;
2892 : }
2893 27 : } else if (nv[0] == "type_name") {
2894 11 : type = parse_type_from_string (eval (nv[1]), true);
2895 16 : } else if (nv[0] == "type_arguments") {
2896 7 : parse_type_arguments_from_string (type, eval (nv[1]));
2897 9 : } else if (nv[0] == "deprecated") {
2898 0 : if (eval (nv[1]) == "1") {
2899 67 : deprecated = true;
2900 : }
2901 9 : } else if (nv[0] == "replacement") {
2902 0 : replacement = eval (nv[1]);
2903 9 : } else if (nv[0] == "deprecated_since") {
2904 0 : deprecated_since = eval (nv[1]);
2905 9 : } else if (nv[0] == "cheader_filename") {
2906 0 : cheader_filename = eval (nv[1]);
2907 9 : } else if (nv[0] == "ctype") {
2908 2 : ctype = eval (nv[1]);
2909 7 : } else if (nv[0] == "array_null_terminated") {
2910 3 : if (eval (nv[1]) == "1") {
2911 67 : array_null_terminated = true;
2912 : }
2913 4 : } else if (nv[0] == "array_length_cname") {
2914 0 : array_length_cname = eval (nv[1]);
2915 4 : } else if (nv[0] == "array_length_type") {
2916 0 : array_length_type = eval (nv[1]);
2917 4 : } else if (nv[0] == "no_delegate_target") {
2918 2 : if (eval (nv[1]) == "1") {
2919 67 : no_delegate_target = true;
2920 : }
2921 2 : } else if (nv[0] == "experimental") {
2922 0 : if (eval (nv[1]) == "1") {
2923 67 : experimental = true;
2924 : }
2925 : }
2926 : }
2927 : }
2928 :
2929 2281 : if (node.name.has_prefix("_") && !unhidden) {
2930 220 : return null;
2931 : }
2932 :
2933 2171 : if (current_type_symbol_set != null) {
2934 674 : current_type_symbol_set.add (node.name);
2935 : }
2936 :
2937 2171 : string field_name = node.name;
2938 2171 : if (field_name == "string") {
2939 : // avoid conflict with string type
2940 1 : field_name = "str";
2941 : }
2942 :
2943 2171 : var field = new Field (field_name, type, null, current_source_reference);
2944 2171 : field.access = SymbolAccessibility.PUBLIC;
2945 :
2946 2171 : if (field_name != node.name) {
2947 1 : field.set_attribute_string ("CCode", "cname", node.name);
2948 : }
2949 :
2950 2171 : if (deprecated) {
2951 0 : field.set_attribute_bool ("Version", "deprecated", true);
2952 :
2953 0 : if (deprecated_since != null) {
2954 0 : field.set_attribute_string ("Version", "deprecated_since", deprecated_since);
2955 : }
2956 :
2957 0 : if (replacement != null) {
2958 0 : field.set_attribute_string ("Version", "replacement", replacement);
2959 : }
2960 : }
2961 :
2962 2171 : if (experimental) {
2963 0 : field.set_attribute_bool ("Version", "experimental", true);
2964 : }
2965 :
2966 2171 : if (ctype != null) {
2967 2 : field.set_attribute_string ("CCode", "type", ctype);
2968 : }
2969 :
2970 2171 : if (cheader_filename != null) {
2971 0 : field.set_attribute_string ("CCode", "cheader_filename", cheader_filename);
2972 : }
2973 :
2974 2171 : if (array_null_terminated) {
2975 3 : field.set_attribute_bool ("CCode", "array_null_terminated", true);
2976 : }
2977 :
2978 2171 : if (array_length_cname != null || array_length_type != null) {
2979 0 : if (array_length_cname != null) {
2980 0 : field.set_attribute_string ("CCode", "array_length_cname", array_length_cname);
2981 : }
2982 0 : if (array_length_type != null) {
2983 0 : field.set_attribute_string ("CCode", "array_length_type", array_length_type);
2984 : }
2985 2171 : } else if (field.variable_type is ArrayType) {
2986 55 : field.set_attribute_bool ("CCode", "array_length", false);
2987 : }
2988 :
2989 2171 : if (no_delegate_target) {
2990 2 : field.set_attribute_bool ("CCode", "delegate_target", false);
2991 : }
2992 :
2993 4342 : return field;
2994 : }
2995 :
2996 59625 : private string[]? get_attributes (string codenode) {
2997 59625 : var attributes = codenode_attributes_map.get (codenode);
2998 :
2999 101039 : if (attributes == null) {
3000 48852 : var dot_required = (-1 != codenode.index_of_char ('.'));
3001 48852 : var colon_required = (-1 != codenode.index_of_char (':'));
3002 :
3003 48852 : var pattern_specs = codenode_attributes_patterns.get_keys ();
3004 562104 : foreach (PatternSpec* pattern in pattern_specs) {
3005 315679 : var pspec = codenode_attributes_patterns[pattern];
3006 :
3007 315679 : if ((dot_required && -1 == pspec.index_of_char ('.')) ||
3008 274418 : (colon_required && -1 == pspec.index_of_char (':'))) {
3009 103230 : continue;
3010 : }
3011 :
3012 212449 : if (pattern->match_string (codenode)) {
3013 7438 : return get_attributes (pspec);
3014 : }
3015 : }
3016 : }
3017 :
3018 41414 : if (attributes == null) {
3019 41414 : return null;
3020 : }
3021 :
3022 10773 : GLib.SList<string> attr_list = new GLib.SList<string> ();
3023 10773 : var attr = new GLib.StringBuilder.sized (attributes.length);
3024 10773 : var attributes_len = attributes.length;
3025 10773 : unowned string remaining = attributes;
3026 10773 : bool quoted = false, escaped = false;
3027 413032 : for (int b = 0 ; b < attributes_len ; b++) {
3028 402259 : unichar c = remaining.get_char ();
3029 :
3030 402259 : if (escaped) {
3031 0 : escaped = false;
3032 0 : attr.append_unichar (c);
3033 : } else {
3034 402259 : if (c == '"') {
3035 36622 : attr.append_unichar (c);
3036 36622 : quoted = !quoted;
3037 365637 : } else if (c == '\\') {
3038 : escaped = true;
3039 365637 : } else if (!quoted && (c == ' ')) {
3040 15080 : attr_list.prepend (attr.str);
3041 7540 : attr.truncate (0);
3042 : } else {
3043 358097 : attr.append_unichar (c);
3044 : }
3045 : }
3046 :
3047 402259 : remaining = (string) ((char*) remaining + remaining.index_of_nth_char (1));
3048 : }
3049 :
3050 10773 : if (attr.len > 0) {
3051 21544 : attr_list.prepend (attr.str);
3052 : }
3053 :
3054 10773 : var attrs = new string[attr_list.length ()];
3055 10773 : unowned GLib.SList<string>? attr_i = attr_list;
3056 29085 : for (int a = 0 ; a < attrs.length ; a++, attr_i = attr_i.next) {
3057 36624 : attrs[(attrs.length - 1) - a] = attr_i.data;
3058 : }
3059 :
3060 29085 : return attrs;
3061 : }
3062 :
3063 7372 : private string eval (string s) {
3064 7372 : return ((s.length >= 2) && s.has_prefix ("\"") && s.has_suffix ("\"")) ? s.substring (1, s.length - 2) : s;
3065 : }
3066 :
3067 477 : private Signal? parse_signal (IdlNodeSignal sig_node) {
3068 477 : weak IdlNode node = (IdlNode) sig_node;
3069 :
3070 477 : if (sig_node.deprecated || sig_node.result == null) {
3071 3 : return null;
3072 : }
3073 :
3074 477 : var sig = new Signal (fix_prop_name (node.name), parse_param (sig_node.result), current_source_reference);
3075 477 : sig.access = SymbolAccessibility.PUBLIC;
3076 :
3077 477 : var attributes = get_attributes ("%s::%s".printf (get_cname (current_data_type), sig.name));
3078 562 : if (attributes != null) {
3079 : string ns_name = null;
3080 352 : foreach (string attr in attributes) {
3081 90 : var nv = attr.split ("=", 2);
3082 90 : if (nv[0] == "name") {
3083 4 : sig.set_attribute_string ("CCode", "cname", sig.name.replace ("_", "-"));
3084 4 : sig.name = eval (nv[1]);
3085 86 : } else if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
3086 80 : sig.set_attribute ("HasEmitter", true);
3087 6 : } else if (nv[0] == "hidden") {
3088 3 : if (eval (nv[1]) == "1") {
3089 9 : return null;
3090 : }
3091 3 : } else if (nv[0] == "deprecated") {
3092 0 : if (eval (nv[1]) == "1") {
3093 0 : sig.set_attribute_bool ("Version", "deprecated", true);
3094 : }
3095 3 : } else if (nv[0] == "replacement") {
3096 0 : sig.set_attribute_string ("Version", "replacement", eval (nv[1]));
3097 3 : } else if (nv[0] == "deprecated_since") {
3098 0 : sig.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
3099 3 : } else if (nv[0] == "transfer_ownership") {
3100 1 : if (eval (nv[1]) == "1") {
3101 1 : sig.return_type.value_owned = true;
3102 : }
3103 2 : } else if (nv[0] == "namespace_name") {
3104 0 : ns_name = eval (nv[1]);
3105 2 : } else if (nv[0] == "type_name") {
3106 0 : sig.return_type = parse_type_from_string (eval (nv[1]), false);
3107 2 : } else if (nv[0] == "type_arguments") {
3108 0 : parse_type_arguments_from_string (sig.return_type, eval (nv[1]));
3109 2 : } else if (nv[0] == "experimental") {
3110 2 : if (eval (nv[1]) == "1") {
3111 2 : sig.set_attribute_bool ("Version", "experimental", true);
3112 : }
3113 : }
3114 : }
3115 85 : if (ns_name != null) {
3116 0 : ((UnresolvedType) sig.return_type).unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
3117 : }
3118 : }
3119 :
3120 474 : sig.is_virtual = true;
3121 :
3122 474 : bool first = true;
3123 :
3124 1854 : foreach (weak IdlNodeParam param in sig_node.parameters) {
3125 927 : if (first) {
3126 : // ignore implicit first signal parameter (sender)
3127 474 : first = false;
3128 474 : continue;
3129 : }
3130 :
3131 453 : weak IdlNode param_node = (IdlNode) param;
3132 :
3133 : ParameterDirection direction;
3134 453 : var param_type = parse_param (param, out direction);
3135 453 : var p = new Parameter (param_node.name, param_type, current_source_reference);
3136 453 : p.direction = direction;
3137 :
3138 453 : bool hide_param = false;
3139 453 : bool show_param = false;
3140 906 : attributes = get_attributes ("%s::%s.%s".printf (get_cname (current_data_type), sig.name, param_node.name));
3141 499 : if (attributes != null) {
3142 : string ns_name = null;
3143 208 : foreach (string attr in attributes) {
3144 81 : var nv = attr.split ("=", 2);
3145 81 : if (nv[0] == "hidden") {
3146 0 : if (eval (nv[1]) == "1") {
3147 : hide_param = true;
3148 0 : } else if (eval (nv[1]) == "0") {
3149 81 : show_param = true;
3150 : }
3151 81 : } else if (nv[0] == "is_array") {
3152 0 : if (eval (nv[1]) == "1") {
3153 0 : param_type.value_owned = true;
3154 0 : param_type = new ArrayType (param_type, 1, param_type.source_reference);
3155 0 : p.variable_type = param_type;
3156 0 : p.direction = ParameterDirection.IN;
3157 : }
3158 81 : } else if (nv[0] == "no_array_length") {
3159 0 : if (eval (nv[1]) == "1") {
3160 0 : p.set_attribute_bool ("CCode", "array_length", false);
3161 : }
3162 81 : } else if (nv[0] == "array_length_type") {
3163 0 : p.set_attribute_string ("CCode", "array_length_type", nv[1]);
3164 81 : } else if (nv[0] == "array_null_terminated") {
3165 0 : if (eval (nv[1]) == "1") {
3166 0 : p.set_attribute_bool ("CCode", "array_length", false);
3167 0 : p.set_attribute_bool ("CCode", "array_null_terminated", true);
3168 : }
3169 81 : } else if (nv[0] == "is_out") {
3170 2 : if (eval (nv[1]) == "1") {
3171 2 : p.direction = ParameterDirection.OUT;
3172 : }
3173 79 : } else if (nv[0] == "is_ref") {
3174 2 : if (eval (nv[1]) == "1") {
3175 2 : p.direction = ParameterDirection.REF;
3176 : }
3177 77 : } else if (nv[0] == "nullable") {
3178 8 : if (eval (nv[1]) == "1" && !(param_type is VoidType)) {
3179 8 : param_type.nullable = true;
3180 : }
3181 69 : } else if (nv[0] == "transfer_ownership") {
3182 0 : if (eval (nv[1]) == "1") {
3183 0 : param_type.value_owned = true;
3184 : }
3185 69 : } else if (nv[0] == "type_name") {
3186 36 : p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
3187 33 : } else if (nv[0] == "type_arguments") {
3188 0 : parse_type_arguments_from_string (p.variable_type, eval (nv[1]));
3189 33 : } else if (nv[0] == "namespace_name") {
3190 33 : ns_name = eval (nv[1]);
3191 : }
3192 : }
3193 46 : if (ns_name != null) {
3194 33 : ((UnresolvedType) param_type).unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
3195 : }
3196 : }
3197 :
3198 453 : if (show_param || !hide_param) {
3199 453 : sig.add_parameter (p);
3200 : }
3201 : }
3202 :
3203 474 : return sig;
3204 : }
3205 : }
3206 :
3207 : // vim:sw=8 noet
|