Improve output for owned property getters
[vala-lang.git] / vapigen / valagidlparser.vala
blob160bc9fa3588e3846f7a745c3698db4fdd769878
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 cb = new Delegate (node.name, parse_param (f_node.result), current_source_reference);
296 cb.access = SymbolAccessibility.PUBLIC;
298 bool check_has_target = true;
300 var attributes = get_attributes (node.name);
301 if (attributes != null) {
302 foreach (string attr in attributes) {
303 var nv = attr.split ("=", 2);
304 if (nv[0] == "hidden") {
305 if (eval (nv[1]) == "1") {
306 return null;
308 } else if (nv[0] == "cheader_filename") {
309 cb.add_cheader_filename (eval (nv[1]));
310 } else if (nv[0] == "has_target") {
311 if (eval (nv[1]) == "0") {
312 check_has_target = false;
313 } else if (eval (nv[1]) == "1") {
314 cb.has_target = true;
320 uint remaining_params = f_node.parameters.length ();
321 foreach (weak IdlNodeParam param in f_node.parameters) {
322 weak IdlNode param_node = (IdlNode) param;
324 if (check_has_target && remaining_params == 1 && (param_node.name == "user_data" || param_node.name == "data")) {
325 // hide user_data parameter for instance delegates
326 cb.has_target = true;
327 } else {
328 string param_name = param_node.name;
329 if (param_name == "string") {
330 // avoid conflict with string type
331 param_name = "str";
332 } else if (param_name == "self") {
333 // avoid conflict with delegate target
334 param_name = "_self";
337 ParameterDirection direction;
338 var p = new FormalParameter (param_name, parse_param (param, out direction));
339 p.direction = direction;
341 bool hide_param = false;
342 bool show_param = false;
343 attributes = get_attributes ("%s.%s".printf (node.name, param_node.name));
344 if (attributes != null) {
345 foreach (string attr in attributes) {
346 var nv = attr.split ("=", 2);
347 if (nv[0] == "hidden") {
348 if (eval (nv[1]) == "1") {
349 hide_param = true;
350 } else if (eval (nv[1]) == "0") {
351 show_param = true;
357 if (show_param || !hide_param) {
358 cb.add_parameter (p);
362 remaining_params--;
365 return cb;
368 private bool is_reference_type (string cname) {
369 var st_attributes = get_attributes (cname);
370 if (st_attributes != null) {
371 foreach (string attr in st_attributes) {
372 var nv = attr.split ("=", 2);
373 if (nv[0] == "is_value_type" && eval (nv[1]) == "1") {
374 return false;
378 return true;
381 private void parse_struct (IdlNodeStruct st_node, Namespace ns, IdlModule module) {
382 weak IdlNode node = (IdlNode) st_node;
384 if (st_node.deprecated) {
385 return;
388 string name = fix_type_name (node.name, ns);
390 if (!is_reference_type (node.name)) {
391 var st = ns.scope.lookup (name) as Struct;
392 if (st == null) {
393 st = new Struct (name, current_source_reference);
394 st.access = SymbolAccessibility.PUBLIC;
396 var st_attributes = get_attributes (node.name);
397 if (st_attributes != null) {
398 foreach (string attr in st_attributes) {
399 var nv = attr.split ("=", 2);
400 if (nv[0] == "cheader_filename") {
401 st.add_cheader_filename (eval (nv[1]));
402 } else if (nv[0] == "hidden") {
403 if (eval (nv[1]) == "1") {
404 return;
406 } else if (nv[0] == "simple_type") {
407 if (eval (nv[1]) == "1") {
408 st.set_simple_type (true);
414 ns.add_struct (st);
415 current_source_file.add_node (st);
418 current_data_type = st;
420 foreach (weak IdlNode member in st_node.members) {
421 if (member.type == IdlNodeTypeId.FUNCTION) {
422 var m = parse_function ((IdlNodeFunction) member);
423 if (m != null) {
424 st.add_method (m);
426 } else if (member.type == IdlNodeTypeId.FIELD) {
427 var f = parse_field ((IdlNodeField) member);
428 if (f != null) {
429 st.add_field (f);
434 current_data_type = null;
435 } else {
436 var cl = ns.scope.lookup (name) as Class;
437 if (cl == null) {
438 string base_class = null;
440 cl = new Class (name, current_source_reference);
441 cl.access = SymbolAccessibility.PUBLIC;
442 cl.is_compact = true;
444 var cl_attributes = get_attributes (node.name);
445 if (cl_attributes != null) {
446 foreach (string attr in cl_attributes) {
447 var nv = attr.split ("=", 2);
448 if (nv[0] == "cheader_filename") {
449 cl.add_cheader_filename (eval (nv[1]));
450 } else if (nv[0] == "base_class") {
451 base_class = eval (nv[1]);
452 } else if (nv[0] == "hidden") {
453 if (eval (nv[1]) == "1") {
454 return;
456 } else if (nv[0] == "is_immutable") {
457 if (eval (nv[1]) == "1") {
458 cl.is_immutable = true;
460 } else if (nv[0] == "is_fundamental") {
461 if (eval (nv[1]) == "1") {
462 cl.is_compact = false;
464 } else if (nv[0] == "abstract" && base_class != null) {
465 if (eval (nv[1]) == "1") {
466 cl.is_abstract = true;
472 ns.add_class (cl);
473 current_source_file.add_node (cl);
475 if (base_class != null) {
476 var parent = parse_type_string (base_class);
477 cl.add_base_type (parent);
481 current_data_type = cl;
483 string ref_function = null;
484 string unref_function = null;
485 string copy_function = null;
486 string free_function = null;
488 foreach (weak IdlNode member in st_node.members) {
489 if (member.type == IdlNodeTypeId.FUNCTION) {
490 if (member.name == "ref") {
491 ref_function = ((IdlNodeFunction) member).symbol;
492 } else if (member.name == "unref") {
493 unref_function = ((IdlNodeFunction) member).symbol;
494 } else if (member.name == "free" || member.name == "destroy") {
495 free_function = ((IdlNodeFunction) member).symbol;
496 } else {
497 if (member.name == "copy") {
498 copy_function = ((IdlNodeFunction) member).symbol;
500 var m = parse_function ((IdlNodeFunction) member);
501 if (m != null) {
502 cl.add_method (m);
505 } else if (member.type == IdlNodeTypeId.FIELD) {
506 var f = parse_field ((IdlNodeField) member);
507 if (f != null) {
508 cl.add_field (f);
513 if (ref_function != null) {
514 cl.set_ref_function (ref_function);
516 if (copy_function != null) {
517 cl.set_dup_function (copy_function);
519 if (unref_function != null) {
520 cl.set_unref_function (unref_function);
521 } else if (free_function != null) {
522 cl.set_free_function (free_function);
525 current_data_type = null;
529 private void parse_union (IdlNodeUnion un_node, Namespace ns, IdlModule module) {
530 weak IdlNode node = (IdlNode) un_node;
532 if (un_node.deprecated) {
533 return;
536 string name = fix_type_name (node.name, ns);
538 if (!is_reference_type (node.name)) {
539 var st = ns.scope.lookup (name) as Struct;
540 if (st == null) {
541 st = new Struct (name, current_source_reference);
542 st.access = SymbolAccessibility.PUBLIC;
544 var st_attributes = get_attributes (node.name);
545 if (st_attributes != null) {
546 foreach (string attr in st_attributes) {
547 var nv = attr.split ("=", 2);
548 if (nv[0] == "cheader_filename") {
549 st.add_cheader_filename (eval (nv[1]));
550 } else if (nv[0] == "hidden") {
551 if (eval (nv[1]) == "1") {
552 return;
558 ns.add_struct (st);
559 current_source_file.add_node (st);
562 current_data_type = st;
564 foreach (weak IdlNode member in un_node.members) {
565 if (member.type == IdlNodeTypeId.FUNCTION) {
566 var m = parse_function ((IdlNodeFunction) member);
567 if (m != null) {
568 st.add_method (m);
570 } else if (member.type == IdlNodeTypeId.FIELD) {
571 var f = parse_field ((IdlNodeField) member);
572 if (f != null) {
573 st.add_field (f);
578 current_data_type = null;
579 } else {
580 var cl = ns.scope.lookup (name) as Class;
581 if (cl == null) {
582 cl = new Class (name, current_source_reference);
583 cl.access = SymbolAccessibility.PUBLIC;
584 cl.is_compact = true;
586 var cl_attributes = get_attributes (node.name);
587 if (cl_attributes != null) {
588 foreach (string attr in cl_attributes) {
589 var nv = attr.split ("=", 2);
590 if (nv[0] == "cheader_filename") {
591 cl.add_cheader_filename (eval (nv[1]));
592 } else if (nv[0] == "hidden") {
593 if (eval (nv[1]) == "1") {
594 return;
600 ns.add_class (cl);
601 current_source_file.add_node (cl);
604 current_data_type = cl;
606 string ref_function = null;
607 string unref_function = null;
608 string copy_function = null;
609 string free_function = null;
611 foreach (weak IdlNode member in un_node.members) {
612 if (member.type == IdlNodeTypeId.FUNCTION) {
613 if (member.name == "ref") {
614 ref_function = ((IdlNodeFunction) member).symbol;
615 } else if (member.name == "unref") {
616 unref_function = ((IdlNodeFunction) member).symbol;
617 } else if (member.name == "free" || member.name == "destroy") {
618 free_function = ((IdlNodeFunction) member).symbol;
619 } else {
620 if (member.name == "copy") {
621 copy_function = ((IdlNodeFunction) member).symbol;
623 var m = parse_function ((IdlNodeFunction) member);
624 if (m != null) {
625 cl.add_method (m);
628 } else if (member.type == IdlNodeTypeId.FIELD) {
629 var f = parse_field ((IdlNodeField) member);
630 if (f != null) {
631 cl.add_field (f);
636 if (ref_function != null) {
637 cl.set_ref_function (ref_function);
639 if (copy_function != null) {
640 cl.set_dup_function (copy_function);
642 if (unref_function != null) {
643 cl.set_unref_function (unref_function);
644 } else if (free_function != null) {
645 cl.set_free_function (free_function);
648 current_data_type = null;
652 private void parse_boxed (IdlNodeBoxed boxed_node, Namespace ns, IdlModule module) {
653 weak IdlNode node = (IdlNode) boxed_node;
655 string name = fix_type_name (node.name, ns);
657 var node_attributes = get_attributes (node.name);
658 if (node_attributes != null) {
659 foreach (string attr in node_attributes) {
660 var nv = attr.split ("=", 2);
661 if (nv[0] == "hidden") {
662 return;
667 if (!is_reference_type (node.name)) {
668 var st = ns.scope.lookup (name) as Struct;
669 if (st == null) {
670 st = new Struct (name, current_source_reference);
671 st.access = SymbolAccessibility.PUBLIC;
673 var st_attributes = get_attributes (node.name);
674 if (st_attributes != null) {
675 foreach (string attr in st_attributes) {
676 var nv = attr.split ("=", 2);
677 if (nv[0] == "cheader_filename") {
678 st.add_cheader_filename (eval (nv[1]));
683 ns.add_struct (st);
684 st.set_type_id (st.get_upper_case_cname ("TYPE_"));
685 current_source_file.add_node (st);
688 current_data_type = st;
690 foreach (weak IdlNode member in boxed_node.members) {
691 if (member.type == IdlNodeTypeId.FUNCTION) {
692 var m = parse_function ((IdlNodeFunction) member);
693 if (m != null) {
694 st.add_method (m);
696 } else if (member.type == IdlNodeTypeId.FIELD) {
697 var f = parse_field ((IdlNodeField) member);
698 if (f != null) {
699 st.add_field (f);
704 current_data_type = null;
705 } else {
706 var cl = ns.scope.lookup (name) as Class;
707 if (cl == null) {
708 cl = new Class (name, current_source_reference);
709 cl.access = SymbolAccessibility.PUBLIC;
710 cl.is_compact = true;
712 var cl_attributes = get_attributes (node.name);
713 if (cl_attributes != null) {
714 foreach (string attr in cl_attributes) {
715 var nv = attr.split ("=", 2);
716 if (nv[0] == "cheader_filename") {
717 cl.add_cheader_filename (eval (nv[1]));
718 } else if (nv[0] == "is_immutable") {
719 if (eval (nv[1]) == "1") {
720 cl.is_immutable = true;
726 ns.add_class (cl);
727 cl.set_type_id (cl.get_upper_case_cname ("TYPE_"));
728 current_source_file.add_node (cl);
731 current_data_type = cl;
733 string ref_function = null;
734 string unref_function = null;
735 string copy_function = null;
736 string free_function = null;
738 foreach (weak IdlNode member in boxed_node.members) {
739 if (member.type == IdlNodeTypeId.FUNCTION) {
740 if (member.name == "ref") {
741 ref_function = ((IdlNodeFunction) member).symbol;
742 } else if (member.name == "unref") {
743 unref_function = ((IdlNodeFunction) member).symbol;
744 } else if (member.name == "free" || member.name == "destroy") {
745 free_function = ((IdlNodeFunction) member).symbol;
746 } else {
747 if (member.name == "copy") {
748 copy_function = ((IdlNodeFunction) member).symbol;
750 var m = parse_function ((IdlNodeFunction) member);
751 if (m != null) {
752 cl.add_method (m);
755 } else if (member.type == IdlNodeTypeId.FIELD) {
756 var f = parse_field ((IdlNodeField) member);
757 if (f != null) {
758 cl.add_field (f);
763 if (ref_function != null) {
764 cl.set_ref_function (ref_function);
766 if (copy_function != null) {
767 cl.set_dup_function (copy_function);
769 if (unref_function != null) {
770 cl.set_unref_function (unref_function);
771 } else if (free_function != null) {
772 cl.set_free_function (free_function);
775 current_data_type = null;
779 private TypeSymbol? parse_enum (IdlNodeEnum en_node) {
780 weak IdlNode node = (IdlNode) en_node;
782 var en = new Enum (node.name, current_source_reference);
783 en.access = SymbolAccessibility.PUBLIC;
784 en.has_type_id = (en_node.gtype_name != null && en_node.gtype_name != "");
786 string common_prefix = null;
788 foreach (weak IdlNode value in en_node.values) {
789 if (common_prefix == null) {
790 common_prefix = value.name;
791 while (common_prefix.len () > 0 && !common_prefix.has_suffix ("_")) {
792 // FIXME: could easily be made faster
793 common_prefix = common_prefix.ndup (common_prefix.size () - 1);
795 } else {
796 while (!value.name.has_prefix (common_prefix)) {
797 common_prefix = common_prefix.ndup (common_prefix.size () - 1);
800 while (common_prefix.len () > 0 && (!common_prefix.has_suffix ("_") ||
801 (value.name.offset (common_prefix.size ()).get_char ().isdigit ()) && (value.name.len () - common_prefix.len ()) <= 1)) {
802 // enum values may not consist solely of digits
803 common_prefix = common_prefix.ndup (common_prefix.size () - 1);
807 bool is_errordomain = false;
809 var cheader_filenames = new ArrayList<string> ();
811 var en_attributes = get_attributes (node.name);
812 if (en_attributes != null) {
813 foreach (string attr in en_attributes) {
814 var nv = attr.split ("=", 2);
815 if (nv[0] == "common_prefix") {
816 common_prefix = eval (nv[1]);
817 } else if (nv[0] == "cheader_filename") {
818 cheader_filenames.add (eval (nv[1]));
819 en.add_cheader_filename (eval (nv[1]));
820 } else if (nv[0] == "hidden") {
821 if (eval (nv[1]) == "1") {
822 return null;
824 } else if (nv[0] == "rename_to") {
825 en.name = eval (nv[1]);
826 } else if (nv[0] == "errordomain") {
827 if (eval (nv[1]) == "1") {
828 is_errordomain = true;
834 en.set_cprefix (common_prefix);
836 foreach (weak IdlNode value2 in en_node.values) {
837 var ev = new EnumValue (value2.name.offset (common_prefix.len ()));
838 en.add_value (ev);
841 if (is_errordomain) {
842 var ed = new ErrorDomain (en.name, current_source_reference);
843 ed.access = SymbolAccessibility.PUBLIC;
844 ed.set_cprefix (common_prefix);
846 foreach (string filename in cheader_filenames) {
847 ed.add_cheader_filename (filename);
850 foreach (EnumValue ev in en.get_values ()) {
851 ed.add_code (new ErrorCode (ev.name));
854 return ed;
857 return en;
860 private void parse_object (IdlNodeInterface node, Namespace ns, IdlModule module) {
861 string name = fix_type_name (((IdlNode) node).name, ns);
863 string base_class = null;
865 var cl = ns.scope.lookup (name) as Class;
866 if (cl == null) {
867 cl = new Class (name, current_source_reference);
868 cl.access = SymbolAccessibility.PUBLIC;
870 var attributes = get_attributes (node.gtype_name);
871 if (attributes != null) {
872 foreach (string attr in attributes) {
873 var nv = attr.split ("=", 2);
874 if (nv[0] == "cheader_filename") {
875 cl.add_cheader_filename (eval (nv[1]));
876 } else if (nv[0] == "base_class") {
877 base_class = eval (nv[1]);
878 } else if (nv[0] == "hidden") {
879 if (eval (nv[1]) == "1") {
880 return;
882 } else if (nv[0] == "type_check_function") {
883 cl.type_check_function = eval (nv[1]);
884 } else if (nv[0] == "abstract") {
885 if (eval (nv[1]) == "1") {
886 cl.is_abstract = true;
892 ns.add_class (cl);
893 current_source_file.add_node (cl);
896 if (base_class != null) {
897 var parent = parse_type_string (base_class);
898 cl.add_base_type (parent);
899 } else if (node.parent != null) {
900 var parent = parse_type_string (node.parent);
901 cl.add_base_type (parent);
902 } else {
903 var gobject_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Object");
904 cl.add_base_type (new UnresolvedType.from_symbol (gobject_symbol));
907 foreach (string iface_name in node.interfaces) {
908 var iface = parse_type_string (iface_name);
909 cl.add_base_type (iface);
912 current_data_type = cl;
914 current_type_symbol_set = new HashSet<string> (str_hash, str_equal);
915 var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
916 var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
918 foreach (weak IdlNode member in node.members) {
919 if (member.type == IdlNodeTypeId.FUNCTION) {
920 current_type_func_map.set (member.name, (IdlNodeFunction) member);
922 if (member.type == IdlNodeTypeId.VFUNC) {
923 current_type_vfunc_map.set (member.name, "1");
927 foreach (weak IdlNode member in node.members) {
928 if (member.type == IdlNodeTypeId.FUNCTION) {
929 // Ignore if vfunc (handled below)
930 if (!current_type_vfunc_map.contains (member.name)) {
931 var m = parse_function ((IdlNodeFunction) member);
932 if (m != null) {
933 cl.add_method (m);
936 } else if (member.type == IdlNodeTypeId.VFUNC) {
937 var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name));
938 if (m != null) {
939 cl.add_method (m);
941 } else if (member.type == IdlNodeTypeId.PROPERTY) {
942 var prop = parse_property ((IdlNodeProperty) member);
943 if (prop != null) {
944 cl.add_property (prop);
946 } else if (member.type == IdlNodeTypeId.SIGNAL) {
947 var sig = parse_signal ((IdlNodeSignal) member);
948 if (sig != null) {
949 cl.add_signal (sig);
954 foreach (weak IdlNode member in node.members) {
955 if (member.type == IdlNodeTypeId.FIELD) {
956 if (!current_type_symbol_set.contains (member.name)) {
957 var f = parse_field ((IdlNodeField) member);
958 if (f != null) {
959 cl.add_field (f);
965 foreach (Property prop in cl.get_properties ()) {
966 var getter = "get_%s".printf (prop.name);
968 if (prop.get_accessor != null && !current_type_symbol_set.contains (getter)) {
969 prop.no_accessor_method = true;
970 prop.get_accessor.value_type.value_owned = true;
973 var setter = "set_%s".printf (prop.name);
975 if (prop.set_accessor != null && !current_type_symbol_set.contains (setter)) {
976 prop.no_accessor_method = true;
980 current_data_type = null;
981 current_type_symbol_set = null;
984 private void parse_interface (IdlNodeInterface node, Namespace ns, IdlModule module) {
985 string name = fix_type_name (node.gtype_name, ns);
987 var iface = ns.scope.lookup (name) as Interface;
988 if (iface == null) {
989 iface = new Interface (name, current_source_reference);
990 iface.access = SymbolAccessibility.PUBLIC;
992 var attributes = get_attributes (node.gtype_name);
993 if (attributes != null) {
994 foreach (string attr in attributes) {
995 var nv = attr.split ("=", 2);
996 if (nv[0] == "cheader_filename") {
997 iface.add_cheader_filename (eval (nv[1]));
998 } else if (nv[0] == "lower_case_csuffix") {
999 iface.set_lower_case_csuffix (eval (nv[1]));
1004 foreach (string prereq_name in node.prerequisites) {
1005 var prereq = parse_type_string (prereq_name);
1006 iface.add_prerequisite (prereq);
1009 ns.add_interface (iface);
1010 current_source_file.add_node (iface);
1013 current_data_type = iface;
1015 var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
1016 var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
1018 foreach (weak IdlNode member in node.members) {
1019 if (member.type == IdlNodeTypeId.FUNCTION) {
1020 current_type_func_map.set (member.name, (IdlNodeFunction) member);
1022 if (member.type == IdlNodeTypeId.VFUNC) {
1023 current_type_vfunc_map.set (member.name, "1");
1027 foreach (weak IdlNode member in node.members) {
1028 if (member.type == IdlNodeTypeId.FUNCTION) {
1029 // Ignore if vfunc (handled below)
1030 if (!current_type_vfunc_map.contains (member.name)) {
1031 var m = parse_function ((IdlNodeFunction) member, true);
1032 if (m != null) {
1033 iface.add_method (m);
1036 } else if (member.type == IdlNodeTypeId.VFUNC) {
1037 var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name), true);
1038 if (m != null) {
1039 iface.add_method (m);
1041 } else if (member.type == IdlNodeTypeId.PROPERTY) {
1042 var prop = parse_property ((IdlNodeProperty) member);
1043 if (prop != null) {
1044 iface.add_property (prop);
1046 } else if (member.type == IdlNodeTypeId.SIGNAL) {
1047 var sig = parse_signal ((IdlNodeSignal) member);
1048 if (sig != null) {
1049 iface.add_signal (sig);
1054 current_data_type = null;
1057 private DataType? parse_type (IdlNodeType type_node, out ParameterDirection direction = null) {
1058 ParameterDirection dir = ParameterDirection.IN;
1060 var type = new UnresolvedType ();
1061 if (type_node.tag == TypeTag.VOID) {
1062 if (type_node.is_pointer) {
1063 return new PointerType (new VoidType ());
1064 } else {
1065 return new VoidType ();
1067 } else if (type_node.tag == TypeTag.BOOLEAN) {
1068 type.unresolved_symbol = new UnresolvedSymbol (null, "bool");
1069 } else if (type_node.tag == TypeTag.INT8) {
1070 type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1071 } else if (type_node.tag == TypeTag.UINT8) {
1072 type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1073 } else if (type_node.tag == TypeTag.INT16) {
1074 type.unresolved_symbol = new UnresolvedSymbol (null, "int16");
1075 } else if (type_node.tag == TypeTag.UINT16) {
1076 type.unresolved_symbol = new UnresolvedSymbol (null, "uint16");
1077 } else if (type_node.tag == TypeTag.INT32) {
1078 type.unresolved_symbol = new UnresolvedSymbol (null, "int32");
1079 } else if (type_node.tag == TypeTag.UINT32) {
1080 type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
1081 } else if (type_node.tag == TypeTag.INT64) {
1082 type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1083 } else if (type_node.tag == TypeTag.UINT64) {
1084 type.unresolved_symbol = new UnresolvedSymbol (null, "uint64");
1085 } else if (type_node.tag == TypeTag.INT) {
1086 type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1087 } else if (type_node.tag == TypeTag.UINT) {
1088 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1089 } else if (type_node.tag == TypeTag.LONG) {
1090 type.unresolved_symbol = new UnresolvedSymbol (null, "long");
1091 } else if (type_node.tag == TypeTag.ULONG) {
1092 type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1093 } else if (type_node.tag == TypeTag.SSIZE) {
1094 type.unresolved_symbol = new UnresolvedSymbol (null, "ssize_t");
1095 } else if (type_node.tag == TypeTag.SIZE) {
1096 type.unresolved_symbol = new UnresolvedSymbol (null, "size_t");
1097 } else if (type_node.tag == TypeTag.FLOAT) {
1098 type.unresolved_symbol = new UnresolvedSymbol (null, "float");
1099 } else if (type_node.tag == TypeTag.DOUBLE) {
1100 type.unresolved_symbol = new UnresolvedSymbol (null, "double");
1101 } else if (type_node.tag == TypeTag.UTF8) {
1102 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1103 } else if (type_node.tag == TypeTag.FILENAME) {
1104 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1105 } else if (type_node.tag == TypeTag.ARRAY) {
1106 var element_type = parse_type (type_node.parameter_type1);
1107 type = element_type as UnresolvedType;
1108 if (type == null) {
1109 return element_type;
1111 return new ArrayType (element_type, 1, element_type.source_reference);
1112 } else if (type_node.tag == TypeTag.LIST) {
1113 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "List");
1114 } else if (type_node.tag == TypeTag.SLIST) {
1115 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "SList");
1116 } else if (type_node.tag == TypeTag.HASH) {
1117 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "HashTable");
1118 } else if (type_node.tag == TypeTag.ERROR) {
1119 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Error");
1120 } else if (type_node.is_interface) {
1121 var n = type_node.@interface;
1123 if (n == "") {
1124 return null;
1127 if (n.has_prefix ("const-")) {
1128 n = n.offset ("const-".len ());
1131 if (type_node.is_pointer &&
1132 (n == "gchar" || n == "char")) {
1133 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1134 if (type_node.unparsed.has_suffix ("**")) {
1135 dir = ParameterDirection.OUT;
1137 } else if (n == "gunichar") {
1138 type.unresolved_symbol = new UnresolvedSymbol (null, "unichar");
1139 } else if (n == "gchar") {
1140 type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1141 } else if (n == "guchar" || n == "guint8") {
1142 type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1143 if (type_node.is_pointer) {
1144 return new ArrayType (type, 1, type.source_reference);
1146 } else if (n == "gushort") {
1147 type.unresolved_symbol = new UnresolvedSymbol (null, "ushort");
1148 } else if (n == "gshort") {
1149 type.unresolved_symbol = new UnresolvedSymbol (null, "short");
1150 } else if (n == "gconstpointer" || n == "void") {
1151 return new PointerType (new VoidType ());
1152 } else if (n == "goffset" || n == "off_t") {
1153 type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1154 } else if (n == "value_array") {
1155 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "ValueArray");
1156 } else if (n == "time_t") {
1157 type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1158 } else if (n == "socklen_t") {
1159 type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
1160 } else if (n == "mode_t") {
1161 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1162 } else if (n == "gint" || n == "pid_t") {
1163 type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1164 } else if (n == "unsigned" || n == "unsigned-int") {
1165 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1166 } else if (n == "FILE") {
1167 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "FileStream");
1168 } else if (n == "struct") {
1169 return new PointerType (new VoidType ());
1170 } else if (n == "iconv_t") {
1171 return new PointerType (new VoidType ());
1172 } else if (n == "GType") {
1173 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Type");
1174 if (type_node.is_pointer) {
1175 return new ArrayType (type, 1, type.source_reference);
1177 } else if (n == "GStrv") {
1178 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1179 return new ArrayType (type, 1, type.source_reference);
1180 } else {
1181 var named_type = parse_type_string (n);
1182 type = named_type as UnresolvedType;
1183 if (type == null) {
1184 return named_type;
1186 if (is_simple_type (n)) {
1187 if (type_node.is_pointer) {
1188 dir = ParameterDirection.OUT;
1190 } else if (type_node.unparsed.has_suffix ("**")) {
1191 dir = ParameterDirection.OUT;
1194 } else {
1195 stdout.printf ("%d\n", type_node.tag);
1197 if (&direction != null) {
1198 direction = dir;
1200 return type;
1203 private bool is_simple_type (string type_name) {
1204 var st = cname_type_map[type_name] as Struct;
1205 if (st != null && st.is_simple_type ()) {
1206 return true;
1209 return false;
1212 private DataType parse_type_string (string n) {
1213 if (n == "va_list") {
1214 // unsupported
1215 return new PointerType (new VoidType ());
1218 var type = new UnresolvedType ();
1220 var dt = cname_type_map[n];
1221 if (dt != null) {
1222 UnresolvedSymbol parent_symbol = null;
1223 if (dt.parent_symbol.name != null) {
1224 parent_symbol = new UnresolvedSymbol (null, dt.parent_symbol.name);
1226 type.unresolved_symbol = new UnresolvedSymbol (parent_symbol, dt.name);
1227 return type;
1230 var type_attributes = get_attributes (n);
1232 string ns_name = null;
1234 if (null != type_attributes) {
1235 foreach (string attr in type_attributes) {
1236 var nv = attr.split ("=", 2);
1238 if (nv[0] == "cprefix") {
1239 type.unresolved_symbol = new UnresolvedSymbol (null, n.offset (eval (nv[1]).len ()));
1240 } else if (nv[0] == "name") {
1241 type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1242 } else if (nv[0] == "namespace") {
1243 ns_name = eval (nv[1]);
1244 } else if (nv[0] == "rename_to") {
1245 type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1250 if (type.unresolved_symbol != null) {
1251 if (type.unresolved_symbol.name == "pointer") {
1252 return new PointerType (new VoidType ());
1254 if (ns_name != null) {
1255 type.unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
1257 return type;
1260 if (n.has_prefix (current_namespace.name)) {
1261 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, current_namespace.name), n.offset (current_namespace.name.len ()));
1262 } else if (n.has_prefix ("G")) {
1263 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), n.offset (1));
1264 } else {
1265 var name_parts = n.split (".", 2);
1266 if (name_parts[1] == null) {
1267 type.unresolved_symbol = new UnresolvedSymbol (null, name_parts[0]);
1268 } else {
1269 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, name_parts[0]), name_parts[1]);
1273 return type;
1276 private DataType? parse_param (IdlNodeParam param, out ParameterDirection direction = null) {
1277 var type = parse_type (param.type, out direction);
1279 // disable for now as null_ok not yet correctly set
1280 // type.non_null = !param.null_ok;
1282 return type;
1285 private Method? create_method (string name, string symbol, IdlNodeParam? res, GLib.List<IdlNodeParam>? parameters, bool is_constructor, bool is_interface) {
1286 DataType return_type = null;
1287 if (res != null) {
1288 return_type = parse_param (res);
1291 Method m;
1292 if (!is_interface && (is_constructor || name.has_prefix ("new"))) {
1293 m = new CreationMethod (null, name, current_source_reference);
1294 m.has_construct_function = false;
1295 if (m.name == "new") {
1296 m.name = null;
1297 } else if (m.name.has_prefix ("new_")) {
1298 m.name = m.name.offset ("new_".len ());
1300 // For classes, check whether a creation method return type equals to the
1301 // type of the class created. If the types do not match (e.g. in most
1302 // gtk widgets) add an attribute to the creation method indicating the used
1303 // return type.
1304 if (current_data_type is Class && res != null) {
1305 if ("%s*".printf (current_data_type.get_cname()) != res.type.unparsed) {
1306 ((CreationMethod)m).custom_return_type_cname = res.type.unparsed;
1309 } else {
1310 m = new Method (name, return_type, current_source_reference);
1312 m.access = SymbolAccessibility.PUBLIC;
1314 if (current_type_symbol_set != null) {
1315 current_type_symbol_set.add (name);
1318 if (current_data_type != null) {
1319 var sig_attributes = get_attributes ("%s::%s".printf (current_data_type.get_cname (), name));
1320 if (sig_attributes != null) {
1321 foreach (string attr in sig_attributes) {
1322 var nv = attr.split ("=", 2);
1323 if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
1324 return null;
1330 bool add_ellipsis = false;
1331 bool suppress_throws = false;
1333 var attributes = get_attributes (symbol);
1334 if (attributes != null) {
1335 foreach (string attr in attributes) {
1336 var nv = attr.split ("=", 2);
1337 if (nv[0] == "name") {
1338 m.set_cname (m.name);
1339 m.name = eval (nv[1]);
1340 } else if (nv[0] == "hidden") {
1341 if (eval (nv[1]) == "1") {
1342 return null;
1344 } else if (nv[0] == "ellipsis") {
1345 if (eval (nv[1]) == "1") {
1346 add_ellipsis = true;
1348 } else if (nv[0] == "transfer_ownership") {
1349 if (eval (nv[1]) == "1") {
1350 return_type.value_owned = true;
1352 } else if (nv[0] == "nullable") {
1353 if (eval (nv[1]) == "1") {
1354 return_type.nullable = true;
1356 } else if (nv[0] == "sentinel") {
1357 m.sentinel = eval (nv[1]);
1358 } else if (nv[0] == "is_array") {
1359 if (eval (nv[1]) == "1") {
1360 return_type = new ArrayType (return_type, 1, return_type.source_reference);
1361 m.return_type = return_type;
1363 } else if (nv[0] == "throws") {
1364 if (eval (nv[1]) == "0") {
1365 suppress_throws = true;
1367 } else if (nv[0] == "no_array_length") {
1368 if (eval (nv[1]) == "1") {
1369 m.no_array_length = true;
1371 } else if (nv[0] == "array_null_terminated") {
1372 if (eval (nv[1]) == "1") {
1373 m.no_array_length = true;
1374 m.array_null_terminated = true;
1376 } else if (nv[0] == "type_name") {
1377 var sym = new UnresolvedSymbol (null, eval (nv[1]));
1378 if (return_type is UnresolvedType) {
1379 ((UnresolvedType) return_type).unresolved_symbol = sym;
1380 } else {
1381 // Overwrite old return_type, so "type_name" must be before any
1382 // other return type modifying metadata
1383 m.return_type = return_type = new UnresolvedType.from_symbol (sym, return_type.source_reference);
1385 } else if (nv[0] == "type_arguments") {
1386 var type_args = eval (nv[1]).split (",");
1387 foreach (string type_arg in type_args) {
1388 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1389 arg_type.value_owned = true;
1390 return_type.add_type_argument (arg_type);
1392 } else if (nv[0] == "cheader_filename") {
1393 m.add_cheader_filename (eval (nv[1]));
1394 } else if (nv[0] == "abstract") {
1395 if (eval (nv[1]) == "1") {
1396 m.is_abstract = true;
1398 } else if (nv[0] == "virtual") {
1399 if (eval (nv[1]) == "1") {
1400 m.is_virtual = true;
1407 m.set_cname (symbol);
1409 bool first = true;
1410 FormalParameter last_param = null;
1411 DataType last_param_type = null;
1412 foreach (weak IdlNodeParam param in parameters) {
1413 weak IdlNode param_node = (IdlNode) param;
1415 if (first) {
1416 first = false;
1417 if (!(m is CreationMethod) &&
1418 current_data_type != null &&
1419 param.type.is_interface &&
1420 (param_node.name == "self" ||
1421 param.type.@interface.has_suffix (current_data_type.get_cname ()))) {
1422 // instance method
1423 continue;
1424 } else if (!(m is CreationMethod) &&
1425 current_data_type != null &&
1426 param.type.is_interface &&
1427 (param_node.name == "klass" ||
1428 param.type.@interface.has_suffix ("%sClass".printf(current_data_type.get_cname ())))) {
1429 // class method
1430 m.binding = MemberBinding.CLASS;
1431 if (m.name.has_prefix ("class_")) {
1432 m.name = m.name.substring ("class_".len (), m.name.len () - "class_".len ());
1434 continue;
1435 } else {
1436 // static method
1437 m.binding = MemberBinding.STATIC;
1441 if (suppress_throws == false && param_is_exception (param)) {
1442 m.add_error_type (parse_type (param.type));
1443 continue;
1446 string param_name = param_node.name;
1447 if (param_name == "result") {
1448 // avoid conflict with generated result variable
1449 param_name = "_result";
1450 } else if (param_name == "string") {
1451 // avoid conflict with string type
1452 param_name = "str";
1454 ParameterDirection direction;
1455 var param_type = parse_param (param, out direction);
1456 var p = new FormalParameter (param_name, param_type);
1457 p.direction = direction;
1459 bool hide_param = false;
1460 bool show_param = false;
1461 bool set_array_length_pos = false;
1462 double array_length_pos = 0;
1463 bool set_delegate_target_pos = false;
1464 double delegate_target_pos = 0;
1465 bool array_requested = false;
1466 attributes = get_attributes ("%s.%s".printf (symbol, param_node.name));
1467 if (attributes != null) {
1468 foreach (string attr in attributes) {
1469 var nv = attr.split ("=", 2);
1470 if (nv[0] == "is_array") {
1471 if (eval (nv[1]) == "1") {
1472 param_type = new ArrayType (param_type, 1, param_type.source_reference);
1473 p.parameter_type = param_type;
1474 p.direction = ParameterDirection.IN;
1475 array_requested = true;
1477 } else if (nv[0] == "is_out") {
1478 if (eval (nv[1]) == "1") {
1479 p.direction = ParameterDirection.OUT;
1480 if (!array_requested && param_type is ArrayType) {
1481 var array_type = (ArrayType) param_type;
1482 param_type = array_type.element_type;
1483 p.parameter_type = param_type;
1486 } else if (nv[0] == "is_ref") {
1487 if (eval (nv[1]) == "1") {
1488 p.direction = ParameterDirection.REF;
1489 if (!array_requested && param_type is ArrayType) {
1490 var array_type = (ArrayType) param_type;
1491 param_type = array_type.element_type;
1492 p.parameter_type = param_type;
1495 } else if (nv[0] == "nullable") {
1496 if (eval (nv[1]) == "1") {
1497 param_type.nullable = true;
1499 } else if (nv[0] == "transfer_ownership") {
1500 if (eval (nv[1]) == "1") {
1501 param_type.value_owned = true;
1503 } else if (nv[0] == "takes_ownership") {
1504 if (eval (nv[1]) == "1") {
1505 param_type.value_owned = true;
1507 } else if (nv[0] == "value_owned") {
1508 if (eval (nv[1]) == "0") {
1509 param_type.value_owned = false;
1510 } else if (eval (nv[1]) == "1") {
1511 param_type.value_owned = true;
1513 } else if (nv[0] == "hidden") {
1514 if (eval (nv[1]) == "1") {
1515 hide_param = true;
1516 } else if (eval (nv[1]) == "0") {
1517 show_param = true;
1519 } else if (nv[0] == "no_array_length") {
1520 if (eval (nv[1]) == "1") {
1521 p.no_array_length = true;
1523 } else if (nv[0] == "array_null_terminated") {
1524 if (eval (nv[1]) == "1") {
1525 p.no_array_length = true;
1526 p.array_null_terminated = true;
1528 } else if (nv[0] == "array_length_pos") {
1529 set_array_length_pos = true;
1530 array_length_pos = eval (nv[1]).to_double ();
1531 } else if (nv[0] == "delegate_target_pos") {
1532 set_delegate_target_pos = true;
1533 delegate_target_pos = eval (nv[1]).to_double ();
1534 } else if (nv[0] == "type_name") {
1535 ((UnresolvedType) param_type).unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1536 } else if (nv[0] == "ctype") {
1537 p.ctype = eval (nv[1]);
1538 } else if (nv[0] == "type_arguments") {
1539 var type_args = eval (nv[1]).split (",");
1540 foreach (string type_arg in type_args) {
1541 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1542 arg_type.value_owned = true;
1543 param_type.add_type_argument (arg_type);
1549 if (last_param != null && p.name == "n_" + last_param.name) {
1550 if (!(last_param_type is ArrayType)) {
1551 // last_param is array, p is array length
1552 last_param_type = new ArrayType (last_param_type, 1, last_param_type.source_reference);
1553 last_param.parameter_type = last_param_type;
1554 last_param.direction = ParameterDirection.IN;
1557 // hide array length param
1558 hide_param = true;
1559 } else if (last_param != null && p.name == "user_data") {
1560 // last_param is delegate
1562 // hide deleate target param
1563 hide_param = true;
1566 if (show_param || !hide_param) {
1567 m.add_parameter (p);
1568 if (set_array_length_pos) {
1569 p.carray_length_parameter_position = array_length_pos;
1571 if (set_delegate_target_pos) {
1572 p.cdelegate_target_parameter_position = delegate_target_pos;
1576 last_param = p;
1577 last_param_type = param_type;
1580 if (first) {
1581 // no parameters => static method
1582 m.binding = MemberBinding.STATIC;
1585 if (last_param != null && last_param.name.has_prefix ("first_")) {
1586 last_param.ellipsis = true;
1587 } else if (add_ellipsis) {
1588 m.add_parameter (new FormalParameter.with_ellipsis ());
1591 return m;
1594 private bool param_is_exception (IdlNodeParam param) {
1595 if (!param.type.is_error) {
1596 return false;
1598 var s = param.type.unparsed.chomp ();
1599 if (s.has_suffix ("**")) {
1600 return true;
1602 return false;
1605 private Method? parse_function (IdlNodeFunction f, bool is_interface = false) {
1606 weak IdlNode node = (IdlNode) f;
1608 if (f.deprecated) {
1609 return null;
1612 return create_method (node.name, f.symbol, f.result, f.parameters, f.is_constructor, is_interface);
1615 private Method parse_virtual (IdlNodeVFunc v, IdlNodeFunction? func, bool is_interface = false) {
1616 weak IdlNode node = (IdlNode) v;
1617 string symbol = "%s%s".printf (current_data_type.get_lower_case_cprefix(), node.name);
1619 if (func != null) {
1620 symbol = func.symbol;
1623 Method m = create_method (node.name, symbol, v.result, func != null ? func.parameters : v.parameters, false, is_interface);
1624 if (m != null) {
1625 m.binding = MemberBinding.INSTANCE;
1626 m.is_virtual = !(m.is_abstract || is_interface);
1627 m.is_abstract = m.is_abstract || is_interface;
1629 if (func == null) {
1630 m.attributes.append (new Attribute ("NoWrapper", null));
1634 return m;
1637 private string fix_prop_name (string name) {
1638 var str = new StringBuilder ();
1640 string i = name;
1642 while (i.len () > 0) {
1643 unichar c = i.get_char ();
1644 if (c == '-') {
1645 str.append_c ('_');
1646 } else {
1647 str.append_unichar (c);
1650 i = i.next_char ();
1653 return str.str;
1656 private Property? parse_property (IdlNodeProperty prop_node) {
1657 weak IdlNode node = (IdlNode) prop_node;
1659 if (prop_node.deprecated) {
1660 return null;
1663 if (!prop_node.readable && !prop_node.writable) {
1664 // buggy GIDL definition
1665 prop_node.readable = true;
1666 prop_node.writable = true;
1669 var prop = new Property (fix_prop_name (node.name), parse_type (prop_node.type), null, null, current_source_reference);
1670 prop.access = SymbolAccessibility.PUBLIC;
1671 prop.interface_only = true;
1673 if (prop_node.readable) {
1674 prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, null);
1676 if (prop_node.writable) {
1677 prop.set_accessor = new PropertyAccessor (false, false, false, prop.property_type.copy (), null, null);
1678 if (prop_node.construct_only) {
1679 prop.set_accessor.construction = true;
1680 } else {
1681 prop.set_accessor.writable = true;
1682 prop.set_accessor.construction = prop_node.@construct;
1686 var attributes = get_attributes ("%s:%s".printf (current_data_type.get_cname (), node.name));
1687 if (attributes != null) {
1688 foreach (string attr in attributes) {
1689 var nv = attr.split ("=", 2);
1690 if (nv[0] == "hidden") {
1691 if (eval (nv[1]) == "1") {
1692 return null;
1694 } else if (nv[0] == "type_arguments") {
1695 var type_args = eval (nv[1]).split (",");
1696 foreach (string type_arg in type_args) {
1697 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1698 arg_type.value_owned = true;
1699 prop.property_type.add_type_argument (arg_type);
1705 if (current_type_symbol_set != null) {
1706 current_type_symbol_set.add (prop.name);
1709 return prop;
1712 private Constant? parse_constant (IdlNodeConstant const_node) {
1713 weak IdlNode node = (IdlNode) const_node;
1715 var type = parse_type (const_node.type);
1716 if (type == null) {
1717 return null;
1720 var c = new Constant (node.name, type, null, current_source_reference);
1722 string[] attributes = get_attributes (node.name);
1723 if (attributes != null) {
1724 foreach (string attr in attributes) {
1725 var nv = attr.split ("=", 2);
1726 if (nv[0] == "cheader_filename") {
1727 c.add_cheader_filename (eval (nv[1]));
1728 } else if (nv[0] == "hidden") {
1729 if (eval (nv[1]) == "1") {
1730 return null;
1736 c.access = SymbolAccessibility.PUBLIC;
1738 return c;
1741 private Field? parse_field (IdlNodeField field_node) {
1742 weak IdlNode node = (IdlNode) field_node;
1743 bool unhidden = false;
1745 var type = parse_type (field_node.type);
1746 if (type == null) {
1747 return null;
1750 string cheader_filename = null;
1751 string ctype = null;
1753 var attributes = get_attributes ("%s.%s".printf (current_data_type.get_cname (), node.name));
1754 if (attributes != null) {
1755 foreach (string attr in attributes) {
1756 var nv = attr.split ("=", 2);
1757 if (nv[0] == "hidden") {
1758 if (eval (nv[1]) == "1") {
1759 return null;
1760 } else {
1761 unhidden = true;
1763 } else if (nv[0] == "is_array") {
1764 if (eval (nv[1]) == "1") {
1765 type = new ArrayType (type, 1, type.source_reference);
1767 } else if (nv[0] == "weak") {
1768 if (eval (nv[1]) == "0") {
1769 type.value_owned = true;
1771 } else if (nv[0] == "type_name") {
1772 ((UnresolvedType) type).unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1773 } else if (nv[0] == "type_arguments") {
1774 var type_args = eval (nv[1]).split (",");
1775 foreach (string type_arg in type_args) {
1776 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1777 arg_type.value_owned = true;
1778 type.add_type_argument (arg_type);
1780 } else if (nv[0] == "cheader_filename") {
1781 cheader_filename = eval (nv[1]);
1782 } else if (nv[0] == "ctype") {
1783 ctype = eval (nv[1]);
1788 if (node.name.has_prefix("_") && !unhidden) {
1789 return null;
1792 if (current_type_symbol_set != null) {
1793 current_type_symbol_set.add (node.name);
1796 string field_name = node.name;
1797 if (field_name == "string") {
1798 // avoid conflict with string type
1799 field_name = "str";
1802 var field = new Field (field_name, type, null, current_source_reference);
1803 field.access = SymbolAccessibility.PUBLIC;
1805 if (field_name != node.name) {
1806 field.set_cname (node.name);
1809 if (ctype != null) {
1810 field.set_ctype (ctype);
1813 if (cheader_filename != null) {
1814 field.add_cheader_filename (cheader_filename);
1817 field.no_array_length = true;
1819 return field;
1822 private string[]? get_attributes (string codenode) {
1823 var attributes = codenode_attributes_map.get (codenode);
1825 if (attributes == null) {
1826 var dot_required = (null != codenode.chr (-1, '.'));
1827 var colon_required = (null != codenode.chr (-1, ':'));
1829 var pattern_specs = codenode_attributes_patterns.get_keys ();
1830 foreach (PatternSpec* pattern in pattern_specs) {
1831 var pspec = codenode_attributes_patterns[pattern];
1833 if ((dot_required && null == pspec.chr (-1, '.')) ||
1834 (colon_required && null == pspec.chr (-1, ':'))) {
1835 continue;
1838 if (pattern->match_string (codenode)) {
1839 return get_attributes (pspec);
1844 if (attributes == null) {
1845 return null;
1848 return attributes.split (" ");
1851 private string eval (string s) {
1852 return s.offset (1).ndup (s.size () - 2);
1855 private Signal? parse_signal (IdlNodeSignal sig_node) {
1856 weak IdlNode node = (IdlNode) sig_node;
1858 if (sig_node.deprecated || sig_node.result == null) {
1859 return null;
1862 var sig = new Signal (fix_prop_name (node.name), parse_param (sig_node.result), current_source_reference);
1863 sig.access = SymbolAccessibility.PUBLIC;
1865 var attributes = get_attributes ("%s::%s".printf (current_data_type.get_cname (), sig.name));
1866 if (attributes != null) {
1867 foreach (string attr in attributes) {
1868 var nv = attr.split ("=", 2);
1869 if (nv[0] == "name") {
1870 sig.set_cname (sig.name);
1871 sig.name = eval (nv[1]);
1872 } else if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
1873 sig.has_emitter = true;
1874 } else if (nv[0] == "hidden") {
1875 if (eval (nv[1]) == "1") {
1876 return null;
1882 sig.is_virtual = true;
1884 bool first = true;
1886 foreach (weak IdlNodeParam param in sig_node.parameters) {
1887 if (first) {
1888 // ignore implicit first signal parameter (sender)
1889 first = false;
1890 continue;
1893 weak IdlNode param_node = (IdlNode) param;
1895 ParameterDirection direction;
1896 var param_type = parse_param (param, out direction);
1897 var p = new FormalParameter (param_node.name, param_type);
1898 p.direction = direction;
1899 sig.add_parameter (p);
1901 attributes = get_attributes ("%s::%s.%s".printf (current_data_type.get_cname (), sig.name, param_node.name));
1902 if (attributes != null) {
1903 string ns_name = null;
1904 foreach (string attr in attributes) {
1905 var nv = attr.split ("=", 2);
1906 if (nv[0] == "is_array") {
1907 if (eval (nv[1]) == "1") {
1908 param_type = new ArrayType (param_type, 1, param_type.source_reference);
1909 p.parameter_type = param_type;
1910 p.direction = ParameterDirection.IN;
1912 } else if (nv[0] == "is_out") {
1913 if (eval (nv[1]) == "1") {
1914 p.direction = ParameterDirection.OUT;
1916 } else if (nv[0] == "is_ref") {
1917 if (eval (nv[1]) == "1") {
1918 p.direction = ParameterDirection.REF;
1920 } else if (nv[0] == "nullable") {
1921 if (eval (nv[1]) == "1") {
1922 param_type.nullable = true;
1924 } else if (nv[0] == "type_name") {
1925 ((UnresolvedType) param_type).unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1926 } else if (nv[0] == "namespace_name") {
1927 ns_name = eval (nv[1]);
1930 if (ns_name != null) {
1931 ((UnresolvedType) param_type).unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
1936 return sig;