GAsync: Another temp variable fix
[vala-lang.git] / vapigen / valagidlparser.vala
blob4c5df97709f07df2563f50bb5e0a8dbfa63d66bc
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;
26 using Gee;
28 /**
29 * Code visitor parsing all GIDL files.
31 public class Vala.GIdlParser : CodeVisitor {
32 private CodeContext context;
34 private SourceFile current_source_file;
36 private SourceReference current_source_reference;
38 private Namespace current_namespace;
39 private TypeSymbol current_data_type;
40 private Map<string,string> codenode_attributes_map;
41 private Map<PatternSpec*,string> codenode_attributes_patterns;
42 private Gee.Set<string> current_type_symbol_set;
44 private Map<string,TypeSymbol> cname_type_map;
46 /**
47 * Parse all source files in the specified code context and build a
48 * code tree.
50 * @param context a code context
52 public void parse (CodeContext context) {
53 cname_type_map = new HashMap<string,TypeSymbol> (str_hash, str_equal);
55 this.context = context;
56 context.accept (this);
58 cname_type_map = null;
61 public override void visit_namespace (Namespace ns) {
62 ns.accept_children (this);
65 public override void visit_class (Class cl) {
66 visit_type (cl);
69 public override void visit_struct (Struct st) {
70 visit_type (st);
73 public override void visit_interface (Interface iface) {
74 visit_type (iface);
77 public override void visit_enum (Enum en) {
78 visit_type (en);
81 public override void visit_error_domain (ErrorDomain ed) {
82 visit_type (ed);
85 public override void visit_delegate (Delegate d) {
86 visit_type (d);
89 private void visit_type (TypeSymbol t) {
90 if (!cname_type_map.contains (t.get_cname ())) {
91 cname_type_map[t.get_cname ()] = t;
95 public override void visit_source_file (SourceFile source_file) {
96 if (source_file.filename.has_suffix (".gi")) {
97 parse_file (source_file);
101 private void parse_file (SourceFile source_file) {
102 string metadata_filename = "%s.metadata".printf (source_file.filename.ndup (source_file.filename.size () - ".gi".size ()));
104 current_source_file = source_file;
106 codenode_attributes_map = new HashMap<string,string> (str_hash, str_equal);
107 codenode_attributes_patterns = new HashMap<PatternSpec*,string> (direct_hash, (EqualFunc) PatternSpec.equal);
109 if (FileUtils.test (metadata_filename, FileTest.EXISTS)) {
110 try {
111 string metadata;
112 FileUtils.get_contents (metadata_filename, out metadata, null);
114 foreach (string line in metadata.split ("\n")) {
115 if (line.has_prefix ("#")) {
116 // ignore comment lines
117 continue;
120 var tokens = line.split (" ", 2);
122 if (null == tokens[0]) {
123 continue;
126 if (null != tokens[0].chr (-1, '*')) {
127 PatternSpec* pattern = new PatternSpec (tokens[0]);
128 codenode_attributes_patterns[pattern] = tokens[0];
131 codenode_attributes_map[tokens[0]] = tokens[1];
133 } catch (FileError e) {
134 Report.error (null, "Unable to read metadata file: %s".printf (e.message));
138 try {
139 var modules = Idl.parse_file (source_file.filename);
141 current_source_reference = new SourceReference (source_file);
143 foreach (weak IdlModule module in modules) {
144 var ns = parse_module (module);
145 if (ns != null) {
146 context.root.add_namespace (ns);
149 } catch (MarkupError e) {
150 stdout.printf ("error parsing GIDL file: %s\n", e.message);
154 private string fix_type_name (string type_name, Namespace ns) {
155 var attributes = get_attributes (type_name);
156 if (attributes != null) {
157 foreach (string attr in attributes) {
158 var nv = attr.split ("=", 2);
159 if (nv[0] == "name") {
160 return eval (nv[1]);
165 if (type_name.has_prefix (ns.name)) {
166 return type_name.offset (ns.name.len ());
167 } else if (ns.name == "GLib" && type_name.has_prefix ("G")) {
168 return type_name.offset (1);
169 } else {
170 string best_match = null;
171 foreach (string cprefix in ns.get_cprefixes ()) {
172 if (type_name.has_prefix (cprefix)) {
173 if (best_match == null || cprefix.len () > best_match.len ())
174 best_match = cprefix;
178 if (best_match != null) {
179 return type_name.offset (best_match.len ());;
183 return type_name;
186 private string fix_const_name (string const_name, Namespace ns) {
187 if (const_name.has_prefix (ns.name.up () + "_")) {
188 return const_name.offset (ns.name.len () + 1);
189 } else if (ns.name == "GLib" && const_name.has_prefix ("G_")) {
190 return const_name.offset (2);
192 return const_name;
195 private Namespace? parse_module (IdlModule module) {
196 Symbol sym = context.root.scope.lookup (module.name);
197 Namespace ns;
198 if (sym is Namespace) {
199 ns = (Namespace) sym;
200 if (ns.external_package) {
201 ns.attributes = null;
202 ns.source_reference = current_source_reference;
204 } else {
205 ns = new Namespace (module.name, current_source_reference);
208 current_namespace = ns;
210 var attributes = get_attributes (ns.name);
211 if (attributes != null) {
212 foreach (string attr in attributes) {
213 var nv = attr.split ("=", 2);
214 if (nv[0] == "cheader_filename") {
215 ns.set_cheader_filename (eval (nv[1]));
216 } else if (nv[0] == "cprefix") {
217 var cprefixes = eval (nv[1]).split (",");
218 foreach(string name in cprefixes) {
219 ns.add_cprefix (name);
221 } else if (nv[0] == "lower_case_cprefix") {
222 ns.set_lower_case_cprefix (eval (nv[1]));
227 foreach (weak IdlNode node in module.entries) {
228 if (node.type == IdlNodeTypeId.CALLBACK) {
229 var cb = parse_delegate ((IdlNodeFunction) node);
230 if (cb == null) {
231 continue;
233 cb.name = fix_type_name (cb.name, ns);
234 ns.add_delegate (cb);
235 current_source_file.add_node (cb);
236 } else if (node.type == IdlNodeTypeId.STRUCT) {
237 parse_struct ((IdlNodeStruct) node, ns, module);
238 } else if (node.type == IdlNodeTypeId.UNION) {
239 parse_union ((IdlNodeUnion) node, ns, module);
240 } else if (node.type == IdlNodeTypeId.BOXED) {
241 parse_boxed ((IdlNodeBoxed) node, ns, module);
242 } else if (node.type == IdlNodeTypeId.ENUM) {
243 var en = parse_enum ((IdlNodeEnum) node);
244 if (en == null) {
245 continue;
247 en.name = fix_type_name (en.name, ns);
248 if (en is ErrorDomain) {
249 ns.add_error_domain (en as ErrorDomain);
250 } else {
251 ns.add_enum (en as Enum);
253 current_source_file.add_node (en);
254 } else if (node.type == IdlNodeTypeId.FLAGS) {
255 var en = parse_enum ((IdlNodeEnum) node) as Enum;
256 if (en == null) {
257 continue;
259 en.name = fix_type_name (en.name, ns);
260 en.is_flags = true;
261 ns.add_enum (en);
262 current_source_file.add_node (en);
263 } else if (node.type == IdlNodeTypeId.OBJECT) {
264 parse_object ((IdlNodeInterface) node, ns, module);
265 } else if (node.type == IdlNodeTypeId.INTERFACE) {
266 parse_interface ((IdlNodeInterface) node, ns, module);
267 } else if (node.type == IdlNodeTypeId.CONSTANT) {
268 var c = parse_constant ((IdlNodeConstant) node);
269 if (c != null) {
270 c.name = fix_const_name (c.name, ns);
271 ns.add_constant (c);
272 current_source_file.add_node (c);
274 } else if (node.type == IdlNodeTypeId.FUNCTION) {
275 var m = parse_function ((IdlNodeFunction) node);
276 if (m != null) {
277 m.binding = MemberBinding.STATIC;
278 ns.add_method (m);
279 current_source_file.add_node (m);
284 current_namespace = null;
286 if (sym is Namespace) {
287 return null;
289 return ns;
292 private Delegate? parse_delegate (IdlNodeFunction f_node) {
293 weak IdlNode node = (IdlNode) f_node;
295 var return_type = parse_param (f_node.result);
297 var cb = new Delegate (node.name, return_type, current_source_reference);
298 cb.access = SymbolAccessibility.PUBLIC;
300 bool check_has_target = true;
302 var attributes = get_attributes (node.name);
303 if (attributes != null) {
304 foreach (string attr in attributes) {
305 var nv = attr.split ("=", 2);
306 if (nv[0] == "hidden") {
307 if (eval (nv[1]) == "1") {
308 return null;
310 } else if (nv[0] == "cheader_filename") {
311 cb.add_cheader_filename (eval (nv[1]));
312 } else if (nv[0] == "has_target") {
313 if (eval (nv[1]) == "0") {
314 check_has_target = false;
315 } else if (eval (nv[1]) == "1") {
316 cb.has_target = true;
318 } else if (nv[0] == "transfer_ownership") {
319 if (eval (nv[1]) == "1") {
320 return_type.value_owned = true;
326 uint remaining_params = f_node.parameters.length ();
327 foreach (weak IdlNodeParam param in f_node.parameters) {
328 weak IdlNode param_node = (IdlNode) param;
330 if (check_has_target && remaining_params == 1 && (param_node.name == "user_data" || param_node.name == "data")) {
331 // hide user_data parameter for instance delegates
332 cb.has_target = true;
333 } else {
334 string param_name = param_node.name;
335 if (param_name == "string") {
336 // avoid conflict with string type
337 param_name = "str";
338 } else if (param_name == "self") {
339 // avoid conflict with delegate target
340 param_name = "_self";
343 ParameterDirection direction;
344 var param_type = parse_param (param, out direction);
345 var p = new FormalParameter (param_name, param_type);
346 p.direction = direction;
348 bool hide_param = false;
349 bool show_param = false;
350 attributes = get_attributes ("%s.%s".printf (node.name, param_node.name));
351 if (attributes != null) {
352 foreach (string attr in attributes) {
353 var nv = attr.split ("=", 2);
354 if (nv[0] == "hidden") {
355 if (eval (nv[1]) == "1") {
356 hide_param = true;
357 } else if (eval (nv[1]) == "0") {
358 show_param = true;
360 } else if (nv[0] == "is_out") {
361 if (eval (nv[1]) == "1") {
362 p.direction = ParameterDirection.OUT;
364 } else if (nv[0] == "is_ref") {
365 if (eval (nv[1]) == "1") {
366 p.direction = ParameterDirection.REF;
368 } else if (nv[0] == "takes_ownership") {
369 if (eval (nv[1]) == "1") {
370 param_type.value_owned = true;
376 if (show_param || !hide_param) {
377 cb.add_parameter (p);
381 remaining_params--;
384 return cb;
387 private bool is_reference_type (string cname) {
388 var st_attributes = get_attributes (cname);
389 if (st_attributes != null) {
390 foreach (string attr in st_attributes) {
391 var nv = attr.split ("=", 2);
392 if (nv[0] == "is_value_type" && eval (nv[1]) == "1") {
393 return false;
397 return true;
400 private void parse_struct (IdlNodeStruct st_node, Namespace ns, IdlModule module) {
401 weak IdlNode node = (IdlNode) st_node;
403 if (st_node.deprecated) {
404 return;
407 string name = fix_type_name (node.name, ns);
409 if (!is_reference_type (node.name)) {
410 var st = ns.scope.lookup (name) as Struct;
411 if (st == null) {
412 st = new Struct (name, current_source_reference);
413 st.access = SymbolAccessibility.PUBLIC;
415 var st_attributes = get_attributes (node.name);
416 if (st_attributes != null) {
417 foreach (string attr in st_attributes) {
418 var nv = attr.split ("=", 2);
419 if (nv[0] == "cheader_filename") {
420 st.add_cheader_filename (eval (nv[1]));
421 } else if (nv[0] == "hidden") {
422 if (eval (nv[1]) == "1") {
423 return;
425 } else if (nv[0] == "simple_type") {
426 if (eval (nv[1]) == "1") {
427 st.set_simple_type (true);
429 } else if (nv[0] == "use_const") {
430 if (eval (nv[1]) == "0") {
431 st.use_const = false;
433 } else if (nv[0] == "has_type_id") {
434 if (eval (nv[1]) == "0") {
435 st.has_type_id = false;
437 } else if (nv[0] == "type_id") {
438 st.set_type_id (eval (nv[1]));
439 } else if (nv[0] == "has_copy_function") {
440 if (eval (nv[1]) == "0") {
441 st.has_copy_function = false;
443 } else if (nv[0] == "has_destroy_function") {
444 if (eval (nv[1]) == "0") {
445 st.has_destroy_function = false;
451 ns.add_struct (st);
452 current_source_file.add_node (st);
455 current_data_type = st;
457 foreach (weak IdlNode member in st_node.members) {
458 if (member.type == IdlNodeTypeId.FUNCTION) {
459 var m = parse_function ((IdlNodeFunction) member);
460 if (m != null) {
461 st.add_method (m);
463 } else if (member.type == IdlNodeTypeId.FIELD) {
464 var f = parse_field ((IdlNodeField) member);
465 if (f != null) {
466 st.add_field (f);
471 current_data_type = null;
472 } else {
473 bool ref_function_void = false;
474 string ref_function = null;
475 string unref_function = null;
476 string copy_function = null;
477 string free_function = null;
479 var cl = ns.scope.lookup (name) as Class;
480 if (cl == null) {
481 string base_class = null;
483 cl = new Class (name, current_source_reference);
484 cl.access = SymbolAccessibility.PUBLIC;
485 cl.is_compact = true;
487 var cl_attributes = get_attributes (node.name);
488 if (cl_attributes != null) {
489 foreach (string attr in cl_attributes) {
490 var nv = attr.split ("=", 2);
491 if (nv[0] == "cheader_filename") {
492 cl.add_cheader_filename (eval (nv[1]));
493 } else if (nv[0] == "base_class") {
494 base_class = eval (nv[1]);
495 } else if (nv[0] == "hidden") {
496 if (eval (nv[1]) == "1") {
497 return;
499 } else if (nv[0] == "is_immutable") {
500 if (eval (nv[1]) == "1") {
501 cl.is_immutable = true;
503 } else if (nv[0] == "is_fundamental") {
504 if (eval (nv[1]) == "1") {
505 cl.is_compact = false;
507 } else if (nv[0] == "abstract" && base_class != null) {
508 if (eval (nv[1]) == "1") {
509 cl.is_abstract = true;
511 } else if (nv[0] == "free_function") {
512 free_function = eval (nv[1]);
513 } else if (nv[0] == "ref_function") {
514 ref_function = eval (nv[1]);
515 } else if (nv[0] == "unref_function") {
516 unref_function = eval (nv[1]);
517 } else if (nv[0] == "copy_function") {
518 copy_function = eval (nv[1]);
519 } else if (nv[0] == "ref_function_void") {
520 if (eval (nv[1]) == "1") {
521 ref_function_void = true;
527 ns.add_class (cl);
528 current_source_file.add_node (cl);
530 if (base_class != null) {
531 var parent = parse_type_string (base_class);
532 cl.add_base_type (parent);
536 current_data_type = cl;
538 foreach (weak IdlNode member in st_node.members) {
539 if (member.type == IdlNodeTypeId.FUNCTION) {
540 if ((ref_function == null) && (member.name == "ref")) {
541 ref_function = ((IdlNodeFunction) member).symbol;
542 ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
543 } else if ((unref_function == null) && (member.name == "unref")) {
544 unref_function = ((IdlNodeFunction) member).symbol;
545 } else if ((free_function == null) && (member.name == "free" || member.name == "destroy")) {
546 free_function = ((IdlNodeFunction) member).symbol;
547 } else {
548 if ((copy_function == null) && (member.name == "copy")) {
549 copy_function = ((IdlNodeFunction) member).symbol;
551 var m = parse_function ((IdlNodeFunction) member);
552 if (m != null) {
553 cl.add_method (m);
556 } else if (member.type == IdlNodeTypeId.FIELD) {
557 var f = parse_field ((IdlNodeField) member);
558 if (f != null) {
559 cl.add_field (f);
564 if (ref_function != null) {
565 cl.set_ref_function (ref_function);
566 cl.ref_function_void = ref_function_void;
568 if (copy_function != null) {
569 cl.set_dup_function (copy_function);
571 if (unref_function != null) {
572 cl.set_unref_function (unref_function);
573 } else if (free_function != null) {
574 cl.set_free_function (free_function);
577 current_data_type = null;
581 private void parse_union (IdlNodeUnion un_node, Namespace ns, IdlModule module) {
582 weak IdlNode node = (IdlNode) un_node;
584 if (un_node.deprecated) {
585 return;
588 string name = fix_type_name (node.name, ns);
590 if (!is_reference_type (node.name)) {
591 var st = ns.scope.lookup (name) as Struct;
592 if (st == null) {
593 st = new Struct (name, current_source_reference);
594 st.access = SymbolAccessibility.PUBLIC;
596 var st_attributes = get_attributes (node.name);
597 if (st_attributes != null) {
598 foreach (string attr in st_attributes) {
599 var nv = attr.split ("=", 2);
600 if (nv[0] == "cheader_filename") {
601 st.add_cheader_filename (eval (nv[1]));
602 } else if (nv[0] == "hidden") {
603 if (eval (nv[1]) == "1") {
604 return;
610 ns.add_struct (st);
611 current_source_file.add_node (st);
614 current_data_type = st;
616 foreach (weak IdlNode member in un_node.members) {
617 if (member.type == IdlNodeTypeId.FUNCTION) {
618 var m = parse_function ((IdlNodeFunction) member);
619 if (m != null) {
620 st.add_method (m);
622 } else if (member.type == IdlNodeTypeId.FIELD) {
623 var f = parse_field ((IdlNodeField) member);
624 if (f != null) {
625 st.add_field (f);
630 current_data_type = null;
631 } else {
632 var cl = ns.scope.lookup (name) as Class;
633 if (cl == null) {
634 cl = new Class (name, current_source_reference);
635 cl.access = SymbolAccessibility.PUBLIC;
636 cl.is_compact = true;
638 var cl_attributes = get_attributes (node.name);
639 if (cl_attributes != null) {
640 foreach (string attr in cl_attributes) {
641 var nv = attr.split ("=", 2);
642 if (nv[0] == "cheader_filename") {
643 cl.add_cheader_filename (eval (nv[1]));
644 } else if (nv[0] == "hidden") {
645 if (eval (nv[1]) == "1") {
646 return;
652 ns.add_class (cl);
653 current_source_file.add_node (cl);
656 current_data_type = cl;
658 bool ref_function_void = false;
659 string ref_function = null;
660 string unref_function = null;
661 string copy_function = null;
662 string free_function = null;
664 foreach (weak IdlNode member in un_node.members) {
665 if (member.type == IdlNodeTypeId.FUNCTION) {
666 if (member.name == "ref") {
667 ref_function = ((IdlNodeFunction) member).symbol;
668 ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
669 } else if (member.name == "unref") {
670 unref_function = ((IdlNodeFunction) member).symbol;
671 } else if (member.name == "free" || member.name == "destroy") {
672 free_function = ((IdlNodeFunction) member).symbol;
673 } else {
674 if (member.name == "copy") {
675 copy_function = ((IdlNodeFunction) member).symbol;
677 var m = parse_function ((IdlNodeFunction) member);
678 if (m != null) {
679 cl.add_method (m);
682 } else if (member.type == IdlNodeTypeId.FIELD) {
683 var f = parse_field ((IdlNodeField) member);
684 if (f != null) {
685 cl.add_field (f);
690 if (ref_function != null) {
691 cl.set_ref_function (ref_function);
692 cl.ref_function_void = ref_function_void;
694 if (copy_function != null) {
695 cl.set_dup_function (copy_function);
697 if (unref_function != null) {
698 cl.set_unref_function (unref_function);
699 } else if (free_function != null) {
700 cl.set_free_function (free_function);
703 current_data_type = null;
707 private void parse_boxed (IdlNodeBoxed boxed_node, Namespace ns, IdlModule module) {
708 weak IdlNode node = (IdlNode) boxed_node;
710 string name = fix_type_name (node.name, ns);
712 var node_attributes = get_attributes (node.name);
713 if (node_attributes != null) {
714 foreach (string attr in node_attributes) {
715 var nv = attr.split ("=", 2);
716 if (nv[0] == "hidden") {
717 return;
722 if (!is_reference_type (node.name)) {
723 var st = ns.scope.lookup (name) as Struct;
724 if (st == null) {
725 st = new Struct (name, current_source_reference);
726 st.access = SymbolAccessibility.PUBLIC;
728 var st_attributes = get_attributes (node.name);
729 if (st_attributes != null) {
730 foreach (string attr in st_attributes) {
731 var nv = attr.split ("=", 2);
732 if (nv[0] == "cheader_filename") {
733 st.add_cheader_filename (eval (nv[1]));
734 } else if (nv[0] == "use_const") {
735 if (eval (nv[1]) == "0") {
736 st.use_const = false;
738 } else if (nv[0] == "has_copy_function") {
739 if (eval (nv[1]) == "0") {
740 st.has_copy_function = false;
742 } else if (nv[0] == "has_destroy_function") {
743 if (eval (nv[1]) == "0") {
744 st.has_destroy_function = false;
750 ns.add_struct (st);
751 st.set_type_id (st.get_upper_case_cname ("TYPE_"));
752 current_source_file.add_node (st);
755 current_data_type = st;
757 foreach (weak IdlNode member in boxed_node.members) {
758 if (member.type == IdlNodeTypeId.FUNCTION) {
759 var m = parse_function ((IdlNodeFunction) member);
760 if (m != null) {
761 st.add_method (m);
763 } else if (member.type == IdlNodeTypeId.FIELD) {
764 var f = parse_field ((IdlNodeField) member);
765 if (f != null) {
766 st.add_field (f);
771 current_data_type = null;
772 } else {
773 var cl = ns.scope.lookup (name) as Class;
774 if (cl == null) {
775 cl = new Class (name, current_source_reference);
776 cl.access = SymbolAccessibility.PUBLIC;
777 cl.is_compact = true;
779 var cl_attributes = get_attributes (node.name);
780 if (cl_attributes != null) {
781 foreach (string attr in cl_attributes) {
782 var nv = attr.split ("=", 2);
783 if (nv[0] == "cheader_filename") {
784 cl.add_cheader_filename (eval (nv[1]));
785 } else if (nv[0] == "is_immutable") {
786 if (eval (nv[1]) == "1") {
787 cl.is_immutable = true;
793 ns.add_class (cl);
794 cl.set_type_id (cl.get_upper_case_cname ("TYPE_"));
795 current_source_file.add_node (cl);
798 current_data_type = cl;
800 bool ref_function_void = false;
801 string ref_function = null;
802 string unref_function = null;
803 string copy_function = null;
804 string free_function = null;
806 foreach (weak IdlNode member in boxed_node.members) {
807 if (member.type == IdlNodeTypeId.FUNCTION) {
808 if (member.name == "ref") {
809 ref_function = ((IdlNodeFunction) member).symbol;
810 ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
811 } else if (member.name == "unref") {
812 unref_function = ((IdlNodeFunction) member).symbol;
813 } else if (member.name == "free" || member.name == "destroy") {
814 free_function = ((IdlNodeFunction) member).symbol;
815 } else {
816 if (member.name == "copy") {
817 copy_function = ((IdlNodeFunction) member).symbol;
819 var m = parse_function ((IdlNodeFunction) member);
820 if (m != null) {
821 cl.add_method (m);
824 } else if (member.type == IdlNodeTypeId.FIELD) {
825 var f = parse_field ((IdlNodeField) member);
826 if (f != null) {
827 cl.add_field (f);
832 if (ref_function != null) {
833 cl.set_ref_function (ref_function);
834 cl.ref_function_void = ref_function_void;
836 if (copy_function != null) {
837 cl.set_dup_function (copy_function);
839 if (unref_function != null) {
840 cl.set_unref_function (unref_function);
841 } else if (free_function != null) {
842 cl.set_free_function (free_function);
845 current_data_type = null;
849 private TypeSymbol? parse_enum (IdlNodeEnum en_node) {
850 weak IdlNode node = (IdlNode) en_node;
852 var en = new Enum (node.name, current_source_reference);
853 en.access = SymbolAccessibility.PUBLIC;
854 en.has_type_id = (en_node.gtype_name != null && en_node.gtype_name != "");
856 string common_prefix = null;
858 foreach (weak IdlNode value in en_node.values) {
859 if (common_prefix == null) {
860 common_prefix = value.name;
861 while (common_prefix.len () > 0 && !common_prefix.has_suffix ("_")) {
862 // FIXME: could easily be made faster
863 common_prefix = common_prefix.ndup (common_prefix.size () - 1);
865 } else {
866 while (!value.name.has_prefix (common_prefix)) {
867 common_prefix = common_prefix.ndup (common_prefix.size () - 1);
870 while (common_prefix.len () > 0 && (!common_prefix.has_suffix ("_") ||
871 (value.name.offset (common_prefix.length).get_char ().isdigit ()) && (value.name.len () - common_prefix.len ()) <= 1)) {
872 // enum values may not consist solely of digits
873 common_prefix = common_prefix.ndup (common_prefix.size () - 1);
877 bool is_errordomain = false;
879 var cheader_filenames = new ArrayList<string> ();
881 var en_attributes = get_attributes (node.name);
882 if (en_attributes != null) {
883 foreach (string attr in en_attributes) {
884 var nv = attr.split ("=", 2);
885 if (nv[0] == "common_prefix") {
886 common_prefix = eval (nv[1]);
887 } else if (nv[0] == "cheader_filename") {
888 cheader_filenames.add (eval (nv[1]));
889 en.add_cheader_filename (eval (nv[1]));
890 } else if (nv[0] == "hidden") {
891 if (eval (nv[1]) == "1") {
892 return null;
894 } else if (nv[0] == "rename_to") {
895 en.name = eval (nv[1]);
896 } else if (nv[0] == "errordomain") {
897 if (eval (nv[1]) == "1") {
898 is_errordomain = true;
900 } else if (nv[0] == "to_string") {
901 var return_type = new UnresolvedType ();
902 return_type.unresolved_symbol = new UnresolvedSymbol (null, "string");
903 return_type.value_owned = false;
904 var m = new Method ("to_string", return_type, current_source_reference);
905 m.access = SymbolAccessibility.PUBLIC;
906 m.set_cname (eval(nv[1]));
907 en.add_method (m);
912 en.set_cprefix (common_prefix);
914 foreach (weak IdlNode value2 in en_node.values) {
915 var ev = new EnumValue (value2.name.offset (common_prefix.len ()));
916 en.add_value (ev);
919 if (is_errordomain) {
920 var ed = new ErrorDomain (en.name, current_source_reference);
921 ed.access = SymbolAccessibility.PUBLIC;
922 ed.set_cprefix (common_prefix);
924 foreach (string filename in cheader_filenames) {
925 ed.add_cheader_filename (filename);
928 foreach (EnumValue ev in en.get_values ()) {
929 ed.add_code (new ErrorCode (ev.name));
932 return ed;
935 return en;
938 private void parse_object (IdlNodeInterface node, Namespace ns, IdlModule module) {
939 string name = fix_type_name (((IdlNode) node).name, ns);
941 string base_class = null;
943 var cl = ns.scope.lookup (name) as Class;
944 if (cl == null) {
945 cl = new Class (name, current_source_reference);
946 cl.access = SymbolAccessibility.PUBLIC;
948 var attributes = get_attributes (node.gtype_name);
949 if (attributes != null) {
950 foreach (string attr in attributes) {
951 var nv = attr.split ("=", 2);
952 if (nv[0] == "cheader_filename") {
953 cl.add_cheader_filename (eval (nv[1]));
954 } else if (nv[0] == "base_class") {
955 base_class = eval (nv[1]);
956 } else if (nv[0] == "hidden") {
957 if (eval (nv[1]) == "1") {
958 return;
960 } else if (nv[0] == "type_check_function") {
961 cl.type_check_function = eval (nv[1]);
962 } else if (nv[0] == "abstract") {
963 if (eval (nv[1]) == "1") {
964 cl.is_abstract = true;
970 ns.add_class (cl);
971 current_source_file.add_node (cl);
974 if (base_class != null) {
975 var parent = parse_type_string (base_class);
976 cl.add_base_type (parent);
977 } else if (node.parent != null) {
978 var parent = parse_type_string (node.parent);
979 cl.add_base_type (parent);
980 } else {
981 var gobject_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Object");
982 cl.add_base_type (new UnresolvedType.from_symbol (gobject_symbol));
985 foreach (string iface_name in node.interfaces) {
986 var iface = parse_type_string (iface_name);
987 cl.add_base_type (iface);
990 current_data_type = cl;
992 current_type_symbol_set = new HashSet<string> (str_hash, str_equal);
993 var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
994 var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
996 foreach (weak IdlNode member in node.members) {
997 if (member.type == IdlNodeTypeId.FUNCTION) {
998 current_type_func_map.set (member.name, (IdlNodeFunction) member);
1000 if (member.type == IdlNodeTypeId.VFUNC) {
1001 current_type_vfunc_map.set (member.name, "1");
1005 foreach (weak IdlNode member in node.members) {
1006 if (member.type == IdlNodeTypeId.FUNCTION) {
1007 // Ignore if vfunc (handled below)
1008 if (!current_type_vfunc_map.contains (member.name)) {
1009 var m = parse_function ((IdlNodeFunction) member);
1010 if (m != null) {
1011 cl.add_method (m);
1014 } else if (member.type == IdlNodeTypeId.VFUNC) {
1015 var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name));
1016 if (m != null) {
1017 cl.add_method (m);
1019 } else if (member.type == IdlNodeTypeId.PROPERTY) {
1020 var prop = parse_property ((IdlNodeProperty) member);
1021 if (prop != null) {
1022 cl.add_property (prop);
1024 } else if (member.type == IdlNodeTypeId.SIGNAL) {
1025 var sig = parse_signal ((IdlNodeSignal) member);
1026 if (sig != null) {
1027 cl.add_signal (sig);
1032 foreach (weak IdlNode member in node.members) {
1033 if (member.type == IdlNodeTypeId.FIELD) {
1034 if (!current_type_symbol_set.contains (member.name)) {
1035 var f = parse_field ((IdlNodeField) member);
1036 if (f != null) {
1037 cl.add_field (f);
1043 foreach (Property prop in cl.get_properties ()) {
1044 var getter = "get_%s".printf (prop.name);
1046 if (prop.get_accessor != null && !current_type_symbol_set.contains (getter)) {
1047 prop.no_accessor_method = true;
1050 var setter = "set_%s".printf (prop.name);
1052 if (prop.set_accessor != null && prop.set_accessor.writable
1053 && !current_type_symbol_set.contains (setter)) {
1054 prop.no_accessor_method = true;
1057 if (prop.no_accessor_method && prop.get_accessor != null) {
1058 prop.get_accessor.value_type.value_owned = true;
1062 handle_async_methods (cl);
1064 current_data_type = null;
1065 current_type_symbol_set = null;
1068 private void parse_interface (IdlNodeInterface node, Namespace ns, IdlModule module) {
1069 string name = fix_type_name (node.gtype_name, ns);
1071 var iface = ns.scope.lookup (name) as Interface;
1072 if (iface == null) {
1073 iface = new Interface (name, current_source_reference);
1074 iface.access = SymbolAccessibility.PUBLIC;
1076 var attributes = get_attributes (node.gtype_name);
1077 if (attributes != null) {
1078 foreach (string attr in attributes) {
1079 var nv = attr.split ("=", 2);
1080 if (nv[0] == "cheader_filename") {
1081 iface.add_cheader_filename (eval (nv[1]));
1082 } else if (nv[0] == "lower_case_csuffix") {
1083 iface.set_lower_case_csuffix (eval (nv[1]));
1088 foreach (string prereq_name in node.prerequisites) {
1089 var prereq = parse_type_string (prereq_name);
1090 iface.add_prerequisite (prereq);
1093 ns.add_interface (iface);
1094 current_source_file.add_node (iface);
1097 current_data_type = iface;
1099 var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
1100 var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
1102 foreach (weak IdlNode member in node.members) {
1103 if (member.type == IdlNodeTypeId.FUNCTION) {
1104 current_type_func_map.set (member.name, (IdlNodeFunction) member);
1106 if (member.type == IdlNodeTypeId.VFUNC) {
1107 current_type_vfunc_map.set (member.name, "1");
1111 foreach (weak IdlNode member in node.members) {
1112 if (member.type == IdlNodeTypeId.FUNCTION) {
1113 // Ignore if vfunc (handled below)
1114 if (!current_type_vfunc_map.contains (member.name)) {
1115 var m = parse_function ((IdlNodeFunction) member, true);
1116 if (m != null) {
1117 iface.add_method (m);
1120 } else if (member.type == IdlNodeTypeId.VFUNC) {
1121 var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name), true);
1122 if (m != null) {
1123 iface.add_method (m);
1125 } else if (member.type == IdlNodeTypeId.PROPERTY) {
1126 var prop = parse_property ((IdlNodeProperty) member);
1127 if (prop != null) {
1128 iface.add_property (prop);
1130 } else if (member.type == IdlNodeTypeId.SIGNAL) {
1131 var sig = parse_signal ((IdlNodeSignal) member);
1132 if (sig != null) {
1133 iface.add_signal (sig);
1138 handle_async_methods (iface);
1140 current_data_type = null;
1143 void handle_async_methods (ObjectTypeSymbol type_symbol) {
1144 foreach (Method m in type_symbol.get_methods ()) {
1145 if (m.coroutine) {
1146 var finish_method = type_symbol.scope.lookup (m.name.substring (0, m.name.length - "_async".length) + "_finish") as Method;
1147 if (finish_method != null) {
1148 m.return_type = finish_method.return_type.copy ();
1149 foreach (var param in finish_method.get_parameters ()) {
1150 if (param.direction == ParameterDirection.OUT) {
1151 var async_param = param.copy ();
1152 if (m.scope.lookup (param.name) != null) {
1153 // parameter name conflict
1154 async_param.name += "_out";
1156 m.add_parameter (async_param);
1159 foreach (DataType error_type in finish_method.get_error_types ()) {
1160 m.add_error_type (error_type.copy ());
1167 private DataType? parse_type (IdlNodeType type_node, out ParameterDirection direction = null) {
1168 ParameterDirection dir = ParameterDirection.IN;
1170 var type = new UnresolvedType ();
1171 if (type_node.tag == TypeTag.VOID) {
1172 if (type_node.is_pointer) {
1173 return new PointerType (new VoidType ());
1174 } else {
1175 return new VoidType ();
1177 } else if (type_node.tag == TypeTag.BOOLEAN) {
1178 type.unresolved_symbol = new UnresolvedSymbol (null, "bool");
1179 } else if (type_node.tag == TypeTag.INT8) {
1180 type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1181 } else if (type_node.tag == TypeTag.UINT8) {
1182 type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1183 } else if (type_node.tag == TypeTag.INT16) {
1184 type.unresolved_symbol = new UnresolvedSymbol (null, "int16");
1185 } else if (type_node.tag == TypeTag.UINT16) {
1186 type.unresolved_symbol = new UnresolvedSymbol (null, "uint16");
1187 } else if (type_node.tag == TypeTag.INT32) {
1188 type.unresolved_symbol = new UnresolvedSymbol (null, "int32");
1189 } else if (type_node.tag == TypeTag.UINT32) {
1190 type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
1191 } else if (type_node.tag == TypeTag.INT64) {
1192 type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1193 } else if (type_node.tag == TypeTag.UINT64) {
1194 type.unresolved_symbol = new UnresolvedSymbol (null, "uint64");
1195 } else if (type_node.tag == TypeTag.INT) {
1196 type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1197 } else if (type_node.tag == TypeTag.UINT) {
1198 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1199 } else if (type_node.tag == TypeTag.LONG) {
1200 type.unresolved_symbol = new UnresolvedSymbol (null, "long");
1201 } else if (type_node.tag == TypeTag.ULONG) {
1202 type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1203 } else if (type_node.tag == TypeTag.SSIZE) {
1204 type.unresolved_symbol = new UnresolvedSymbol (null, "ssize_t");
1205 } else if (type_node.tag == TypeTag.SIZE) {
1206 type.unresolved_symbol = new UnresolvedSymbol (null, "size_t");
1207 } else if (type_node.tag == TypeTag.FLOAT) {
1208 type.unresolved_symbol = new UnresolvedSymbol (null, "float");
1209 } else if (type_node.tag == TypeTag.DOUBLE) {
1210 type.unresolved_symbol = new UnresolvedSymbol (null, "double");
1211 } else if (type_node.tag == TypeTag.UTF8) {
1212 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1213 } else if (type_node.tag == TypeTag.FILENAME) {
1214 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1215 } else if (type_node.tag == TypeTag.ARRAY) {
1216 var element_type = parse_type (type_node.parameter_type1);
1217 type = element_type as UnresolvedType;
1218 if (type == null) {
1219 return element_type;
1221 return new ArrayType (element_type, 1, element_type.source_reference);
1222 } else if (type_node.tag == TypeTag.LIST) {
1223 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "List");
1224 } else if (type_node.tag == TypeTag.SLIST) {
1225 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "SList");
1226 } else if (type_node.tag == TypeTag.HASH) {
1227 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "HashTable");
1228 } else if (type_node.tag == TypeTag.ERROR) {
1229 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Error");
1230 } else if (type_node.is_interface) {
1231 var n = type_node.@interface;
1233 if (n == "") {
1234 return null;
1237 if (n.has_prefix ("const-")) {
1238 n = n.offset ("const-".len ());
1241 if (type_node.is_pointer &&
1242 (n == "gchar" || n == "char")) {
1243 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1244 if (type_node.unparsed.has_suffix ("**")) {
1245 dir = ParameterDirection.OUT;
1247 } else if (n == "gunichar") {
1248 type.unresolved_symbol = new UnresolvedSymbol (null, "unichar");
1249 } else if (n == "gchar") {
1250 type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1251 } else if (n == "guchar" || n == "guint8") {
1252 type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1253 if (type_node.is_pointer) {
1254 return new ArrayType (type, 1, type.source_reference);
1256 } else if (n == "gushort") {
1257 type.unresolved_symbol = new UnresolvedSymbol (null, "ushort");
1258 } else if (n == "gshort") {
1259 type.unresolved_symbol = new UnresolvedSymbol (null, "short");
1260 } else if (n == "gconstpointer" || n == "void") {
1261 return new PointerType (new VoidType ());
1262 } else if (n == "goffset" || n == "off_t") {
1263 type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1264 } else if (n == "value_array") {
1265 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "ValueArray");
1266 } else if (n == "time_t") {
1267 type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1268 } else if (n == "socklen_t") {
1269 type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
1270 } else if (n == "mode_t") {
1271 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1272 } else if (n == "gint" || n == "pid_t") {
1273 type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1274 } else if (n == "unsigned" || n == "unsigned-int") {
1275 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1276 } else if (n == "FILE") {
1277 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "FileStream");
1278 } else if (n == "struct") {
1279 return new PointerType (new VoidType ());
1280 } else if (n == "iconv_t") {
1281 return new PointerType (new VoidType ());
1282 } else if (n == "GType") {
1283 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Type");
1284 if (type_node.is_pointer) {
1285 return new ArrayType (type, 1, type.source_reference);
1287 } else if (n == "GStrv") {
1288 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1289 return new ArrayType (type, 1, type.source_reference);
1290 } else {
1291 var named_type = parse_type_string (n);
1292 type = named_type as UnresolvedType;
1293 if (type == null) {
1294 return named_type;
1296 if (is_simple_type (n)) {
1297 if (type_node.is_pointer) {
1298 dir = ParameterDirection.OUT;
1300 } else if (type_node.unparsed.has_suffix ("**")) {
1301 dir = ParameterDirection.OUT;
1304 } else {
1305 stdout.printf ("%d\n", type_node.tag);
1307 if (&direction != null) {
1308 direction = dir;
1310 return type;
1313 private bool is_simple_type (string type_name) {
1314 var st = cname_type_map[type_name] as Struct;
1315 if (st != null && st.is_simple_type ()) {
1316 return true;
1319 return false;
1322 private DataType parse_type_string (string n) {
1323 if (n == "va_list") {
1324 // unsupported
1325 return new PointerType (new VoidType ());
1328 var type = new UnresolvedType ();
1330 var dt = cname_type_map[n];
1331 if (dt != null) {
1332 UnresolvedSymbol parent_symbol = null;
1333 if (dt.parent_symbol.name != null) {
1334 parent_symbol = new UnresolvedSymbol (null, dt.parent_symbol.name);
1336 type.unresolved_symbol = new UnresolvedSymbol (parent_symbol, dt.name);
1337 return type;
1340 var type_attributes = get_attributes (n);
1342 string ns_name = null;
1344 if (null != type_attributes) {
1345 foreach (string attr in type_attributes) {
1346 var nv = attr.split ("=", 2);
1348 if (nv[0] == "cprefix") {
1349 type.unresolved_symbol = new UnresolvedSymbol (null, n.offset (eval (nv[1]).len ()));
1350 } else if (nv[0] == "name") {
1351 type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1352 } else if (nv[0] == "namespace") {
1353 ns_name = eval (nv[1]);
1354 } else if (nv[0] == "rename_to") {
1355 type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1360 if (type.unresolved_symbol != null) {
1361 if (type.unresolved_symbol.name == "pointer") {
1362 return new PointerType (new VoidType ());
1364 if (ns_name != null) {
1365 type.unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
1367 return type;
1370 if (n.has_prefix (current_namespace.name)) {
1371 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, current_namespace.name), n.offset (current_namespace.name.len ()));
1372 } else if (n.has_prefix ("G")) {
1373 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), n.offset (1));
1374 } else {
1375 var name_parts = n.split (".", 2);
1376 if (name_parts[1] == null) {
1377 type.unresolved_symbol = new UnresolvedSymbol (null, name_parts[0]);
1378 } else {
1379 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, name_parts[0]), name_parts[1]);
1383 return type;
1386 private DataType? parse_param (IdlNodeParam param, out ParameterDirection direction = null) {
1387 var type = parse_type (param.type, out direction);
1389 // disable for now as null_ok not yet correctly set
1390 // type.non_null = !param.null_ok;
1392 return type;
1395 private Method? create_method (string name, string symbol, IdlNodeParam? res, GLib.List<IdlNodeParam>? parameters, bool is_constructor, bool is_interface) {
1396 DataType return_type = null;
1397 if (res != null) {
1398 return_type = parse_param (res);
1401 Method m;
1402 if (!is_interface && (is_constructor || name.has_prefix ("new"))) {
1403 m = new CreationMethod (null, name, current_source_reference);
1404 m.has_construct_function = false;
1405 if (m.name == "new") {
1406 m.name = null;
1407 } else if (m.name.has_prefix ("new_")) {
1408 m.name = m.name.offset ("new_".len ());
1410 // For classes, check whether a creation method return type equals to the
1411 // type of the class created. If the types do not match (e.g. in most
1412 // gtk widgets) add an attribute to the creation method indicating the used
1413 // return type.
1414 if (current_data_type is Class && res != null) {
1415 if ("%s*".printf (current_data_type.get_cname()) != res.type.unparsed) {
1416 ((CreationMethod)m).custom_return_type_cname = res.type.unparsed;
1419 } else {
1420 m = new Method (name, return_type, current_source_reference);
1422 m.access = SymbolAccessibility.PUBLIC;
1424 if (current_type_symbol_set != null) {
1425 current_type_symbol_set.add (name);
1428 if (current_data_type != null) {
1429 var sig_attributes = get_attributes ("%s::%s".printf (current_data_type.get_cname (), name));
1430 if (sig_attributes != null) {
1431 foreach (string attr in sig_attributes) {
1432 var nv = attr.split ("=", 2);
1433 if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
1434 return null;
1440 bool add_ellipsis = false;
1441 bool suppress_throws = false;
1443 var attributes = get_attributes (symbol);
1444 if (attributes != null) {
1445 foreach (string attr in attributes) {
1446 var nv = attr.split ("=", 2);
1447 if (nv[0] == "name") {
1448 m.set_cname (m.name);
1449 m.name = eval (nv[1]);
1450 } else if (nv[0] == "hidden") {
1451 if (eval (nv[1]) == "1") {
1452 return null;
1454 } else if (nv[0] == "ellipsis") {
1455 if (eval (nv[1]) == "1") {
1456 add_ellipsis = true;
1458 } else if (nv[0] == "printf_format") {
1459 if (eval (nv[1]) == "1") {
1460 m.printf_format = true;
1462 } else if (nv[0] == "transfer_ownership") {
1463 if (eval (nv[1]) == "1") {
1464 return_type.value_owned = true;
1466 } else if (nv[0] == "nullable") {
1467 if (eval (nv[1]) == "1") {
1468 return_type.nullable = true;
1470 } else if (nv[0] == "sentinel") {
1471 m.sentinel = eval (nv[1]);
1472 } else if (nv[0] == "is_array") {
1473 if (eval (nv[1]) == "1") {
1474 return_type = new ArrayType (return_type, 1, return_type.source_reference);
1475 m.return_type = return_type;
1477 } else if (nv[0] == "throws") {
1478 if (eval (nv[1]) == "0") {
1479 suppress_throws = true;
1481 } else if (nv[0] == "no_array_length") {
1482 if (eval (nv[1]) == "1") {
1483 m.no_array_length = true;
1485 } else if (nv[0] == "array_null_terminated") {
1486 if (eval (nv[1]) == "1") {
1487 m.no_array_length = true;
1488 m.array_null_terminated = true;
1490 } else if (nv[0] == "type_name") {
1491 var sym = new UnresolvedSymbol (null, eval (nv[1]));
1492 if (return_type is UnresolvedType) {
1493 ((UnresolvedType) return_type).unresolved_symbol = sym;
1494 } else {
1495 // Overwrite old return_type, so "type_name" must be before any
1496 // other return type modifying metadata
1497 m.return_type = return_type = new UnresolvedType.from_symbol (sym, return_type.source_reference);
1499 } else if (nv[0] == "type_arguments") {
1500 var type_args = eval (nv[1]).split (",");
1501 foreach (string type_arg in type_args) {
1502 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1503 arg_type.value_owned = true;
1504 return_type.add_type_argument (arg_type);
1506 } else if (nv[0] == "cheader_filename") {
1507 m.add_cheader_filename (eval (nv[1]));
1508 } else if (nv[0] == "abstract") {
1509 if (eval (nv[1]) == "1") {
1510 m.is_abstract = true;
1512 } else if (nv[0] == "virtual") {
1513 if (eval (nv[1]) == "1") {
1514 m.is_virtual = true;
1516 } else if (nv[0] == "vfunc_name") {
1517 m.vfunc_name = eval (nv[1]);
1522 m.set_cname (symbol);
1524 bool first = true;
1525 FormalParameter last_param = null;
1526 DataType last_param_type = null;
1527 foreach (weak IdlNodeParam param in parameters) {
1528 weak IdlNode param_node = (IdlNode) param;
1530 if (first) {
1531 first = false;
1532 if (!(m is CreationMethod) &&
1533 current_data_type != null &&
1534 param.type.is_interface &&
1535 (param_node.name == "self" ||
1536 param.type.@interface.has_suffix (current_data_type.get_cname ()))) {
1537 // instance method
1538 continue;
1539 } else if (!(m is CreationMethod) &&
1540 current_data_type != null &&
1541 param.type.is_interface &&
1542 (param_node.name == "klass" ||
1543 param.type.@interface.has_suffix ("%sClass".printf(current_data_type.get_cname ())))) {
1544 // class method
1545 m.binding = MemberBinding.CLASS;
1546 if (m.name.has_prefix ("class_")) {
1547 m.name = m.name.substring ("class_".len (), m.name.len () - "class_".len ());
1549 continue;
1550 } else {
1551 // static method
1552 m.binding = MemberBinding.STATIC;
1556 if (param.type.@interface == "GAsyncReadyCallback" && symbol.has_suffix ("_async")) {
1557 // async method
1558 m.coroutine = true;
1559 continue;
1562 if (suppress_throws == false && param_is_exception (param)) {
1563 m.add_error_type (parse_type (param.type));
1564 continue;
1567 string param_name = param_node.name;
1568 if (param_name == "result") {
1569 // avoid conflict with generated result variable
1570 param_name = "_result";
1571 } else if (param_name == "string") {
1572 // avoid conflict with string type
1573 param_name = "str";
1575 ParameterDirection direction;
1576 var param_type = parse_param (param, out direction);
1577 var p = new FormalParameter (param_name, param_type);
1578 p.direction = direction;
1580 bool hide_param = false;
1581 bool show_param = false;
1582 bool set_array_length_pos = false;
1583 double array_length_pos = 0;
1584 bool set_delegate_target_pos = false;
1585 double delegate_target_pos = 0;
1586 bool array_requested = false;
1587 attributes = get_attributes ("%s.%s".printf (symbol, param_node.name));
1588 if (attributes != null) {
1589 foreach (string attr in attributes) {
1590 var nv = attr.split ("=", 2);
1591 if (nv[0] == "is_array") {
1592 if (eval (nv[1]) == "1") {
1593 param_type = new ArrayType (param_type, 1, param_type.source_reference);
1594 p.parameter_type = param_type;
1595 p.direction = ParameterDirection.IN;
1596 array_requested = true;
1598 } else if (nv[0] == "is_out") {
1599 if (eval (nv[1]) == "1") {
1600 p.direction = ParameterDirection.OUT;
1601 if (!array_requested && param_type is ArrayType) {
1602 var array_type = (ArrayType) param_type;
1603 param_type = array_type.element_type;
1604 p.parameter_type = param_type;
1607 } else if (nv[0] == "is_ref") {
1608 if (eval (nv[1]) == "1") {
1609 p.direction = ParameterDirection.REF;
1610 if (!array_requested && param_type is ArrayType) {
1611 var array_type = (ArrayType) param_type;
1612 param_type = array_type.element_type;
1613 p.parameter_type = param_type;
1616 } else if (nv[0] == "nullable") {
1617 if (eval (nv[1]) == "1") {
1618 param_type.nullable = true;
1620 } else if (nv[0] == "transfer_ownership") {
1621 if (eval (nv[1]) == "1") {
1622 param_type.value_owned = true;
1624 } else if (nv[0] == "takes_ownership") {
1625 if (eval (nv[1]) == "1") {
1626 param_type.value_owned = true;
1628 } else if (nv[0] == "value_owned") {
1629 if (eval (nv[1]) == "0") {
1630 param_type.value_owned = false;
1631 } else if (eval (nv[1]) == "1") {
1632 param_type.value_owned = true;
1634 } else if (nv[0] == "hidden") {
1635 if (eval (nv[1]) == "1") {
1636 hide_param = true;
1637 } else if (eval (nv[1]) == "0") {
1638 show_param = true;
1640 } else if (nv[0] == "no_array_length") {
1641 if (eval (nv[1]) == "1") {
1642 p.no_array_length = true;
1644 } else if (nv[0] == "array_null_terminated") {
1645 if (eval (nv[1]) == "1") {
1646 p.no_array_length = true;
1647 p.array_null_terminated = true;
1649 } else if (nv[0] == "array_length_pos") {
1650 set_array_length_pos = true;
1651 array_length_pos = eval (nv[1]).to_double ();
1652 } else if (nv[0] == "delegate_target_pos") {
1653 set_delegate_target_pos = true;
1654 delegate_target_pos = eval (nv[1]).to_double ();
1655 } else if (nv[0] == "type_name") {
1656 ((UnresolvedType) param_type).unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1657 } else if (nv[0] == "ctype") {
1658 p.ctype = eval (nv[1]);
1659 } else if (nv[0] == "type_arguments") {
1660 var type_args = eval (nv[1]).split (",");
1661 foreach (string type_arg in type_args) {
1662 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1663 arg_type.value_owned = true;
1664 param_type.add_type_argument (arg_type);
1670 if (last_param != null && p.name == "n_" + last_param.name) {
1671 if (!(last_param_type is ArrayType)) {
1672 // last_param is array, p is array length
1673 last_param_type = new ArrayType (last_param_type, 1, last_param_type.source_reference);
1674 last_param.parameter_type = last_param_type;
1675 last_param.direction = ParameterDirection.IN;
1678 // hide array length param
1679 hide_param = true;
1680 } else if (last_param != null && p.name == "user_data") {
1681 // last_param is delegate
1683 // hide deleate target param
1684 hide_param = true;
1687 if (show_param || !hide_param) {
1688 m.add_parameter (p);
1689 if (set_array_length_pos) {
1690 p.carray_length_parameter_position = array_length_pos;
1692 if (set_delegate_target_pos) {
1693 p.cdelegate_target_parameter_position = delegate_target_pos;
1697 last_param = p;
1698 last_param_type = param_type;
1701 if (first) {
1702 // no parameters => static method
1703 m.binding = MemberBinding.STATIC;
1706 if (last_param != null && last_param.name.has_prefix ("first_")) {
1707 last_param.ellipsis = true;
1708 } else if (add_ellipsis) {
1709 m.add_parameter (new FormalParameter.with_ellipsis ());
1712 return m;
1715 private bool param_is_exception (IdlNodeParam param) {
1716 if (!param.type.is_error) {
1717 return false;
1719 var s = param.type.unparsed.chomp ();
1720 if (s.has_suffix ("**")) {
1721 return true;
1723 return false;
1726 private Method? parse_function (IdlNodeFunction f, bool is_interface = false) {
1727 weak IdlNode node = (IdlNode) f;
1729 if (f.deprecated) {
1730 return null;
1733 return create_method (node.name, f.symbol, f.result, f.parameters, f.is_constructor, is_interface);
1736 private Method parse_virtual (IdlNodeVFunc v, IdlNodeFunction? func, bool is_interface = false) {
1737 weak IdlNode node = (IdlNode) v;
1738 string symbol = "%s%s".printf (current_data_type.get_lower_case_cprefix(), node.name);
1740 if (func != null) {
1741 symbol = func.symbol;
1744 Method m = create_method (node.name, symbol, v.result, func != null ? func.parameters : v.parameters, false, is_interface);
1745 if (m != null) {
1746 m.binding = MemberBinding.INSTANCE;
1747 m.is_virtual = !(m.is_abstract || is_interface);
1748 m.is_abstract = m.is_abstract || is_interface;
1750 var attributes = get_attributes (symbol);
1751 if (attributes != null) {
1752 foreach (string attr in attributes) {
1753 var nv = attr.split ("=", 2);
1754 if (nv[0] == "virtual") {
1755 if (eval (nv[1]) == "0") {
1756 m.is_virtual = false;
1757 m.is_abstract = false;
1763 if (func == null) {
1764 m.attributes.append (new Attribute ("NoWrapper", null));
1768 return m;
1771 private string fix_prop_name (string name) {
1772 var str = new StringBuilder ();
1774 string i = name;
1776 while (i.len () > 0) {
1777 unichar c = i.get_char ();
1778 if (c == '-') {
1779 str.append_c ('_');
1780 } else {
1781 str.append_unichar (c);
1784 i = i.next_char ();
1787 return str.str;
1790 private Property? parse_property (IdlNodeProperty prop_node) {
1791 weak IdlNode node = (IdlNode) prop_node;
1793 if (prop_node.deprecated) {
1794 return null;
1797 if (!prop_node.readable && !prop_node.writable) {
1798 // buggy GIDL definition
1799 prop_node.readable = true;
1800 prop_node.writable = true;
1803 var prop = new Property (fix_prop_name (node.name), parse_type (prop_node.type), null, null, current_source_reference);
1804 prop.access = SymbolAccessibility.PUBLIC;
1805 prop.interface_only = true;
1807 if (prop_node.type.is_interface && prop_node.type.interface == "GStrv") {
1808 prop.no_array_length = true;
1809 prop.array_null_terminated = true;
1812 if (prop_node.readable) {
1813 prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, null);
1815 if (prop_node.writable) {
1816 prop.set_accessor = new PropertyAccessor (false, false, false, prop.property_type.copy (), null, null);
1817 if (prop_node.construct_only) {
1818 prop.set_accessor.construction = true;
1819 } else {
1820 prop.set_accessor.writable = true;
1821 prop.set_accessor.construction = prop_node.@construct;
1825 var attributes = get_attributes ("%s:%s".printf (current_data_type.get_cname (), node.name));
1826 if (attributes != null) {
1827 foreach (string attr in attributes) {
1828 var nv = attr.split ("=", 2);
1829 if (nv[0] == "hidden") {
1830 if (eval (nv[1]) == "1") {
1831 return null;
1833 } else if (nv[0] == "type_arguments") {
1834 var type_args = eval (nv[1]).split (",");
1835 foreach (string type_arg in type_args) {
1836 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1837 arg_type.value_owned = true;
1838 prop.property_type.add_type_argument (arg_type);
1840 } else if (nv[0] == "accessor_method") {
1841 if (eval (nv[1]) == "0") {
1842 prop.no_accessor_method = true;
1844 } else if (nv[0] == "owned_get") {
1845 if (eval (nv[1]) == "1") {
1846 prop.get_accessor.value_type.value_owned = true;
1852 if (current_type_symbol_set != null) {
1853 current_type_symbol_set.add (prop.name);
1856 return prop;
1859 private Constant? parse_constant (IdlNodeConstant const_node) {
1860 weak IdlNode node = (IdlNode) const_node;
1862 var type = parse_type (const_node.type);
1863 if (type == null) {
1864 return null;
1867 var c = new Constant (node.name, type, null, current_source_reference);
1868 c.external = true;
1870 string[] attributes = get_attributes (node.name);
1871 if (attributes != null) {
1872 foreach (string attr in attributes) {
1873 var nv = attr.split ("=", 2);
1874 if (nv[0] == "cheader_filename") {
1875 c.add_cheader_filename (eval (nv[1]));
1876 } else if (nv[0] == "hidden") {
1877 if (eval (nv[1]) == "1") {
1878 return null;
1884 c.access = SymbolAccessibility.PUBLIC;
1886 return c;
1889 private Field? parse_field (IdlNodeField field_node) {
1890 weak IdlNode node = (IdlNode) field_node;
1891 bool unhidden = false;
1893 var type = parse_type (field_node.type);
1894 if (type == null) {
1895 return null;
1898 string cheader_filename = null;
1899 string ctype = null;
1900 bool array_null_terminated = false;
1902 var attributes = get_attributes ("%s.%s".printf (current_data_type.get_cname (), node.name));
1903 if (attributes != null) {
1904 foreach (string attr in attributes) {
1905 var nv = attr.split ("=", 2);
1906 if (nv[0] == "hidden") {
1907 if (eval (nv[1]) == "1") {
1908 return null;
1909 } else {
1910 unhidden = true;
1912 } else if (nv[0] == "is_array") {
1913 if (eval (nv[1]) == "1") {
1914 type = new ArrayType (type, 1, type.source_reference);
1916 } else if (nv[0] == "weak") {
1917 if (eval (nv[1]) == "0") {
1918 type.value_owned = true;
1920 } else if (nv[0] == "type_name") {
1921 ((UnresolvedType) type).unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1922 } else if (nv[0] == "type_arguments") {
1923 var type_args = eval (nv[1]).split (",");
1924 foreach (string type_arg in type_args) {
1925 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1926 arg_type.value_owned = true;
1927 type.add_type_argument (arg_type);
1929 } else if (nv[0] == "cheader_filename") {
1930 cheader_filename = eval (nv[1]);
1931 } else if (nv[0] == "ctype") {
1932 ctype = eval (nv[1]);
1933 } else if (nv[0] == "array_null_terminated") {
1934 if (eval (nv[1]) == "1") {
1935 array_null_terminated = true;
1941 if (node.name.has_prefix("_") && !unhidden) {
1942 return null;
1945 if (current_type_symbol_set != null) {
1946 current_type_symbol_set.add (node.name);
1949 string field_name = node.name;
1950 if (field_name == "string") {
1951 // avoid conflict with string type
1952 field_name = "str";
1955 var field = new Field (field_name, type, null, current_source_reference);
1956 field.access = SymbolAccessibility.PUBLIC;
1958 if (field_name != node.name) {
1959 field.set_cname (node.name);
1962 if (ctype != null) {
1963 field.set_ctype (ctype);
1966 if (cheader_filename != null) {
1967 field.add_cheader_filename (cheader_filename);
1970 field.no_array_length = true;
1971 if (array_null_terminated) {
1972 field.array_null_terminated = true;
1975 return field;
1978 private string[]? get_attributes (string codenode) {
1979 var attributes = codenode_attributes_map.get (codenode);
1981 if (attributes == null) {
1982 var dot_required = (null != codenode.chr (-1, '.'));
1983 var colon_required = (null != codenode.chr (-1, ':'));
1985 var pattern_specs = codenode_attributes_patterns.get_keys ();
1986 foreach (PatternSpec* pattern in pattern_specs) {
1987 var pspec = codenode_attributes_patterns[pattern];
1989 if ((dot_required && null == pspec.chr (-1, '.')) ||
1990 (colon_required && null == pspec.chr (-1, ':'))) {
1991 continue;
1994 if (pattern->match_string (codenode)) {
1995 return get_attributes (pspec);
2000 if (attributes == null) {
2001 return null;
2004 return attributes.split (" ");
2007 private string eval (string s) {
2008 return ((s.size () >= 2) && s.has_prefix ("\"") && s.has_suffix ("\"")) ? s.offset (1).ndup (s.size () - 2) : s;
2011 private Signal? parse_signal (IdlNodeSignal sig_node) {
2012 weak IdlNode node = (IdlNode) sig_node;
2014 if (sig_node.deprecated || sig_node.result == null) {
2015 return null;
2018 var sig = new Signal (fix_prop_name (node.name), parse_param (sig_node.result), current_source_reference);
2019 sig.access = SymbolAccessibility.PUBLIC;
2021 var attributes = get_attributes ("%s::%s".printf (current_data_type.get_cname (), sig.name));
2022 if (attributes != null) {
2023 foreach (string attr in attributes) {
2024 var nv = attr.split ("=", 2);
2025 if (nv[0] == "name") {
2026 sig.set_cname (sig.name);
2027 sig.name = eval (nv[1]);
2028 } else if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
2029 sig.has_emitter = true;
2030 } else if (nv[0] == "hidden") {
2031 if (eval (nv[1]) == "1") {
2032 return null;
2038 sig.is_virtual = true;
2040 bool first = true;
2042 foreach (weak IdlNodeParam param in sig_node.parameters) {
2043 if (first) {
2044 // ignore implicit first signal parameter (sender)
2045 first = false;
2046 continue;
2049 weak IdlNode param_node = (IdlNode) param;
2051 ParameterDirection direction;
2052 var param_type = parse_param (param, out direction);
2053 var p = new FormalParameter (param_node.name, param_type);
2054 p.direction = direction;
2055 sig.add_parameter (p);
2057 attributes = get_attributes ("%s::%s.%s".printf (current_data_type.get_cname (), sig.name, param_node.name));
2058 if (attributes != null) {
2059 string ns_name = null;
2060 foreach (string attr in attributes) {
2061 var nv = attr.split ("=", 2);
2062 if (nv[0] == "is_array") {
2063 if (eval (nv[1]) == "1") {
2064 param_type = new ArrayType (param_type, 1, param_type.source_reference);
2065 p.parameter_type = param_type;
2066 p.direction = ParameterDirection.IN;
2068 } else if (nv[0] == "is_out") {
2069 if (eval (nv[1]) == "1") {
2070 p.direction = ParameterDirection.OUT;
2072 } else if (nv[0] == "is_ref") {
2073 if (eval (nv[1]) == "1") {
2074 p.direction = ParameterDirection.REF;
2076 } else if (nv[0] == "nullable") {
2077 if (eval (nv[1]) == "1") {
2078 param_type.nullable = true;
2080 } else if (nv[0] == "transfer_ownership") {
2081 if (eval (nv[1]) == "1") {
2082 param_type.value_owned = true;
2084 } else if (nv[0] == "type_name") {
2085 ((UnresolvedType) param_type).unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
2086 } else if (nv[0] == "namespace_name") {
2087 ns_name = eval (nv[1]);
2090 if (ns_name != null) {
2091 ((UnresolvedType) param_type).unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
2096 return sig;
2100 // vim:sw=8 noet