Fix error messages for unsupported signal parameters
[vala-lang.git] / vapigen / valagidlparser.vala
blob193824436f49282ad79842e86761b6f0d932ff68
1 /* valagidlparser.vala
3 * Copyright (C) 2006-2009 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
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.
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.
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
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using GLib;
27 /**
28 * Code visitor parsing all GIDL files.
30 public class Vala.GIdlParser : CodeVisitor {
31 private CodeContext context;
33 private SourceFile current_source_file;
35 private SourceReference current_source_reference;
37 private Namespace current_namespace;
38 private TypeSymbol current_data_type;
39 private Map<string,string> codenode_attributes_map;
40 private Map<PatternSpec*,string> codenode_attributes_patterns;
41 private Set<string> current_type_symbol_set;
43 private Map<string,TypeSymbol> cname_type_map;
45 /**
46 * Parse all source files in the specified code context and build a
47 * code tree.
49 * @param context a code context
51 public void parse (CodeContext context) {
52 cname_type_map = new HashMap<string,TypeSymbol> (str_hash, str_equal);
54 this.context = context;
55 context.accept (this);
57 cname_type_map = null;
60 public override void visit_namespace (Namespace ns) {
61 ns.accept_children (this);
64 public override void visit_class (Class cl) {
65 visit_type (cl);
68 public override void visit_struct (Struct st) {
69 visit_type (st);
72 public override void visit_interface (Interface iface) {
73 visit_type (iface);
76 public override void visit_enum (Enum en) {
77 visit_type (en);
80 public override void visit_error_domain (ErrorDomain ed) {
81 visit_type (ed);
84 public override void visit_delegate (Delegate d) {
85 visit_type (d);
88 private void visit_type (TypeSymbol t) {
89 if (!cname_type_map.contains (t.get_cname ())) {
90 cname_type_map[t.get_cname ()] = t;
94 public override void visit_source_file (SourceFile source_file) {
95 if (source_file.filename.has_suffix (".gi")) {
96 parse_file (source_file);
100 private void parse_file (SourceFile source_file) {
101 string metadata_filename = "%s.metadata".printf (source_file.filename.ndup (source_file.filename.size () - ".gi".size ()));
103 current_source_file = source_file;
105 codenode_attributes_map = new HashMap<string,string> (str_hash, str_equal);
106 codenode_attributes_patterns = new HashMap<PatternSpec*,string> (direct_hash, (EqualFunc) PatternSpec.equal);
108 if (FileUtils.test (metadata_filename, FileTest.EXISTS)) {
109 try {
110 string metadata;
111 FileUtils.get_contents (metadata_filename, out metadata, null);
113 foreach (string line in metadata.split ("\n")) {
114 if (line.has_prefix ("#")) {
115 // ignore comment lines
116 continue;
119 var tokens = line.split (" ", 2);
121 if (null == tokens[0]) {
122 continue;
125 if (null != tokens[0].chr (-1, '*')) {
126 PatternSpec* pattern = new PatternSpec (tokens[0]);
127 codenode_attributes_patterns[pattern] = tokens[0];
130 codenode_attributes_map[tokens[0]] = tokens[1];
132 } catch (FileError e) {
133 Report.error (null, "Unable to read metadata file: %s".printf (e.message));
137 try {
138 var modules = Idl.parse_file (source_file.filename);
140 current_source_reference = new SourceReference (source_file);
142 foreach (weak IdlModule module in modules) {
143 var ns = parse_module (module);
144 if (ns != null) {
145 context.root.add_namespace (ns);
148 } catch (MarkupError e) {
149 stdout.printf ("error parsing GIDL file: %s\n", e.message);
153 private string fix_type_name (string type_name, Namespace ns) {
154 var attributes = get_attributes (type_name);
155 if (attributes != null) {
156 foreach (string attr in attributes) {
157 var nv = attr.split ("=", 2);
158 if (nv[0] == "name") {
159 return eval (nv[1]);
164 if (type_name.has_prefix (ns.name)) {
165 return type_name.offset (ns.name.len ());
166 } else if (ns.name == "GLib" && type_name.has_prefix ("G")) {
167 return type_name.offset (1);
168 } else {
169 string best_match = null;
170 foreach (string cprefix in ns.get_cprefixes ()) {
171 if (type_name.has_prefix (cprefix)) {
172 if (best_match == null || cprefix.len () > best_match.len ())
173 best_match = cprefix;
177 if (best_match != null) {
178 return type_name.offset (best_match.len ());;
182 return type_name;
185 private string fix_const_name (string const_name, Namespace ns) {
186 if (const_name.has_prefix (ns.name.up () + "_")) {
187 return const_name.offset (ns.name.len () + 1);
188 } else if (ns.name == "GLib" && const_name.has_prefix ("G_")) {
189 return const_name.offset (2);
191 return const_name;
194 private Namespace? parse_module (IdlModule module) {
195 Symbol sym = context.root.scope.lookup (module.name);
196 Namespace ns;
197 if (sym is Namespace) {
198 ns = (Namespace) sym;
199 if (ns.external_package) {
200 ns.attributes = null;
201 ns.source_reference = current_source_reference;
203 } else {
204 ns = new Namespace (module.name, current_source_reference);
207 current_namespace = ns;
209 var attributes = get_attributes (ns.name);
210 if (attributes != null) {
211 foreach (string attr in attributes) {
212 var nv = attr.split ("=", 2);
213 if (nv[0] == "cheader_filename") {
214 ns.set_cheader_filename (eval (nv[1]));
215 } else if (nv[0] == "cprefix") {
216 var cprefixes = eval (nv[1]).split (",");
217 foreach(string name in cprefixes) {
218 ns.add_cprefix (name);
220 } else if (nv[0] == "lower_case_cprefix") {
221 ns.set_lower_case_cprefix (eval (nv[1]));
226 foreach (weak IdlNode node in module.entries) {
227 if (node.type == IdlNodeTypeId.CALLBACK) {
228 var cb = parse_delegate ((IdlNodeFunction) node);
229 if (cb == null) {
230 continue;
232 cb.name = fix_type_name (cb.name, ns);
233 ns.add_delegate (cb);
234 current_source_file.add_node (cb);
235 } else if (node.type == IdlNodeTypeId.STRUCT) {
236 parse_struct ((IdlNodeStruct) node, ns, module);
237 } else if (node.type == IdlNodeTypeId.UNION) {
238 parse_union ((IdlNodeUnion) node, ns, module);
239 } else if (node.type == IdlNodeTypeId.BOXED) {
240 parse_boxed ((IdlNodeBoxed) node, ns, module);
241 } else if (node.type == IdlNodeTypeId.ENUM) {
242 var en = parse_enum ((IdlNodeEnum) node);
243 if (en == null) {
244 continue;
246 en.name = fix_type_name (en.name, ns);
247 if (en is ErrorDomain) {
248 ns.add_error_domain (en as ErrorDomain);
249 } else {
250 ns.add_enum (en as Enum);
252 current_source_file.add_node (en);
253 } else if (node.type == IdlNodeTypeId.FLAGS) {
254 var en = parse_enum ((IdlNodeEnum) node) as Enum;
255 if (en == null) {
256 continue;
258 en.name = fix_type_name (en.name, ns);
259 en.is_flags = true;
260 ns.add_enum (en);
261 current_source_file.add_node (en);
262 } else if (node.type == IdlNodeTypeId.OBJECT) {
263 parse_object ((IdlNodeInterface) node, ns, module);
264 } else if (node.type == IdlNodeTypeId.INTERFACE) {
265 parse_interface ((IdlNodeInterface) node, ns, module);
266 } else if (node.type == IdlNodeTypeId.CONSTANT) {
267 var c = parse_constant ((IdlNodeConstant) node);
268 if (c != null) {
269 c.name = fix_const_name (c.name, ns);
270 ns.add_constant (c);
271 current_source_file.add_node (c);
273 } else if (node.type == IdlNodeTypeId.FUNCTION) {
274 var m = parse_function ((IdlNodeFunction) node);
275 if (m != null) {
276 m.binding = MemberBinding.STATIC;
277 ns.add_method (m);
278 current_source_file.add_node (m);
283 current_namespace = null;
285 if (sym is Namespace) {
286 return null;
288 return ns;
291 private Delegate? parse_delegate (IdlNodeFunction f_node) {
292 weak IdlNode node = (IdlNode) f_node;
294 var return_type = parse_param (f_node.result);
296 var cb = new Delegate (node.name, return_type, current_source_reference);
297 cb.access = SymbolAccessibility.PUBLIC;
299 bool check_has_target = true;
301 var attributes = get_attributes (node.name);
302 if (attributes != null) {
303 foreach (string attr in attributes) {
304 var nv = attr.split ("=", 2);
305 if (nv[0] == "hidden") {
306 if (eval (nv[1]) == "1") {
307 return null;
309 } else if (nv[0] == "cheader_filename") {
310 cb.add_cheader_filename (eval (nv[1]));
311 } else if (nv[0] == "has_target") {
312 if (eval (nv[1]) == "0") {
313 check_has_target = false;
314 } else if (eval (nv[1]) == "1") {
315 cb.has_target = true;
317 } else if (nv[0] == "transfer_ownership") {
318 if (eval (nv[1]) == "1") {
319 return_type.value_owned = true;
325 uint remaining_params = f_node.parameters.length ();
326 foreach (weak IdlNodeParam param in f_node.parameters) {
327 weak IdlNode param_node = (IdlNode) param;
329 if (check_has_target && remaining_params == 1 && (param_node.name == "user_data" || param_node.name == "data")) {
330 // hide user_data parameter for instance delegates
331 cb.has_target = true;
332 } else {
333 string param_name = param_node.name;
334 if (param_name == "string") {
335 // avoid conflict with string type
336 param_name = "str";
337 } else if (param_name == "self") {
338 // avoid conflict with delegate target
339 param_name = "_self";
342 ParameterDirection direction;
343 var param_type = parse_param (param, out direction);
344 var p = new FormalParameter (param_name, param_type);
345 p.direction = direction;
347 bool hide_param = false;
348 bool show_param = false;
349 attributes = get_attributes ("%s.%s".printf (node.name, param_node.name));
350 if (attributes != null) {
351 foreach (string attr in attributes) {
352 var nv = attr.split ("=", 2);
353 if (nv[0] == "hidden") {
354 if (eval (nv[1]) == "1") {
355 hide_param = true;
356 } else if (eval (nv[1]) == "0") {
357 show_param = true;
359 } else if (nv[0] == "is_out") {
360 if (eval (nv[1]) == "1") {
361 p.direction = ParameterDirection.OUT;
363 } else if (nv[0] == "is_ref") {
364 if (eval (nv[1]) == "1") {
365 p.direction = ParameterDirection.REF;
367 } else if (nv[0] == "takes_ownership") {
368 if (eval (nv[1]) == "1") {
369 param_type.value_owned = true;
371 } else if (nv[0] == "nullable") {
372 if (eval (nv[1]) == "1") {
373 param_type.nullable = true;
379 if (show_param || !hide_param) {
380 cb.add_parameter (p);
384 remaining_params--;
387 return cb;
390 private bool is_reference_type (string cname) {
391 var st_attributes = get_attributes (cname);
392 if (st_attributes != null) {
393 foreach (string attr in st_attributes) {
394 var nv = attr.split ("=", 2);
395 if (nv[0] == "is_value_type" && eval (nv[1]) == "1") {
396 return false;
400 return true;
403 private void parse_struct (IdlNodeStruct st_node, Namespace ns, IdlModule module) {
404 weak IdlNode node = (IdlNode) st_node;
406 if (st_node.deprecated) {
407 return;
410 string name = fix_type_name (node.name, ns);
412 if (!is_reference_type (node.name)) {
413 var st = ns.scope.lookup (name) as Struct;
414 if (st == null) {
415 st = new Struct (name, current_source_reference);
416 st.access = SymbolAccessibility.PUBLIC;
418 var st_attributes = get_attributes (node.name);
419 if (st_attributes != null) {
420 foreach (string attr in st_attributes) {
421 var nv = attr.split ("=", 2);
422 if (nv[0] == "cheader_filename") {
423 st.add_cheader_filename (eval (nv[1]));
424 } else if (nv[0] == "hidden") {
425 if (eval (nv[1]) == "1") {
426 return;
428 } else if (nv[0] == "simple_type") {
429 if (eval (nv[1]) == "1") {
430 st.set_simple_type (true);
432 } else if (nv[0] == "immutable") {
433 if (eval (nv[1]) == "1") {
434 st.is_immutable = true;
436 } else if (nv[0] == "has_type_id") {
437 if (eval (nv[1]) == "0") {
438 st.has_type_id = false;
440 } else if (nv[0] == "type_id") {
441 st.set_type_id (eval (nv[1]));
442 } else if (nv[0] == "has_copy_function") {
443 if (eval (nv[1]) == "0") {
444 st.has_copy_function = false;
446 } else if (nv[0] == "has_destroy_function") {
447 if (eval (nv[1]) == "0") {
448 st.has_destroy_function = false;
454 ns.add_struct (st);
455 current_source_file.add_node (st);
458 current_data_type = st;
460 foreach (weak IdlNode member in st_node.members) {
461 if (member.type == IdlNodeTypeId.FUNCTION) {
462 var m = parse_function ((IdlNodeFunction) member);
463 if (m != null) {
464 st.add_method (m);
466 } else if (member.type == IdlNodeTypeId.FIELD) {
467 var f = parse_field ((IdlNodeField) member);
468 if (f != null) {
469 st.add_field (f);
474 current_data_type = null;
475 } else {
476 bool ref_function_void = false;
477 string ref_function = null;
478 string unref_function = null;
479 string copy_function = null;
480 string free_function = null;
482 var cl = ns.scope.lookup (name) as Class;
483 if (cl == null) {
484 string base_class = null;
486 cl = new Class (name, current_source_reference);
487 cl.access = SymbolAccessibility.PUBLIC;
488 cl.is_compact = true;
490 var cl_attributes = get_attributes (node.name);
491 if (cl_attributes != null) {
492 foreach (string attr in cl_attributes) {
493 var nv = attr.split ("=", 2);
494 if (nv[0] == "cheader_filename") {
495 cl.add_cheader_filename (eval (nv[1]));
496 } else if (nv[0] == "base_class") {
497 base_class = eval (nv[1]);
498 } else if (nv[0] == "hidden") {
499 if (eval (nv[1]) == "1") {
500 return;
502 } else if (nv[0] == "is_immutable") {
503 if (eval (nv[1]) == "1") {
504 cl.is_immutable = true;
506 } else if (nv[0] == "const_cname") {
507 cl.const_cname = eval (nv[1]);
508 } else if (nv[0] == "is_fundamental") {
509 if (eval (nv[1]) == "1") {
510 cl.is_compact = false;
512 } else if (nv[0] == "abstract" && base_class != null) {
513 if (eval (nv[1]) == "1") {
514 cl.is_abstract = true;
516 } else if (nv[0] == "free_function") {
517 free_function = eval (nv[1]);
518 } else if (nv[0] == "ref_function") {
519 ref_function = eval (nv[1]);
520 } else if (nv[0] == "unref_function") {
521 unref_function = eval (nv[1]);
522 } else if (nv[0] == "copy_function") {
523 copy_function = eval (nv[1]);
524 } else if (nv[0] == "ref_function_void") {
525 if (eval (nv[1]) == "1") {
526 ref_function_void = true;
532 ns.add_class (cl);
533 current_source_file.add_node (cl);
535 if (base_class != null) {
536 var parent = parse_type_string (base_class);
537 cl.add_base_type (parent);
541 current_data_type = cl;
543 foreach (weak IdlNode member in st_node.members) {
544 if (member.type == IdlNodeTypeId.FUNCTION) {
545 if ((ref_function == null) && (member.name == "ref")) {
546 ref_function = ((IdlNodeFunction) member).symbol;
547 ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
548 } else if ((unref_function == null) && (member.name == "unref")) {
549 unref_function = ((IdlNodeFunction) member).symbol;
550 } else if ((free_function == null) && (member.name == "free" || member.name == "destroy")) {
551 free_function = ((IdlNodeFunction) member).symbol;
552 } else {
553 if ((copy_function == null) && (member.name == "copy")) {
554 copy_function = ((IdlNodeFunction) member).symbol;
556 var m = parse_function ((IdlNodeFunction) member);
557 if (m != null) {
558 cl.add_method (m);
561 } else if (member.type == IdlNodeTypeId.FIELD) {
562 var f = parse_field ((IdlNodeField) member);
563 if (f != null) {
564 cl.add_field (f);
569 if (ref_function != null) {
570 cl.set_ref_function (ref_function);
571 cl.ref_function_void = ref_function_void;
573 if (copy_function != null) {
574 cl.set_dup_function (copy_function);
576 if (unref_function != null) {
577 cl.set_unref_function (unref_function);
578 } else if (free_function != null) {
579 cl.set_free_function (free_function);
582 current_data_type = null;
586 private void parse_union (IdlNodeUnion un_node, Namespace ns, IdlModule module) {
587 weak IdlNode node = (IdlNode) un_node;
589 if (un_node.deprecated) {
590 return;
593 string name = fix_type_name (node.name, ns);
595 if (!is_reference_type (node.name)) {
596 var st = ns.scope.lookup (name) as Struct;
597 if (st == null) {
598 st = new Struct (name, current_source_reference);
599 st.access = SymbolAccessibility.PUBLIC;
601 var st_attributes = get_attributes (node.name);
602 if (st_attributes != null) {
603 foreach (string attr in st_attributes) {
604 var nv = attr.split ("=", 2);
605 if (nv[0] == "cheader_filename") {
606 st.add_cheader_filename (eval (nv[1]));
607 } else if (nv[0] == "hidden") {
608 if (eval (nv[1]) == "1") {
609 return;
615 ns.add_struct (st);
616 current_source_file.add_node (st);
619 current_data_type = st;
621 foreach (weak IdlNode member in un_node.members) {
622 if (member.type == IdlNodeTypeId.FUNCTION) {
623 var m = parse_function ((IdlNodeFunction) member);
624 if (m != null) {
625 st.add_method (m);
627 } else if (member.type == IdlNodeTypeId.FIELD) {
628 var f = parse_field ((IdlNodeField) member);
629 if (f != null) {
630 st.add_field (f);
635 current_data_type = null;
636 } else {
637 var cl = ns.scope.lookup (name) as Class;
638 if (cl == null) {
639 cl = new Class (name, current_source_reference);
640 cl.access = SymbolAccessibility.PUBLIC;
641 cl.is_compact = true;
643 var cl_attributes = get_attributes (node.name);
644 if (cl_attributes != null) {
645 foreach (string attr in cl_attributes) {
646 var nv = attr.split ("=", 2);
647 if (nv[0] == "cheader_filename") {
648 cl.add_cheader_filename (eval (nv[1]));
649 } else if (nv[0] == "hidden") {
650 if (eval (nv[1]) == "1") {
651 return;
657 ns.add_class (cl);
658 current_source_file.add_node (cl);
661 current_data_type = cl;
663 bool ref_function_void = false;
664 string ref_function = null;
665 string unref_function = null;
666 string copy_function = null;
667 string free_function = null;
669 foreach (weak IdlNode member in un_node.members) {
670 if (member.type == IdlNodeTypeId.FUNCTION) {
671 if (member.name == "ref") {
672 ref_function = ((IdlNodeFunction) member).symbol;
673 ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
674 } else if (member.name == "unref") {
675 unref_function = ((IdlNodeFunction) member).symbol;
676 } else if (member.name == "free" || member.name == "destroy") {
677 free_function = ((IdlNodeFunction) member).symbol;
678 } else {
679 if (member.name == "copy") {
680 copy_function = ((IdlNodeFunction) member).symbol;
682 var m = parse_function ((IdlNodeFunction) member);
683 if (m != null) {
684 cl.add_method (m);
687 } else if (member.type == IdlNodeTypeId.FIELD) {
688 var f = parse_field ((IdlNodeField) member);
689 if (f != null) {
690 cl.add_field (f);
695 if (ref_function != null) {
696 cl.set_ref_function (ref_function);
697 cl.ref_function_void = ref_function_void;
699 if (copy_function != null) {
700 cl.set_dup_function (copy_function);
702 if (unref_function != null) {
703 cl.set_unref_function (unref_function);
704 } else if (free_function != null) {
705 cl.set_free_function (free_function);
708 current_data_type = null;
712 private void parse_boxed (IdlNodeBoxed boxed_node, Namespace ns, IdlModule module) {
713 weak IdlNode node = (IdlNode) boxed_node;
715 string name = fix_type_name (node.name, ns);
717 var node_attributes = get_attributes (node.name);
718 if (node_attributes != null) {
719 foreach (string attr in node_attributes) {
720 var nv = attr.split ("=", 2);
721 if (nv[0] == "hidden") {
722 return;
727 if (!is_reference_type (node.name)) {
728 var st = ns.scope.lookup (name) as Struct;
729 if (st == null) {
730 st = new Struct (name, current_source_reference);
731 st.access = SymbolAccessibility.PUBLIC;
733 var st_attributes = get_attributes (node.name);
734 if (st_attributes != null) {
735 foreach (string attr in st_attributes) {
736 var nv = attr.split ("=", 2);
737 if (nv[0] == "cheader_filename") {
738 st.add_cheader_filename (eval (nv[1]));
739 } else if (nv[0] == "immutable") {
740 if (eval (nv[1]) == "1") {
741 st.is_immutable = true;
743 } else if (nv[0] == "has_copy_function") {
744 if (eval (nv[1]) == "0") {
745 st.has_copy_function = false;
747 } else if (nv[0] == "has_destroy_function") {
748 if (eval (nv[1]) == "0") {
749 st.has_destroy_function = false;
755 ns.add_struct (st);
756 st.set_type_id (st.get_upper_case_cname ("TYPE_"));
757 current_source_file.add_node (st);
760 current_data_type = st;
762 foreach (weak IdlNode member in boxed_node.members) {
763 if (member.type == IdlNodeTypeId.FUNCTION) {
764 var m = parse_function ((IdlNodeFunction) member);
765 if (m != null) {
766 st.add_method (m);
768 } else if (member.type == IdlNodeTypeId.FIELD) {
769 var f = parse_field ((IdlNodeField) member);
770 if (f != null) {
771 st.add_field (f);
776 current_data_type = null;
777 } else {
778 var cl = ns.scope.lookup (name) as Class;
779 if (cl == null) {
780 cl = new Class (name, current_source_reference);
781 cl.access = SymbolAccessibility.PUBLIC;
782 cl.is_compact = true;
784 var cl_attributes = get_attributes (node.name);
785 if (cl_attributes != null) {
786 foreach (string attr in cl_attributes) {
787 var nv = attr.split ("=", 2);
788 if (nv[0] == "cheader_filename") {
789 cl.add_cheader_filename (eval (nv[1]));
790 } else if (nv[0] == "is_immutable") {
791 if (eval (nv[1]) == "1") {
792 cl.is_immutable = true;
794 } else if (nv[0] == "const_cname") {
795 cl.const_cname = eval (nv[1]);
800 ns.add_class (cl);
801 cl.set_type_id (cl.get_upper_case_cname ("TYPE_"));
802 current_source_file.add_node (cl);
805 current_data_type = cl;
807 bool ref_function_void = false;
808 string ref_function = null;
809 string unref_function = null;
810 string copy_function = null;
811 string free_function = null;
813 foreach (weak IdlNode member in boxed_node.members) {
814 if (member.type == IdlNodeTypeId.FUNCTION) {
815 if (member.name == "ref") {
816 ref_function = ((IdlNodeFunction) member).symbol;
817 ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
818 } else if (member.name == "unref") {
819 unref_function = ((IdlNodeFunction) member).symbol;
820 } else if (member.name == "free" || member.name == "destroy") {
821 free_function = ((IdlNodeFunction) member).symbol;
822 } else {
823 if (member.name == "copy") {
824 copy_function = ((IdlNodeFunction) member).symbol;
826 var m = parse_function ((IdlNodeFunction) member);
827 if (m != null) {
828 cl.add_method (m);
831 } else if (member.type == IdlNodeTypeId.FIELD) {
832 var f = parse_field ((IdlNodeField) member);
833 if (f != null) {
834 cl.add_field (f);
839 if (ref_function != null) {
840 cl.set_ref_function (ref_function);
841 cl.ref_function_void = ref_function_void;
843 if (copy_function != null) {
844 cl.set_dup_function (copy_function);
846 if (unref_function != null) {
847 cl.set_unref_function (unref_function);
848 } else if (free_function != null) {
849 cl.set_free_function (free_function);
852 current_data_type = null;
856 private TypeSymbol? parse_enum (IdlNodeEnum en_node) {
857 weak IdlNode node = (IdlNode) en_node;
859 var en = new Enum (node.name, current_source_reference);
860 en.access = SymbolAccessibility.PUBLIC;
861 en.has_type_id = (en_node.gtype_name != null && en_node.gtype_name != "");
863 string common_prefix = null;
865 foreach (weak IdlNode value in en_node.values) {
866 if (common_prefix == null) {
867 common_prefix = value.name;
868 while (common_prefix.len () > 0 && !common_prefix.has_suffix ("_")) {
869 // FIXME: could easily be made faster
870 common_prefix = common_prefix.ndup (common_prefix.size () - 1);
872 } else {
873 while (!value.name.has_prefix (common_prefix)) {
874 common_prefix = common_prefix.ndup (common_prefix.size () - 1);
877 while (common_prefix.len () > 0 && (!common_prefix.has_suffix ("_") ||
878 (value.name.offset (common_prefix.length).get_char ().isdigit ()) && (value.name.len () - common_prefix.len ()) <= 1)) {
879 // enum values may not consist solely of digits
880 common_prefix = common_prefix.ndup (common_prefix.size () - 1);
884 bool is_errordomain = false;
886 var cheader_filenames = new ArrayList<string> ();
888 var en_attributes = get_attributes (node.name);
889 if (en_attributes != null) {
890 foreach (string attr in en_attributes) {
891 var nv = attr.split ("=", 2);
892 if (nv[0] == "common_prefix") {
893 common_prefix = eval (nv[1]);
894 } else if (nv[0] == "cheader_filename") {
895 cheader_filenames.add (eval (nv[1]));
896 en.add_cheader_filename (eval (nv[1]));
897 } else if (nv[0] == "hidden") {
898 if (eval (nv[1]) == "1") {
899 return null;
901 } else if (nv[0] == "rename_to") {
902 en.name = eval (nv[1]);
903 } else if (nv[0] == "errordomain") {
904 if (eval (nv[1]) == "1") {
905 is_errordomain = true;
907 } else if (nv[0] == "to_string") {
908 var return_type = new UnresolvedType ();
909 return_type.unresolved_symbol = new UnresolvedSymbol (null, "string");
910 return_type.value_owned = false;
911 var m = new Method ("to_string", return_type, current_source_reference);
912 m.access = SymbolAccessibility.PUBLIC;
913 m.set_cname (eval(nv[1]));
914 en.add_method (m);
919 en.set_cprefix (common_prefix);
921 foreach (weak IdlNode value2 in en_node.values) {
922 var ev = new EnumValue (value2.name.offset (common_prefix.len ()));
923 en.add_value (ev);
926 if (is_errordomain) {
927 var ed = new ErrorDomain (en.name, current_source_reference);
928 ed.access = SymbolAccessibility.PUBLIC;
929 ed.set_cprefix (common_prefix);
931 foreach (string filename in cheader_filenames) {
932 ed.add_cheader_filename (filename);
935 foreach (EnumValue ev in en.get_values ()) {
936 ed.add_code (new ErrorCode (ev.name));
939 return ed;
942 return en;
945 private void parse_object (IdlNodeInterface node, Namespace ns, IdlModule module) {
946 string name = fix_type_name (((IdlNode) node).name, ns);
948 string base_class = null;
950 var cl = ns.scope.lookup (name) as Class;
951 if (cl == null) {
952 cl = new Class (name, current_source_reference);
953 cl.access = SymbolAccessibility.PUBLIC;
955 var attributes = get_attributes (node.gtype_name);
956 if (attributes != null) {
957 foreach (string attr in attributes) {
958 var nv = attr.split ("=", 2);
959 if (nv[0] == "cheader_filename") {
960 cl.add_cheader_filename (eval (nv[1]));
961 } else if (nv[0] == "base_class") {
962 base_class = eval (nv[1]);
963 } else if (nv[0] == "hidden") {
964 if (eval (nv[1]) == "1") {
965 return;
967 } else if (nv[0] == "type_check_function") {
968 cl.type_check_function = eval (nv[1]);
969 } else if (nv[0] == "abstract") {
970 if (eval (nv[1]) == "1") {
971 cl.is_abstract = true;
977 ns.add_class (cl);
978 current_source_file.add_node (cl);
981 if (base_class != null) {
982 var parent = parse_type_string (base_class);
983 cl.add_base_type (parent);
984 } else if (node.parent != null) {
985 var parent = parse_type_string (node.parent);
986 cl.add_base_type (parent);
987 } else {
988 var gobject_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Object");
989 cl.add_base_type (new UnresolvedType.from_symbol (gobject_symbol));
992 foreach (string iface_name in node.interfaces) {
993 var iface = parse_type_string (iface_name);
994 cl.add_base_type (iface);
997 current_data_type = cl;
999 current_type_symbol_set = new HashSet<string> (str_hash, str_equal);
1000 var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
1001 var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
1003 foreach (weak IdlNode member in node.members) {
1004 if (member.type == IdlNodeTypeId.FUNCTION) {
1005 current_type_func_map.set (member.name, (IdlNodeFunction) member);
1007 if (member.type == IdlNodeTypeId.VFUNC) {
1008 current_type_vfunc_map.set (member.name, "1");
1012 foreach (weak IdlNode member in node.members) {
1013 if (member.type == IdlNodeTypeId.FUNCTION) {
1014 // Ignore if vfunc (handled below)
1015 if (!current_type_vfunc_map.contains (member.name)) {
1016 var m = parse_function ((IdlNodeFunction) member);
1017 if (m != null) {
1018 cl.add_method (m);
1021 } else if (member.type == IdlNodeTypeId.VFUNC) {
1022 var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name));
1023 if (m != null) {
1024 cl.add_method (m);
1026 } else if (member.type == IdlNodeTypeId.PROPERTY) {
1027 var prop = parse_property ((IdlNodeProperty) member);
1028 if (prop != null) {
1029 cl.add_property (prop);
1031 } else if (member.type == IdlNodeTypeId.SIGNAL) {
1032 var sig = parse_signal ((IdlNodeSignal) member);
1033 if (sig != null) {
1034 cl.add_signal (sig);
1039 foreach (weak IdlNode member in node.members) {
1040 if (member.type == IdlNodeTypeId.FIELD) {
1041 if (!current_type_symbol_set.contains (member.name)) {
1042 var f = parse_field ((IdlNodeField) member);
1043 if (f != null) {
1044 cl.add_field (f);
1050 foreach (Property prop in cl.get_properties ()) {
1051 var getter = "get_%s".printf (prop.name);
1053 if (prop.get_accessor != null && !current_type_symbol_set.contains (getter)) {
1054 prop.no_accessor_method = true;
1057 var setter = "set_%s".printf (prop.name);
1059 if (prop.set_accessor != null && prop.set_accessor.writable
1060 && !current_type_symbol_set.contains (setter)) {
1061 prop.no_accessor_method = true;
1064 if (prop.no_accessor_method && prop.get_accessor != null) {
1065 prop.get_accessor.value_type.value_owned = true;
1069 handle_async_methods (cl);
1071 current_data_type = null;
1072 current_type_symbol_set = null;
1075 private void parse_interface (IdlNodeInterface node, Namespace ns, IdlModule module) {
1076 string name = fix_type_name (node.gtype_name, ns);
1078 var iface = ns.scope.lookup (name) as Interface;
1079 if (iface == null) {
1080 iface = new Interface (name, current_source_reference);
1081 iface.access = SymbolAccessibility.PUBLIC;
1083 var attributes = get_attributes (node.gtype_name);
1084 if (attributes != null) {
1085 foreach (string attr in attributes) {
1086 var nv = attr.split ("=", 2);
1087 if (nv[0] == "cheader_filename") {
1088 iface.add_cheader_filename (eval (nv[1]));
1089 } else if (nv[0] == "lower_case_csuffix") {
1090 iface.set_lower_case_csuffix (eval (nv[1]));
1095 foreach (string prereq_name in node.prerequisites) {
1096 var prereq = parse_type_string (prereq_name);
1097 iface.add_prerequisite (prereq);
1100 ns.add_interface (iface);
1101 current_source_file.add_node (iface);
1104 current_data_type = iface;
1106 var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
1107 var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
1109 foreach (weak IdlNode member in node.members) {
1110 if (member.type == IdlNodeTypeId.FUNCTION) {
1111 current_type_func_map.set (member.name, (IdlNodeFunction) member);
1113 if (member.type == IdlNodeTypeId.VFUNC) {
1114 current_type_vfunc_map.set (member.name, "1");
1118 foreach (weak IdlNode member in node.members) {
1119 if (member.type == IdlNodeTypeId.FUNCTION) {
1120 // Ignore if vfunc (handled below)
1121 if (!current_type_vfunc_map.contains (member.name)) {
1122 var m = parse_function ((IdlNodeFunction) member, true);
1123 if (m != null) {
1124 iface.add_method (m);
1127 } else if (member.type == IdlNodeTypeId.VFUNC) {
1128 var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name), true);
1129 if (m != null) {
1130 iface.add_method (m);
1132 } else if (member.type == IdlNodeTypeId.PROPERTY) {
1133 var prop = parse_property ((IdlNodeProperty) member);
1134 if (prop != null) {
1135 iface.add_property (prop);
1137 } else if (member.type == IdlNodeTypeId.SIGNAL) {
1138 var sig = parse_signal ((IdlNodeSignal) member);
1139 if (sig != null) {
1140 iface.add_signal (sig);
1141 sig.is_virtual = false;
1146 handle_async_methods (iface);
1148 current_data_type = null;
1151 void handle_async_methods (ObjectTypeSymbol type_symbol) {
1152 foreach (Method m in type_symbol.get_methods ()) {
1153 if (m.coroutine) {
1154 string finish_method_base;
1155 if (m.name.has_suffix ("_async")) {
1156 finish_method_base = m.name.substring (0, m.name.length - "_async".length);
1157 } else {
1158 finish_method_base = m.name;
1160 var finish_method = type_symbol.scope.lookup (finish_method_base + "_finish") as Method;
1161 if (finish_method != null) {
1162 m.return_type = finish_method.return_type.copy ();
1163 foreach (var param in finish_method.get_parameters ()) {
1164 if (param.direction == ParameterDirection.OUT) {
1165 var async_param = param.copy ();
1166 if (m.scope.lookup (param.name) != null) {
1167 // parameter name conflict
1168 async_param.name += "_out";
1170 m.add_parameter (async_param);
1173 foreach (DataType error_type in finish_method.get_error_types ()) {
1174 m.add_error_type (error_type.copy ());
1181 private DataType? parse_type (IdlNodeType type_node, out ParameterDirection direction = null) {
1182 ParameterDirection dir = ParameterDirection.IN;
1184 var type = new UnresolvedType ();
1185 if (type_node.tag == TypeTag.VOID) {
1186 if (type_node.is_pointer) {
1187 return new PointerType (new VoidType ());
1188 } else {
1189 return new VoidType ();
1191 } else if (type_node.tag == TypeTag.BOOLEAN) {
1192 type.unresolved_symbol = new UnresolvedSymbol (null, "bool");
1193 } else if (type_node.tag == TypeTag.INT8) {
1194 type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1195 } else if (type_node.tag == TypeTag.UINT8) {
1196 type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1197 } else if (type_node.tag == TypeTag.INT16) {
1198 type.unresolved_symbol = new UnresolvedSymbol (null, "int16");
1199 } else if (type_node.tag == TypeTag.UINT16) {
1200 type.unresolved_symbol = new UnresolvedSymbol (null, "uint16");
1201 } else if (type_node.tag == TypeTag.INT32) {
1202 type.unresolved_symbol = new UnresolvedSymbol (null, "int32");
1203 } else if (type_node.tag == TypeTag.UINT32) {
1204 type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
1205 } else if (type_node.tag == TypeTag.INT64) {
1206 type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1207 } else if (type_node.tag == TypeTag.UINT64) {
1208 type.unresolved_symbol = new UnresolvedSymbol (null, "uint64");
1209 } else if (type_node.tag == TypeTag.INT) {
1210 type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1211 } else if (type_node.tag == TypeTag.UINT) {
1212 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1213 } else if (type_node.tag == TypeTag.LONG) {
1214 type.unresolved_symbol = new UnresolvedSymbol (null, "long");
1215 } else if (type_node.tag == TypeTag.ULONG) {
1216 type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1217 } else if (type_node.tag == TypeTag.SSIZE) {
1218 type.unresolved_symbol = new UnresolvedSymbol (null, "ssize_t");
1219 } else if (type_node.tag == TypeTag.SIZE) {
1220 type.unresolved_symbol = new UnresolvedSymbol (null, "size_t");
1221 } else if (type_node.tag == TypeTag.FLOAT) {
1222 type.unresolved_symbol = new UnresolvedSymbol (null, "float");
1223 } else if (type_node.tag == TypeTag.DOUBLE) {
1224 type.unresolved_symbol = new UnresolvedSymbol (null, "double");
1225 } else if (type_node.tag == TypeTag.UTF8) {
1226 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1227 } else if (type_node.tag == TypeTag.FILENAME) {
1228 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1229 } else if (type_node.tag == TypeTag.ARRAY) {
1230 var element_type = parse_type (type_node.parameter_type1);
1231 type = element_type as UnresolvedType;
1232 if (type == null) {
1233 return element_type;
1235 return new ArrayType (element_type, 1, element_type.source_reference);
1236 } else if (type_node.tag == TypeTag.LIST) {
1237 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "List");
1238 } else if (type_node.tag == TypeTag.SLIST) {
1239 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "SList");
1240 } else if (type_node.tag == TypeTag.HASH) {
1241 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "HashTable");
1242 } else if (type_node.tag == TypeTag.ERROR) {
1243 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Error");
1244 } else if (type_node.is_interface) {
1245 var n = type_node.@interface;
1247 if (n == "") {
1248 return null;
1251 if (n.has_prefix ("const-")) {
1252 n = n.offset ("const-".len ());
1255 if (type_node.is_pointer &&
1256 (n == "gchar" || n == "char")) {
1257 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1258 if (type_node.unparsed.has_suffix ("**")) {
1259 dir = ParameterDirection.OUT;
1261 } else if (n == "gunichar") {
1262 type.unresolved_symbol = new UnresolvedSymbol (null, "unichar");
1263 } else if (n == "gchar") {
1264 type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1265 } else if (n == "guchar" || n == "guint8") {
1266 type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1267 if (type_node.is_pointer) {
1268 return new ArrayType (type, 1, type.source_reference);
1270 } else if (n == "gushort") {
1271 type.unresolved_symbol = new UnresolvedSymbol (null, "ushort");
1272 } else if (n == "gshort") {
1273 type.unresolved_symbol = new UnresolvedSymbol (null, "short");
1274 } else if (n == "gconstpointer" || n == "void") {
1275 return new PointerType (new VoidType ());
1276 } else if (n == "goffset" || n == "off_t") {
1277 type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1278 } else if (n == "value_array") {
1279 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "ValueArray");
1280 } else if (n == "time_t") {
1281 type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1282 } else if (n == "socklen_t") {
1283 type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
1284 } else if (n == "mode_t") {
1285 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1286 } else if (n == "gint" || n == "pid_t") {
1287 type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1288 } else if (n == "unsigned" || n == "unsigned-int") {
1289 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1290 } else if (n == "FILE") {
1291 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "FileStream");
1292 } else if (n == "struct") {
1293 return new PointerType (new VoidType ());
1294 } else if (n == "iconv_t") {
1295 return new PointerType (new VoidType ());
1296 } else if (n == "GType") {
1297 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Type");
1298 if (type_node.is_pointer) {
1299 return new ArrayType (type, 1, type.source_reference);
1301 } else if (n == "GStrv") {
1302 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1303 return new ArrayType (type, 1, type.source_reference);
1304 } else {
1305 var named_type = parse_type_string (n);
1306 type = named_type as UnresolvedType;
1307 if (type == null) {
1308 return named_type;
1310 if (is_simple_type (n)) {
1311 if (type_node.is_pointer) {
1312 dir = ParameterDirection.OUT;
1314 } else if (type_node.unparsed.has_suffix ("**")) {
1315 dir = ParameterDirection.OUT;
1318 } else {
1319 stdout.printf ("%d\n", type_node.tag);
1321 if (&direction != null) {
1322 direction = dir;
1324 return type;
1327 private bool is_simple_type (string type_name) {
1328 var st = cname_type_map[type_name] as Struct;
1329 if (st != null && st.is_simple_type ()) {
1330 return true;
1333 return false;
1336 private DataType parse_type_string (string n) {
1337 if (n == "va_list") {
1338 // unsupported
1339 return new PointerType (new VoidType ());
1342 var type = new UnresolvedType ();
1344 var dt = cname_type_map[n];
1345 if (dt != null) {
1346 UnresolvedSymbol parent_symbol = null;
1347 if (dt.parent_symbol.name != null) {
1348 parent_symbol = new UnresolvedSymbol (null, dt.parent_symbol.name);
1350 type.unresolved_symbol = new UnresolvedSymbol (parent_symbol, dt.name);
1351 return type;
1354 var type_attributes = get_attributes (n);
1356 string ns_name = null;
1358 if (null != type_attributes) {
1359 foreach (string attr in type_attributes) {
1360 var nv = attr.split ("=", 2);
1362 if (nv[0] == "cprefix") {
1363 type.unresolved_symbol = new UnresolvedSymbol (null, n.offset (eval (nv[1]).len ()));
1364 } else if (nv[0] == "name") {
1365 type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1366 } else if (nv[0] == "namespace") {
1367 ns_name = eval (nv[1]);
1368 } else if (nv[0] == "rename_to") {
1369 type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1374 if (type.unresolved_symbol != null) {
1375 if (type.unresolved_symbol.name == "pointer") {
1376 return new PointerType (new VoidType ());
1378 if (ns_name != null) {
1379 type.unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
1381 return type;
1384 if (n.has_prefix (current_namespace.name)) {
1385 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, current_namespace.name), n.offset (current_namespace.name.len ()));
1386 } else if (n.has_prefix ("G")) {
1387 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), n.offset (1));
1388 } else {
1389 var name_parts = n.split (".", 2);
1390 if (name_parts[1] == null) {
1391 type.unresolved_symbol = new UnresolvedSymbol (null, name_parts[0]);
1392 } else {
1393 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, name_parts[0]), name_parts[1]);
1397 return type;
1400 private DataType? parse_param (IdlNodeParam param, out ParameterDirection direction = null) {
1401 var type = parse_type (param.type, out direction);
1403 // disable for now as null_ok not yet correctly set
1404 // type.non_null = !param.null_ok;
1406 return type;
1409 private Method? create_method (string name, string symbol, IdlNodeParam? res, GLib.List<IdlNodeParam>? parameters, bool is_constructor, bool is_interface) {
1410 DataType return_type = null;
1411 if (res != null) {
1412 return_type = parse_param (res);
1415 Method m;
1416 if (!is_interface && (is_constructor || name.has_prefix ("new"))) {
1417 m = new CreationMethod (null, name, current_source_reference);
1418 m.has_construct_function = false;
1419 if (m.name == "new") {
1420 m.name = null;
1421 } else if (m.name.has_prefix ("new_")) {
1422 m.name = m.name.offset ("new_".len ());
1424 // For classes, check whether a creation method return type equals to the
1425 // type of the class created. If the types do not match (e.g. in most
1426 // gtk widgets) add an attribute to the creation method indicating the used
1427 // return type.
1428 if (current_data_type is Class && res != null) {
1429 if ("%s*".printf (current_data_type.get_cname()) != res.type.unparsed) {
1430 ((CreationMethod)m).custom_return_type_cname = res.type.unparsed;
1433 } else {
1434 m = new Method (name, return_type, current_source_reference);
1436 m.access = SymbolAccessibility.PUBLIC;
1438 if (current_type_symbol_set != null) {
1439 current_type_symbol_set.add (name);
1442 if (current_data_type != null) {
1443 var sig_attributes = get_attributes ("%s::%s".printf (current_data_type.get_cname (), name));
1444 if (sig_attributes != null) {
1445 foreach (string attr in sig_attributes) {
1446 var nv = attr.split ("=", 2);
1447 if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
1448 return null;
1454 bool add_ellipsis = false;
1455 bool suppress_throws = false;
1457 var attributes = get_attributes (symbol);
1458 if (attributes != null) {
1459 foreach (string attr in attributes) {
1460 var nv = attr.split ("=", 2);
1461 if (nv[0] == "name") {
1462 m.set_cname (m.name);
1463 m.name = eval (nv[1]);
1464 } else if (nv[0] == "hidden") {
1465 if (eval (nv[1]) == "1") {
1466 return null;
1468 } else if (nv[0] == "ellipsis") {
1469 if (eval (nv[1]) == "1") {
1470 add_ellipsis = true;
1472 } else if (nv[0] == "printf_format") {
1473 if (eval (nv[1]) == "1") {
1474 m.printf_format = true;
1476 } else if (nv[0] == "transfer_ownership") {
1477 if (eval (nv[1]) == "1") {
1478 return_type.value_owned = true;
1480 } else if (nv[0] == "nullable") {
1481 if (eval (nv[1]) == "1") {
1482 return_type.nullable = true;
1484 } else if (nv[0] == "sentinel") {
1485 m.sentinel = eval (nv[1]);
1486 } else if (nv[0] == "is_array") {
1487 if (eval (nv[1]) == "1") {
1488 return_type = new ArrayType (return_type, 1, return_type.source_reference);
1489 m.return_type = return_type;
1491 } else if (nv[0] == "throws") {
1492 if (eval (nv[1]) == "0") {
1493 suppress_throws = true;
1495 } else if (nv[0] == "no_array_length") {
1496 if (eval (nv[1]) == "1") {
1497 m.no_array_length = true;
1499 } else if (nv[0] == "array_null_terminated") {
1500 if (eval (nv[1]) == "1") {
1501 m.no_array_length = true;
1502 m.array_null_terminated = true;
1504 } else if (nv[0] == "type_name") {
1505 var sym = new UnresolvedSymbol (null, eval (nv[1]));
1506 if (return_type is UnresolvedType) {
1507 ((UnresolvedType) return_type).unresolved_symbol = sym;
1508 } else {
1509 // Overwrite old return_type, so "type_name" must be before any
1510 // other return type modifying metadata
1511 m.return_type = return_type = new UnresolvedType.from_symbol (sym, return_type.source_reference);
1513 } else if (nv[0] == "type_arguments") {
1514 var type_args = eval (nv[1]).split (",");
1515 foreach (string type_arg in type_args) {
1516 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1517 arg_type.value_owned = true;
1518 return_type.add_type_argument (arg_type);
1520 } else if (nv[0] == "cheader_filename") {
1521 m.add_cheader_filename (eval (nv[1]));
1522 } else if (nv[0] == "abstract") {
1523 if (eval (nv[1]) == "1") {
1524 m.is_abstract = true;
1526 } else if (nv[0] == "virtual") {
1527 if (eval (nv[1]) == "1") {
1528 m.is_virtual = true;
1530 } else if (nv[0] == "vfunc_name") {
1531 m.vfunc_name = eval (nv[1]);
1532 } else if (nv[0] == "async") {
1533 if (eval (nv[1]) == "1") {
1534 // force async function, even if it doesn't end in _async
1535 m.coroutine = true;
1541 m.set_cname (symbol);
1543 bool first = true;
1544 FormalParameter last_param = null;
1545 DataType last_param_type = null;
1546 foreach (weak IdlNodeParam param in parameters) {
1547 weak IdlNode param_node = (IdlNode) param;
1549 if (first) {
1550 first = false;
1551 if (!(m is CreationMethod) &&
1552 current_data_type != null &&
1553 param.type.is_interface &&
1554 (param_node.name == "self" ||
1555 param.type.@interface.has_suffix (current_data_type.get_cname ()))) {
1556 // instance method
1557 continue;
1558 } else if (!(m is CreationMethod) &&
1559 current_data_type != null &&
1560 param.type.is_interface &&
1561 (param_node.name == "klass" ||
1562 param.type.@interface.has_suffix ("%sClass".printf(current_data_type.get_cname ())))) {
1563 // class method
1564 m.binding = MemberBinding.CLASS;
1565 if (m.name.has_prefix ("class_")) {
1566 m.name = m.name.substring ("class_".len (), m.name.len () - "class_".len ());
1568 continue;
1569 } else {
1570 // static method
1571 m.binding = MemberBinding.STATIC;
1575 if (param.type.@interface == "GAsyncReadyCallback" && (symbol.has_suffix ("_async") || m.coroutine)) {
1576 // async method
1577 m.coroutine = true;
1578 continue;
1581 if (suppress_throws == false && param_is_exception (param)) {
1582 m.add_error_type (parse_type (param.type));
1583 continue;
1586 string param_name = param_node.name;
1587 if (param_name == "result") {
1588 // avoid conflict with generated result variable
1589 param_name = "_result";
1590 } else if (param_name == "string") {
1591 // avoid conflict with string type
1592 param_name = "str";
1594 ParameterDirection direction;
1595 var param_type = parse_param (param, out direction);
1596 var p = new FormalParameter (param_name, param_type);
1597 p.direction = direction;
1599 bool hide_param = false;
1600 bool show_param = false;
1601 bool set_array_length_pos = false;
1602 double array_length_pos = 0;
1603 bool set_delegate_target_pos = false;
1604 double delegate_target_pos = 0;
1605 bool array_requested = false;
1606 attributes = get_attributes ("%s.%s".printf (symbol, param_node.name));
1607 if (attributes != null) {
1608 foreach (string attr in attributes) {
1609 var nv = attr.split ("=", 2);
1610 if (nv[0] == "is_array") {
1611 if (eval (nv[1]) == "1") {
1612 param_type = new ArrayType (param_type, 1, param_type.source_reference);
1613 p.parameter_type = param_type;
1614 p.direction = ParameterDirection.IN;
1615 array_requested = true;
1617 } else if (nv[0] == "is_out") {
1618 if (eval (nv[1]) == "1") {
1619 p.direction = ParameterDirection.OUT;
1620 if (!array_requested && param_type is ArrayType) {
1621 var array_type = (ArrayType) param_type;
1622 param_type = array_type.element_type;
1623 p.parameter_type = param_type;
1626 } else if (nv[0] == "is_ref") {
1627 if (eval (nv[1]) == "1") {
1628 p.direction = ParameterDirection.REF;
1629 if (!array_requested && param_type is ArrayType) {
1630 var array_type = (ArrayType) param_type;
1631 param_type = array_type.element_type;
1632 p.parameter_type = param_type;
1635 } else if (nv[0] == "nullable") {
1636 if (eval (nv[1]) == "1") {
1637 param_type.nullable = true;
1639 } else if (nv[0] == "transfer_ownership") {
1640 if (eval (nv[1]) == "1") {
1641 param_type.value_owned = true;
1643 } else if (nv[0] == "takes_ownership") {
1644 if (eval (nv[1]) == "1") {
1645 param_type.value_owned = true;
1647 } else if (nv[0] == "value_owned") {
1648 if (eval (nv[1]) == "0") {
1649 param_type.value_owned = false;
1650 } else if (eval (nv[1]) == "1") {
1651 param_type.value_owned = true;
1653 } else if (nv[0] == "hidden") {
1654 if (eval (nv[1]) == "1") {
1655 hide_param = true;
1656 } else if (eval (nv[1]) == "0") {
1657 show_param = true;
1659 } else if (nv[0] == "no_array_length") {
1660 if (eval (nv[1]) == "1") {
1661 p.no_array_length = true;
1663 } else if (nv[0] == "array_null_terminated") {
1664 if (eval (nv[1]) == "1") {
1665 p.no_array_length = true;
1666 p.array_null_terminated = true;
1668 } else if (nv[0] == "array_length_pos") {
1669 set_array_length_pos = true;
1670 array_length_pos = eval (nv[1]).to_double ();
1671 } else if (nv[0] == "delegate_target_pos") {
1672 set_delegate_target_pos = true;
1673 delegate_target_pos = eval (nv[1]).to_double ();
1674 } else if (nv[0] == "type_name") {
1675 ((UnresolvedType) param_type).unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1676 } else if (nv[0] == "ctype") {
1677 p.ctype = eval (nv[1]);
1678 } else if (nv[0] == "type_arguments") {
1679 var type_args = eval (nv[1]).split (",");
1680 foreach (string type_arg in type_args) {
1681 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1682 arg_type.value_owned = true;
1683 param_type.add_type_argument (arg_type);
1689 if (last_param != null && p.name == "n_" + last_param.name) {
1690 if (!(last_param_type is ArrayType)) {
1691 // last_param is array, p is array length
1692 last_param_type = new ArrayType (last_param_type, 1, last_param_type.source_reference);
1693 last_param.parameter_type = last_param_type;
1694 last_param.direction = ParameterDirection.IN;
1697 // hide array length param
1698 hide_param = true;
1699 } else if (last_param != null && p.name == "user_data") {
1700 // last_param is delegate
1702 // hide deleate target param
1703 hide_param = true;
1706 if (show_param || !hide_param) {
1707 m.add_parameter (p);
1708 if (set_array_length_pos) {
1709 p.carray_length_parameter_position = array_length_pos;
1711 if (set_delegate_target_pos) {
1712 p.cdelegate_target_parameter_position = delegate_target_pos;
1716 last_param = p;
1717 last_param_type = param_type;
1720 if (first) {
1721 // no parameters => static method
1722 m.binding = MemberBinding.STATIC;
1725 if (last_param != null && last_param.name.has_prefix ("first_")) {
1726 last_param.ellipsis = true;
1727 } else if (add_ellipsis) {
1728 m.add_parameter (new FormalParameter.with_ellipsis ());
1731 return m;
1734 private bool param_is_exception (IdlNodeParam param) {
1735 if (!param.type.is_error) {
1736 return false;
1738 var s = param.type.unparsed.chomp ();
1739 if (s.has_suffix ("**")) {
1740 return true;
1742 return false;
1745 private Method? parse_function (IdlNodeFunction f, bool is_interface = false) {
1746 weak IdlNode node = (IdlNode) f;
1748 if (f.deprecated) {
1749 return null;
1752 return create_method (node.name, f.symbol, f.result, f.parameters, f.is_constructor, is_interface);
1755 private Method parse_virtual (IdlNodeVFunc v, IdlNodeFunction? func, bool is_interface = false) {
1756 weak IdlNode node = (IdlNode) v;
1757 string symbol = "%s%s".printf (current_data_type.get_lower_case_cprefix(), node.name);
1759 if (func != null) {
1760 symbol = func.symbol;
1763 Method m = create_method (node.name, symbol, v.result, func != null ? func.parameters : v.parameters, false, is_interface);
1764 if (m != null) {
1765 m.binding = MemberBinding.INSTANCE;
1766 m.is_virtual = !(m.is_abstract || is_interface);
1767 m.is_abstract = m.is_abstract || is_interface;
1769 var attributes = get_attributes (symbol);
1770 if (attributes != null) {
1771 foreach (string attr in attributes) {
1772 var nv = attr.split ("=", 2);
1773 if (nv[0] == "virtual") {
1774 if (eval (nv[1]) == "0") {
1775 m.is_virtual = false;
1776 m.is_abstract = false;
1782 if (func == null) {
1783 m.attributes.append (new Attribute ("NoWrapper", null));
1787 return m;
1790 private string fix_prop_name (string name) {
1791 var str = new StringBuilder ();
1793 string i = name;
1795 while (i.len () > 0) {
1796 unichar c = i.get_char ();
1797 if (c == '-') {
1798 str.append_c ('_');
1799 } else {
1800 str.append_unichar (c);
1803 i = i.next_char ();
1806 return str.str;
1809 private Property? parse_property (IdlNodeProperty prop_node) {
1810 weak IdlNode node = (IdlNode) prop_node;
1812 if (prop_node.deprecated) {
1813 return null;
1816 if (!prop_node.readable && !prop_node.writable) {
1817 // buggy GIDL definition
1818 prop_node.readable = true;
1819 prop_node.writable = true;
1822 var prop = new Property (fix_prop_name (node.name), parse_type (prop_node.type), null, null, current_source_reference);
1823 prop.access = SymbolAccessibility.PUBLIC;
1824 prop.interface_only = true;
1826 if (prop_node.type.is_interface && prop_node.type.interface == "GStrv") {
1827 prop.no_array_length = true;
1828 prop.array_null_terminated = true;
1831 if (prop_node.readable) {
1832 prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, null);
1834 if (prop_node.writable) {
1835 prop.set_accessor = new PropertyAccessor (false, false, false, prop.property_type.copy (), null, null);
1836 if (prop_node.construct_only) {
1837 prop.set_accessor.construction = true;
1838 } else {
1839 prop.set_accessor.writable = true;
1840 prop.set_accessor.construction = prop_node.@construct;
1844 var attributes = get_attributes ("%s:%s".printf (current_data_type.get_cname (), node.name));
1845 if (attributes != null) {
1846 foreach (string attr in attributes) {
1847 var nv = attr.split ("=", 2);
1848 if (nv[0] == "hidden") {
1849 if (eval (nv[1]) == "1") {
1850 return null;
1852 } else if (nv[0] == "type_arguments") {
1853 var type_args = eval (nv[1]).split (",");
1854 foreach (string type_arg in type_args) {
1855 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1856 arg_type.value_owned = true;
1857 prop.property_type.add_type_argument (arg_type);
1859 } else if (nv[0] == "accessor_method") {
1860 if (eval (nv[1]) == "0") {
1861 prop.no_accessor_method = true;
1863 } else if (nv[0] == "owned_get") {
1864 if (eval (nv[1]) == "1") {
1865 prop.get_accessor.value_type.value_owned = true;
1871 if (current_type_symbol_set != null) {
1872 current_type_symbol_set.add (prop.name);
1875 return prop;
1878 private Constant? parse_constant (IdlNodeConstant const_node) {
1879 weak IdlNode node = (IdlNode) const_node;
1881 var type = parse_type (const_node.type);
1882 if (type == null) {
1883 return null;
1886 var c = new Constant (node.name, type, null, current_source_reference);
1887 c.external = true;
1889 string[] attributes = get_attributes (node.name);
1890 if (attributes != null) {
1891 foreach (string attr in attributes) {
1892 var nv = attr.split ("=", 2);
1893 if (nv[0] == "cheader_filename") {
1894 c.add_cheader_filename (eval (nv[1]));
1895 } else if (nv[0] == "hidden") {
1896 if (eval (nv[1]) == "1") {
1897 return null;
1903 c.access = SymbolAccessibility.PUBLIC;
1905 return c;
1908 private Field? parse_field (IdlNodeField field_node) {
1909 weak IdlNode node = (IdlNode) field_node;
1910 bool unhidden = false;
1912 var type = parse_type (field_node.type);
1913 if (type == null) {
1914 return null;
1917 string cheader_filename = null;
1918 string ctype = null;
1919 bool array_null_terminated = false;
1921 var attributes = get_attributes ("%s.%s".printf (current_data_type.get_cname (), node.name));
1922 if (attributes != null) {
1923 foreach (string attr in attributes) {
1924 var nv = attr.split ("=", 2);
1925 if (nv[0] == "hidden") {
1926 if (eval (nv[1]) == "1") {
1927 return null;
1928 } else {
1929 unhidden = true;
1931 } else if (nv[0] == "is_array") {
1932 if (eval (nv[1]) == "1") {
1933 type = new ArrayType (type, 1, type.source_reference);
1935 } else if (nv[0] == "weak") {
1936 if (eval (nv[1]) == "0") {
1937 type.value_owned = true;
1939 } else if (nv[0] == "type_name") {
1940 ((UnresolvedType) type).unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1941 } else if (nv[0] == "type_arguments") {
1942 var type_args = eval (nv[1]).split (",");
1943 foreach (string type_arg in type_args) {
1944 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1945 arg_type.value_owned = true;
1946 type.add_type_argument (arg_type);
1948 } else if (nv[0] == "cheader_filename") {
1949 cheader_filename = eval (nv[1]);
1950 } else if (nv[0] == "ctype") {
1951 ctype = eval (nv[1]);
1952 } else if (nv[0] == "array_null_terminated") {
1953 if (eval (nv[1]) == "1") {
1954 array_null_terminated = true;
1960 if (node.name.has_prefix("_") && !unhidden) {
1961 return null;
1964 if (current_type_symbol_set != null) {
1965 current_type_symbol_set.add (node.name);
1968 string field_name = node.name;
1969 if (field_name == "string") {
1970 // avoid conflict with string type
1971 field_name = "str";
1974 var field = new Field (field_name, type, null, current_source_reference);
1975 field.access = SymbolAccessibility.PUBLIC;
1977 if (field_name != node.name) {
1978 field.set_cname (node.name);
1981 if (ctype != null) {
1982 field.set_ctype (ctype);
1985 if (cheader_filename != null) {
1986 field.add_cheader_filename (cheader_filename);
1989 field.no_array_length = true;
1990 if (array_null_terminated) {
1991 field.array_null_terminated = true;
1994 return field;
1997 private string[]? get_attributes (string codenode) {
1998 var attributes = codenode_attributes_map.get (codenode);
2000 if (attributes == null) {
2001 var dot_required = (null != codenode.chr (-1, '.'));
2002 var colon_required = (null != codenode.chr (-1, ':'));
2004 var pattern_specs = codenode_attributes_patterns.get_keys ();
2005 foreach (PatternSpec* pattern in pattern_specs) {
2006 var pspec = codenode_attributes_patterns[pattern];
2008 if ((dot_required && null == pspec.chr (-1, '.')) ||
2009 (colon_required && null == pspec.chr (-1, ':'))) {
2010 continue;
2013 if (pattern->match_string (codenode)) {
2014 return get_attributes (pspec);
2019 if (attributes == null) {
2020 return null;
2023 return attributes.split (" ");
2026 private string eval (string s) {
2027 return ((s.size () >= 2) && s.has_prefix ("\"") && s.has_suffix ("\"")) ? s.offset (1).ndup (s.size () - 2) : s;
2030 private Signal? parse_signal (IdlNodeSignal sig_node) {
2031 weak IdlNode node = (IdlNode) sig_node;
2033 if (sig_node.deprecated || sig_node.result == null) {
2034 return null;
2037 var sig = new Signal (fix_prop_name (node.name), parse_param (sig_node.result), current_source_reference);
2038 sig.access = SymbolAccessibility.PUBLIC;
2040 var attributes = get_attributes ("%s::%s".printf (current_data_type.get_cname (), sig.name));
2041 if (attributes != null) {
2042 foreach (string attr in attributes) {
2043 var nv = attr.split ("=", 2);
2044 if (nv[0] == "name") {
2045 sig.set_cname (sig.name);
2046 sig.name = eval (nv[1]);
2047 } else if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
2048 sig.has_emitter = true;
2049 } else if (nv[0] == "hidden") {
2050 if (eval (nv[1]) == "1") {
2051 return null;
2057 sig.is_virtual = true;
2059 bool first = true;
2061 foreach (weak IdlNodeParam param in sig_node.parameters) {
2062 if (first) {
2063 // ignore implicit first signal parameter (sender)
2064 first = false;
2065 continue;
2068 weak IdlNode param_node = (IdlNode) param;
2070 ParameterDirection direction;
2071 var param_type = parse_param (param, out direction);
2072 var p = new FormalParameter (param_node.name, param_type);
2073 p.direction = direction;
2074 sig.add_parameter (p);
2076 attributes = get_attributes ("%s::%s.%s".printf (current_data_type.get_cname (), sig.name, param_node.name));
2077 if (attributes != null) {
2078 string ns_name = null;
2079 foreach (string attr in attributes) {
2080 var nv = attr.split ("=", 2);
2081 if (nv[0] == "is_array") {
2082 if (eval (nv[1]) == "1") {
2083 param_type = new ArrayType (param_type, 1, param_type.source_reference);
2084 p.parameter_type = param_type;
2085 p.direction = ParameterDirection.IN;
2087 } else if (nv[0] == "is_out") {
2088 if (eval (nv[1]) == "1") {
2089 p.direction = ParameterDirection.OUT;
2091 } else if (nv[0] == "is_ref") {
2092 if (eval (nv[1]) == "1") {
2093 p.direction = ParameterDirection.REF;
2095 } else if (nv[0] == "nullable") {
2096 if (eval (nv[1]) == "1") {
2097 param_type.nullable = true;
2099 } else if (nv[0] == "transfer_ownership") {
2100 if (eval (nv[1]) == "1") {
2101 param_type.value_owned = true;
2103 } else if (nv[0] == "type_name") {
2104 ((UnresolvedType) param_type).unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
2105 } else if (nv[0] == "namespace_name") {
2106 ns_name = eval (nv[1]);
2109 if (ns_name != null) {
2110 ((UnresolvedType) param_type).unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
2115 return sig;
2119 // vim:sw=8 noet