Fix handling of int16, uint16, int32, and uint32
[vala-lang.git] / vapigen / valagidlparser.vala
blob5b16b34ff118c3004a30ae43700b596b84241ac7
1 /* valagidlparser.vala
3 * Copyright (C) 2006-2008 Jürg Billeter, Raffaele Sandrini
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
21 * Raffaele Sandrini <raffaele@sandrini.ch>
24 using GLib;
25 using Gee;
27 /**
28 * Code visitor parsing all GIDL files.
30 public class Vala.GIdlParser : CodeVisitor {
31 private CodeContext context;
33 private SourceFile current_source_file;
35 private SourceReference current_source_reference;
37 private Namespace current_namespace;
38 private TypeSymbol current_data_type;
39 private Map<string,string> codenode_attributes_map;
40 private Map<PatternSpec*,string> codenode_attributes_patterns;
41 private Gee.Set<string> current_type_symbol_set;
43 private Map<string,TypeSymbol> cname_type_map;
45 /**
46 * Parse all source files in the specified code context and build a
47 * code tree.
49 * @param context a code context
51 public void parse (CodeContext context) {
52 cname_type_map = new HashMap<string,TypeSymbol> (str_hash, str_equal);
54 this.context = context;
55 context.accept (this);
57 cname_type_map = null;
60 public override void visit_namespace (Namespace ns) {
61 ns.accept_children (this);
64 public override void visit_class (Class cl) {
65 visit_type (cl);
68 public override void visit_struct (Struct st) {
69 visit_type (st);
72 public override void visit_interface (Interface iface) {
73 visit_type (iface);
76 public override void visit_enum (Enum en) {
77 visit_type (en);
80 public override void visit_error_domain (ErrorDomain ed) {
81 visit_type (ed);
84 public override void visit_delegate (Delegate d) {
85 visit_type (d);
88 private void visit_type (TypeSymbol t) {
89 if (!cname_type_map.contains (t.get_cname ())) {
90 cname_type_map[t.get_cname ()] = t;
94 public override void visit_source_file (SourceFile source_file) {
95 if (source_file.filename.has_suffix (".gi")) {
96 parse_file (source_file);
100 private void parse_file (SourceFile source_file) {
101 string metadata_filename = "%s.metadata".printf (source_file.filename.ndup (source_file.filename.size () - ".gi".size ()));
103 current_source_file = source_file;
105 codenode_attributes_map = new HashMap<string,string> (str_hash, str_equal);
106 codenode_attributes_patterns = new HashMap<PatternSpec*,string> (direct_hash, (EqualFunc) PatternSpec.equal);
108 if (FileUtils.test (metadata_filename, FileTest.EXISTS)) {
109 try {
110 string metadata;
111 FileUtils.get_contents (metadata_filename, out metadata, null);
113 foreach (string line in metadata.split ("\n")) {
114 if (line.has_prefix ("#")) {
115 // ignore comment lines
116 continue;
119 var tokens = line.split (" ", 2);
121 if (null == tokens[0]) {
122 continue;
125 if (null != tokens[0].chr (-1, '*')) {
126 PatternSpec* pattern = new PatternSpec (tokens[0]);
127 codenode_attributes_patterns[pattern] = tokens[0];
130 codenode_attributes_map[tokens[0]] = tokens[1];
132 } catch (FileError e) {
133 Report.error (null, "Unable to read metadata file: %s".printf (e.message));
137 try {
138 var modules = Idl.parse_file (source_file.filename);
140 current_source_reference = new SourceReference (source_file);
142 foreach (weak IdlModule module in modules) {
143 var ns = parse_module (module);
144 if (ns != null) {
145 context.root.add_namespace (ns);
148 } catch (MarkupError e) {
149 stdout.printf ("error parsing GIDL file: %s\n", e.message);
153 private string fix_type_name (string type_name, Namespace ns) {
154 var attributes = get_attributes (type_name);
155 if (attributes != null) {
156 foreach (string attr in attributes) {
157 var nv = attr.split ("=", 2);
158 if (nv[0] == "name") {
159 return eval (nv[1]);
164 if (type_name.has_prefix (ns.name)) {
165 return type_name.offset (ns.name.len ());
166 } else if (ns.name == "GLib" && type_name.has_prefix ("G")) {
167 return type_name.offset (1);
168 } else {
169 string best_match = null;
170 foreach (string cprefix in ns.get_cprefixes ()) {
171 if (type_name.has_prefix (cprefix)) {
172 if (best_match == null || cprefix.len () > best_match.len ())
173 best_match = cprefix;
177 if (best_match != null) {
178 return type_name.offset (best_match.len ());;
182 return type_name;
185 private string fix_const_name (string const_name, Namespace ns) {
186 if (const_name.has_prefix (ns.name.up () + "_")) {
187 return const_name.offset (ns.name.len () + 1);
188 } else if (ns.name == "GLib" && const_name.has_prefix ("G_")) {
189 return const_name.offset (2);
191 return const_name;
194 private Namespace? parse_module (IdlModule module) {
195 Symbol sym = context.root.scope.lookup (module.name);
196 Namespace ns;
197 if (sym is Namespace) {
198 ns = (Namespace) sym;
199 if (ns.external_package) {
200 ns.attributes = null;
201 ns.source_reference = current_source_reference;
203 } else {
204 ns = new Namespace (module.name, current_source_reference);
207 current_namespace = ns;
209 var attributes = get_attributes (ns.name);
210 if (attributes != null) {
211 foreach (string attr in attributes) {
212 var nv = attr.split ("=", 2);
213 if (nv[0] == "cheader_filename") {
214 ns.set_cheader_filename (eval (nv[1]));
215 } else if (nv[0] == "cprefix") {
216 var cprefixes = eval (nv[1]).split (",");
217 foreach(string name in cprefixes) {
218 ns.add_cprefix (name);
220 } else if (nv[0] == "lower_case_cprefix") {
221 ns.set_lower_case_cprefix (eval (nv[1]));
226 foreach (weak IdlNode node in module.entries) {
227 if (node.type == IdlNodeTypeId.CALLBACK) {
228 var cb = parse_delegate ((IdlNodeFunction) node);
229 if (cb == null) {
230 continue;
232 cb.name = fix_type_name (cb.name, ns);
233 ns.add_delegate (cb);
234 current_source_file.add_node (cb);
235 } else if (node.type == IdlNodeTypeId.STRUCT) {
236 parse_struct ((IdlNodeStruct) node, ns, module);
237 } else if (node.type == IdlNodeTypeId.UNION) {
238 parse_union ((IdlNodeUnion) node, ns, module);
239 } else if (node.type == IdlNodeTypeId.BOXED) {
240 parse_boxed ((IdlNodeBoxed) node, ns, module);
241 } else if (node.type == IdlNodeTypeId.ENUM) {
242 var en = parse_enum ((IdlNodeEnum) node);
243 if (en == null) {
244 continue;
246 en.name = fix_type_name (en.name, ns);
247 if (en is ErrorDomain) {
248 ns.add_error_domain (en as ErrorDomain);
249 } else {
250 ns.add_enum (en as Enum);
252 current_source_file.add_node (en);
253 } else if (node.type == IdlNodeTypeId.FLAGS) {
254 var en = parse_enum ((IdlNodeEnum) node) as Enum;
255 if (en == null) {
256 continue;
258 en.name = fix_type_name (en.name, ns);
259 en.is_flags = true;
260 ns.add_enum (en);
261 current_source_file.add_node (en);
262 } else if (node.type == IdlNodeTypeId.OBJECT) {
263 parse_object ((IdlNodeInterface) node, ns, module);
264 } else if (node.type == IdlNodeTypeId.INTERFACE) {
265 parse_interface ((IdlNodeInterface) node, ns, module);
266 } else if (node.type == IdlNodeTypeId.CONSTANT) {
267 var c = parse_constant ((IdlNodeConstant) node);
268 if (c != null) {
269 c.name = fix_const_name (c.name, ns);
270 ns.add_constant (c);
271 current_source_file.add_node (c);
273 } else if (node.type == IdlNodeTypeId.FUNCTION) {
274 var m = parse_function ((IdlNodeFunction) node);
275 if (m != null) {
276 m.binding = MemberBinding.STATIC;
277 ns.add_method (m);
278 current_source_file.add_node (m);
283 current_namespace = null;
285 if (sym is Namespace) {
286 return null;
288 return ns;
291 private Delegate? parse_delegate (IdlNodeFunction f_node) {
292 weak IdlNode node = (IdlNode) f_node;
294 var cb = new Delegate (node.name, parse_param (f_node.result), current_source_reference);
295 cb.access = SymbolAccessibility.PUBLIC;
297 bool check_has_target = true;
299 var attributes = get_attributes (node.name);
300 if (attributes != null) {
301 foreach (string attr in attributes) {
302 var nv = attr.split ("=", 2);
303 if (nv[0] == "hidden") {
304 if (eval (nv[1]) == "1") {
305 return null;
307 } else if (nv[0] == "cheader_filename") {
308 cb.add_cheader_filename (eval (nv[1]));
309 } else if (nv[0] == "has_target") {
310 if (eval (nv[1]) == "0") {
311 check_has_target = false;
312 } else if (eval (nv[1]) == "1") {
313 cb.has_target = true;
319 uint remaining_params = f_node.parameters.length ();
320 foreach (weak IdlNodeParam param in f_node.parameters) {
321 weak IdlNode param_node = (IdlNode) param;
323 if (check_has_target && remaining_params == 1 && (param_node.name == "user_data" || param_node.name == "data")) {
324 // hide user_data parameter for instance delegates
325 cb.has_target = true;
326 } else {
327 string param_name = param_node.name;
328 if (param_name == "string") {
329 // avoid conflict with string type
330 param_name = "str";
331 } else if (param_name == "self") {
332 // avoid conflict with delegate target
333 param_name = "_self";
336 ParameterDirection direction;
337 var p = new FormalParameter (param_name, parse_param (param, out direction));
338 p.direction = direction;
340 bool hide_param = false;
341 bool show_param = false;
342 attributes = get_attributes ("%s.%s".printf (node.name, param_node.name));
343 if (attributes != null) {
344 foreach (string attr in attributes) {
345 var nv = attr.split ("=", 2);
346 if (nv[0] == "hidden") {
347 if (eval (nv[1]) == "1") {
348 hide_param = true;
349 } else if (eval (nv[1]) == "0") {
350 show_param = true;
356 if (show_param || !hide_param) {
357 cb.add_parameter (p);
361 remaining_params--;
364 return cb;
367 private bool is_reference_type (string cname) {
368 var st_attributes = get_attributes (cname);
369 if (st_attributes != null) {
370 foreach (string attr in st_attributes) {
371 var nv = attr.split ("=", 2);
372 if (nv[0] == "is_value_type" && eval (nv[1]) == "1") {
373 return false;
377 return true;
380 private void parse_struct (IdlNodeStruct st_node, Namespace ns, IdlModule module) {
381 weak IdlNode node = (IdlNode) st_node;
383 if (st_node.deprecated) {
384 return;
387 string name = fix_type_name (node.name, ns);
389 if (!is_reference_type (node.name)) {
390 var st = ns.scope.lookup (name) as Struct;
391 if (st == null) {
392 st = new Struct (name, current_source_reference);
393 st.access = SymbolAccessibility.PUBLIC;
395 var st_attributes = get_attributes (node.name);
396 if (st_attributes != null) {
397 foreach (string attr in st_attributes) {
398 var nv = attr.split ("=", 2);
399 if (nv[0] == "cheader_filename") {
400 st.add_cheader_filename (eval (nv[1]));
401 } else if (nv[0] == "hidden") {
402 if (eval (nv[1]) == "1") {
403 return;
405 } else if (nv[0] == "simple_type") {
406 if (eval (nv[1]) == "1") {
407 st.set_simple_type (true);
413 ns.add_struct (st);
414 current_source_file.add_node (st);
417 current_data_type = st;
419 foreach (weak IdlNode member in st_node.members) {
420 if (member.type == IdlNodeTypeId.FUNCTION) {
421 var m = parse_function ((IdlNodeFunction) member);
422 if (m != null) {
423 st.add_method (m);
425 } else if (member.type == IdlNodeTypeId.FIELD) {
426 var f = parse_field ((IdlNodeField) member);
427 if (f != null) {
428 st.add_field (f);
433 current_data_type = null;
434 } else {
435 var cl = ns.scope.lookup (name) as Class;
436 if (cl == null) {
437 string base_class = null;
439 cl = new Class (name, current_source_reference);
440 cl.access = SymbolAccessibility.PUBLIC;
441 cl.is_compact = true;
443 var cl_attributes = get_attributes (node.name);
444 if (cl_attributes != null) {
445 foreach (string attr in cl_attributes) {
446 var nv = attr.split ("=", 2);
447 if (nv[0] == "cheader_filename") {
448 cl.add_cheader_filename (eval (nv[1]));
449 } else if (nv[0] == "base_class") {
450 base_class = eval (nv[1]);
451 } else if (nv[0] == "hidden") {
452 if (eval (nv[1]) == "1") {
453 return;
455 } else if (nv[0] == "is_immutable") {
456 if (eval (nv[1]) == "1") {
457 cl.is_immutable = true;
459 } else if (nv[0] == "is_fundamental") {
460 if (eval (nv[1]) == "1") {
461 cl.is_compact = false;
463 } else if (nv[0] == "abstract" && base_class != null) {
464 if (eval (nv[1]) == "1") {
465 cl.is_abstract = true;
471 ns.add_class (cl);
472 current_source_file.add_node (cl);
474 if (base_class != null) {
475 var parent = parse_type_string (base_class);
476 cl.add_base_type (parent);
480 current_data_type = cl;
482 string ref_function = null;
483 string unref_function = null;
484 string copy_function = null;
485 string free_function = null;
487 foreach (weak IdlNode member in st_node.members) {
488 if (member.type == IdlNodeTypeId.FUNCTION) {
489 if (member.name == "ref") {
490 ref_function = ((IdlNodeFunction) member).symbol;
491 } else if (member.name == "unref") {
492 unref_function = ((IdlNodeFunction) member).symbol;
493 } else if (member.name == "free" || member.name == "destroy") {
494 free_function = ((IdlNodeFunction) member).symbol;
495 } else {
496 if (member.name == "copy") {
497 copy_function = ((IdlNodeFunction) member).symbol;
499 var m = parse_function ((IdlNodeFunction) member);
500 if (m != null) {
501 cl.add_method (m);
504 } else if (member.type == IdlNodeTypeId.FIELD) {
505 var f = parse_field ((IdlNodeField) member);
506 if (f != null) {
507 cl.add_field (f);
512 if (ref_function != null) {
513 cl.set_ref_function (ref_function);
515 if (copy_function != null) {
516 cl.set_dup_function (copy_function);
518 if (unref_function != null) {
519 cl.set_unref_function (unref_function);
520 } else if (free_function != null) {
521 cl.set_free_function (free_function);
524 current_data_type = null;
528 private void parse_union (IdlNodeUnion un_node, Namespace ns, IdlModule module) {
529 weak IdlNode node = (IdlNode) un_node;
531 if (un_node.deprecated) {
532 return;
535 string name = fix_type_name (node.name, ns);
537 if (!is_reference_type (node.name)) {
538 var st = ns.scope.lookup (name) as Struct;
539 if (st == null) {
540 st = new Struct (name, current_source_reference);
541 st.access = SymbolAccessibility.PUBLIC;
543 var st_attributes = get_attributes (node.name);
544 if (st_attributes != null) {
545 foreach (string attr in st_attributes) {
546 var nv = attr.split ("=", 2);
547 if (nv[0] == "cheader_filename") {
548 st.add_cheader_filename (eval (nv[1]));
549 } else if (nv[0] == "hidden") {
550 if (eval (nv[1]) == "1") {
551 return;
557 ns.add_struct (st);
558 current_source_file.add_node (st);
561 current_data_type = st;
563 foreach (weak IdlNode member in un_node.members) {
564 if (member.type == IdlNodeTypeId.FUNCTION) {
565 var m = parse_function ((IdlNodeFunction) member);
566 if (m != null) {
567 st.add_method (m);
569 } else if (member.type == IdlNodeTypeId.FIELD) {
570 var f = parse_field ((IdlNodeField) member);
571 if (f != null) {
572 st.add_field (f);
577 current_data_type = null;
578 } else {
579 var cl = ns.scope.lookup (name) as Class;
580 if (cl == null) {
581 cl = new Class (name, current_source_reference);
582 cl.access = SymbolAccessibility.PUBLIC;
583 cl.is_compact = true;
585 var cl_attributes = get_attributes (node.name);
586 if (cl_attributes != null) {
587 foreach (string attr in cl_attributes) {
588 var nv = attr.split ("=", 2);
589 if (nv[0] == "cheader_filename") {
590 cl.add_cheader_filename (eval (nv[1]));
591 } else if (nv[0] == "hidden") {
592 if (eval (nv[1]) == "1") {
593 return;
599 ns.add_class (cl);
600 current_source_file.add_node (cl);
603 current_data_type = cl;
605 string ref_function = null;
606 string unref_function = null;
607 string copy_function = null;
608 string free_function = null;
610 foreach (weak IdlNode member in un_node.members) {
611 if (member.type == IdlNodeTypeId.FUNCTION) {
612 if (member.name == "ref") {
613 ref_function = ((IdlNodeFunction) member).symbol;
614 } else if (member.name == "unref") {
615 unref_function = ((IdlNodeFunction) member).symbol;
616 } else if (member.name == "free" || member.name == "destroy") {
617 free_function = ((IdlNodeFunction) member).symbol;
618 } else {
619 if (member.name == "copy") {
620 copy_function = ((IdlNodeFunction) member).symbol;
622 var m = parse_function ((IdlNodeFunction) member);
623 if (m != null) {
624 cl.add_method (m);
627 } else if (member.type == IdlNodeTypeId.FIELD) {
628 var f = parse_field ((IdlNodeField) member);
629 if (f != null) {
630 cl.add_field (f);
635 if (ref_function != null) {
636 cl.set_ref_function (ref_function);
638 if (copy_function != null) {
639 cl.set_dup_function (copy_function);
641 if (unref_function != null) {
642 cl.set_unref_function (unref_function);
643 } else if (free_function != null) {
644 cl.set_free_function (free_function);
647 current_data_type = null;
651 private void parse_boxed (IdlNodeBoxed boxed_node, Namespace ns, IdlModule module) {
652 weak IdlNode node = (IdlNode) boxed_node;
654 string name = fix_type_name (node.name, ns);
656 var node_attributes = get_attributes (node.name);
657 if (node_attributes != null) {
658 foreach (string attr in node_attributes) {
659 var nv = attr.split ("=", 2);
660 if (nv[0] == "hidden") {
661 return;
666 if (!is_reference_type (node.name)) {
667 var st = ns.scope.lookup (name) as Struct;
668 if (st == null) {
669 st = new Struct (name, current_source_reference);
670 st.access = SymbolAccessibility.PUBLIC;
672 var st_attributes = get_attributes (node.name);
673 if (st_attributes != null) {
674 foreach (string attr in st_attributes) {
675 var nv = attr.split ("=", 2);
676 if (nv[0] == "cheader_filename") {
677 st.add_cheader_filename (eval (nv[1]));
682 ns.add_struct (st);
683 st.set_type_id (st.get_upper_case_cname ("TYPE_"));
684 current_source_file.add_node (st);
687 current_data_type = st;
689 foreach (weak IdlNode member in boxed_node.members) {
690 if (member.type == IdlNodeTypeId.FUNCTION) {
691 var m = parse_function ((IdlNodeFunction) member);
692 if (m != null) {
693 st.add_method (m);
695 } else if (member.type == IdlNodeTypeId.FIELD) {
696 var f = parse_field ((IdlNodeField) member);
697 if (f != null) {
698 st.add_field (f);
703 current_data_type = null;
704 } else {
705 var cl = ns.scope.lookup (name) as Class;
706 if (cl == null) {
707 cl = new Class (name, current_source_reference);
708 cl.access = SymbolAccessibility.PUBLIC;
709 cl.is_compact = true;
711 var cl_attributes = get_attributes (node.name);
712 if (cl_attributes != null) {
713 foreach (string attr in cl_attributes) {
714 var nv = attr.split ("=", 2);
715 if (nv[0] == "cheader_filename") {
716 cl.add_cheader_filename (eval (nv[1]));
717 } else if (nv[0] == "is_immutable") {
718 if (eval (nv[1]) == "1") {
719 cl.is_immutable = true;
725 ns.add_class (cl);
726 cl.set_type_id (cl.get_upper_case_cname ("TYPE_"));
727 current_source_file.add_node (cl);
730 current_data_type = cl;
732 string ref_function = null;
733 string unref_function = null;
734 string copy_function = null;
735 string free_function = null;
737 foreach (weak IdlNode member in boxed_node.members) {
738 if (member.type == IdlNodeTypeId.FUNCTION) {
739 if (member.name == "ref") {
740 ref_function = ((IdlNodeFunction) member).symbol;
741 } else if (member.name == "unref") {
742 unref_function = ((IdlNodeFunction) member).symbol;
743 } else if (member.name == "free" || member.name == "destroy") {
744 free_function = ((IdlNodeFunction) member).symbol;
745 } else {
746 if (member.name == "copy") {
747 copy_function = ((IdlNodeFunction) member).symbol;
749 var m = parse_function ((IdlNodeFunction) member);
750 if (m != null) {
751 cl.add_method (m);
754 } else if (member.type == IdlNodeTypeId.FIELD) {
755 var f = parse_field ((IdlNodeField) member);
756 if (f != null) {
757 cl.add_field (f);
762 if (ref_function != null) {
763 cl.set_ref_function (ref_function);
765 if (copy_function != null) {
766 cl.set_dup_function (copy_function);
768 if (unref_function != null) {
769 cl.set_unref_function (unref_function);
770 } else if (free_function != null) {
771 cl.set_free_function (free_function);
774 current_data_type = null;
778 private TypeSymbol? parse_enum (IdlNodeEnum en_node) {
779 weak IdlNode node = (IdlNode) en_node;
781 var en = new Enum (node.name, current_source_reference);
782 en.access = SymbolAccessibility.PUBLIC;
783 en.has_type_id = (en_node.gtype_name != null && en_node.gtype_name != "");
785 string common_prefix = null;
787 foreach (weak IdlNode value in en_node.values) {
788 if (common_prefix == null) {
789 common_prefix = value.name;
790 while (common_prefix.len () > 0 && !common_prefix.has_suffix ("_")) {
791 // FIXME: could easily be made faster
792 common_prefix = common_prefix.ndup (common_prefix.size () - 1);
794 } else {
795 while (!value.name.has_prefix (common_prefix)) {
796 common_prefix = common_prefix.ndup (common_prefix.size () - 1);
799 while (common_prefix.len () > 0 && (!common_prefix.has_suffix ("_") ||
800 (value.name.offset (common_prefix.size ()).get_char ().isdigit ()) && (value.name.len () - common_prefix.len ()) <= 1)) {
801 // enum values may not consist solely of digits
802 common_prefix = common_prefix.ndup (common_prefix.size () - 1);
806 bool is_errordomain = false;
808 var cheader_filenames = new ArrayList<string> ();
810 var en_attributes = get_attributes (node.name);
811 if (en_attributes != null) {
812 foreach (string attr in en_attributes) {
813 var nv = attr.split ("=", 2);
814 if (nv[0] == "common_prefix") {
815 common_prefix = eval (nv[1]);
816 } else if (nv[0] == "cheader_filename") {
817 cheader_filenames.add (eval (nv[1]));
818 en.add_cheader_filename (eval (nv[1]));
819 } else if (nv[0] == "hidden") {
820 if (eval (nv[1]) == "1") {
821 return null;
823 } else if (nv[0] == "rename_to") {
824 en.name = eval (nv[1]);
825 } else if (nv[0] == "errordomain") {
826 if (eval (nv[1]) == "1") {
827 is_errordomain = true;
833 en.set_cprefix (common_prefix);
835 foreach (weak IdlNode value2 in en_node.values) {
836 var ev = new EnumValue (value2.name.offset (common_prefix.len ()));
837 en.add_value (ev);
840 if (is_errordomain) {
841 var ed = new ErrorDomain (en.name, current_source_reference);
842 ed.access = SymbolAccessibility.PUBLIC;
843 ed.set_cprefix (common_prefix);
845 foreach (string filename in cheader_filenames) {
846 ed.add_cheader_filename (filename);
849 foreach (EnumValue ev in en.get_values ()) {
850 ed.add_code (new ErrorCode (ev.name));
853 return ed;
856 return en;
859 private void parse_object (IdlNodeInterface node, Namespace ns, IdlModule module) {
860 string name = fix_type_name (((IdlNode) node).name, ns);
862 string base_class = null;
864 var cl = ns.scope.lookup (name) as Class;
865 if (cl == null) {
866 cl = new Class (name, current_source_reference);
867 cl.access = SymbolAccessibility.PUBLIC;
869 var attributes = get_attributes (node.gtype_name);
870 if (attributes != null) {
871 foreach (string attr in attributes) {
872 var nv = attr.split ("=", 2);
873 if (nv[0] == "cheader_filename") {
874 cl.add_cheader_filename (eval (nv[1]));
875 } else if (nv[0] == "base_class") {
876 base_class = eval (nv[1]);
877 } else if (nv[0] == "hidden") {
878 if (eval (nv[1]) == "1") {
879 return;
881 } else if (nv[0] == "type_check_function") {
882 cl.type_check_function = eval (nv[1]);
883 } else if (nv[0] == "abstract") {
884 if (eval (nv[1]) == "1") {
885 cl.is_abstract = true;
891 ns.add_class (cl);
892 current_source_file.add_node (cl);
895 if (base_class != null) {
896 var parent = parse_type_string (base_class);
897 cl.add_base_type (parent);
898 } else if (node.parent != null) {
899 var parent = parse_type_string (node.parent);
900 cl.add_base_type (parent);
901 } else {
902 var gobject_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Object");
903 cl.add_base_type (new UnresolvedType.from_symbol (gobject_symbol));
906 foreach (string iface_name in node.interfaces) {
907 var iface = parse_type_string (iface_name);
908 cl.add_base_type (iface);
911 current_data_type = cl;
913 current_type_symbol_set = new HashSet<string> (str_hash, str_equal);
914 var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
915 var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
917 foreach (weak IdlNode member in node.members) {
918 if (member.type == IdlNodeTypeId.FUNCTION) {
919 current_type_func_map.set (member.name, (IdlNodeFunction) member);
921 if (member.type == IdlNodeTypeId.VFUNC) {
922 current_type_vfunc_map.set (member.name, "1");
926 foreach (weak IdlNode member in node.members) {
927 if (member.type == IdlNodeTypeId.FUNCTION) {
928 // Ignore if vfunc (handled below)
929 if (!current_type_vfunc_map.contains (member.name)) {
930 var m = parse_function ((IdlNodeFunction) member);
931 if (m != null) {
932 cl.add_method (m);
935 } else if (member.type == IdlNodeTypeId.VFUNC) {
936 var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name));
937 if (m != null) {
938 cl.add_method (m);
940 } else if (member.type == IdlNodeTypeId.PROPERTY) {
941 var prop = parse_property ((IdlNodeProperty) member);
942 if (prop != null) {
943 cl.add_property (prop);
945 } else if (member.type == IdlNodeTypeId.SIGNAL) {
946 var sig = parse_signal ((IdlNodeSignal) member);
947 if (sig != null) {
948 cl.add_signal (sig);
953 foreach (weak IdlNode member in node.members) {
954 if (member.type == IdlNodeTypeId.FIELD) {
955 if (!current_type_symbol_set.contains (member.name)) {
956 var f = parse_field ((IdlNodeField) member);
957 if (f != null) {
958 cl.add_field (f);
964 foreach (Property prop in cl.get_properties ()) {
965 var getter = "get_%s".printf (prop.name);
967 if (prop.get_accessor != null && !current_type_symbol_set.contains (getter)) {
968 prop.no_accessor_method = true;
971 var setter = "set_%s".printf (prop.name);
973 if (prop.set_accessor != null && !current_type_symbol_set.contains (setter)) {
974 prop.no_accessor_method = true;
978 current_data_type = null;
979 current_type_symbol_set = null;
982 private void parse_interface (IdlNodeInterface node, Namespace ns, IdlModule module) {
983 string name = fix_type_name (node.gtype_name, ns);
985 var iface = ns.scope.lookup (name) as Interface;
986 if (iface == null) {
987 iface = new Interface (name, current_source_reference);
988 iface.access = SymbolAccessibility.PUBLIC;
990 var attributes = get_attributes (node.gtype_name);
991 if (attributes != null) {
992 foreach (string attr in attributes) {
993 var nv = attr.split ("=", 2);
994 if (nv[0] == "cheader_filename") {
995 iface.add_cheader_filename (eval (nv[1]));
996 } else if (nv[0] == "lower_case_csuffix") {
997 iface.set_lower_case_csuffix (eval (nv[1]));
1002 foreach (string prereq_name in node.prerequisites) {
1003 var prereq = parse_type_string (prereq_name);
1004 iface.add_prerequisite (prereq);
1007 ns.add_interface (iface);
1008 current_source_file.add_node (iface);
1011 current_data_type = iface;
1013 var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
1014 var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
1016 foreach (weak IdlNode member in node.members) {
1017 if (member.type == IdlNodeTypeId.FUNCTION) {
1018 current_type_func_map.set (member.name, (IdlNodeFunction) member);
1020 if (member.type == IdlNodeTypeId.VFUNC) {
1021 current_type_vfunc_map.set (member.name, "1");
1025 foreach (weak IdlNode member in node.members) {
1026 if (member.type == IdlNodeTypeId.FUNCTION) {
1027 // Ignore if vfunc (handled below)
1028 if (!current_type_vfunc_map.contains (member.name)) {
1029 var m = parse_function ((IdlNodeFunction) member, true);
1030 if (m != null) {
1031 iface.add_method (m);
1034 } else if (member.type == IdlNodeTypeId.VFUNC) {
1035 var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name), true);
1036 if (m != null) {
1037 iface.add_method (m);
1039 } else if (member.type == IdlNodeTypeId.PROPERTY) {
1040 var prop = parse_property ((IdlNodeProperty) member);
1041 if (prop != null) {
1042 iface.add_property (prop);
1044 } else if (member.type == IdlNodeTypeId.SIGNAL) {
1045 var sig = parse_signal ((IdlNodeSignal) member);
1046 if (sig != null) {
1047 iface.add_signal (sig);
1052 current_data_type = null;
1055 private DataType? parse_type (IdlNodeType type_node, out ParameterDirection direction = null) {
1056 ParameterDirection dir = ParameterDirection.IN;
1058 var type = new UnresolvedType ();
1059 if (type_node.tag == TypeTag.VOID) {
1060 if (type_node.is_pointer) {
1061 return new PointerType (new VoidType ());
1062 } else {
1063 return new VoidType ();
1065 } else if (type_node.tag == TypeTag.BOOLEAN) {
1066 type.unresolved_symbol = new UnresolvedSymbol (null, "bool");
1067 } else if (type_node.tag == TypeTag.INT8) {
1068 type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1069 } else if (type_node.tag == TypeTag.UINT8) {
1070 type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1071 } else if (type_node.tag == TypeTag.INT16) {
1072 type.unresolved_symbol = new UnresolvedSymbol (null, "int16");
1073 } else if (type_node.tag == TypeTag.UINT16) {
1074 type.unresolved_symbol = new UnresolvedSymbol (null, "uint16");
1075 } else if (type_node.tag == TypeTag.INT32) {
1076 type.unresolved_symbol = new UnresolvedSymbol (null, "int32");
1077 } else if (type_node.tag == TypeTag.UINT32) {
1078 type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
1079 } else if (type_node.tag == TypeTag.INT64) {
1080 type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1081 } else if (type_node.tag == TypeTag.UINT64) {
1082 type.unresolved_symbol = new UnresolvedSymbol (null, "uint64");
1083 } else if (type_node.tag == TypeTag.INT) {
1084 type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1085 } else if (type_node.tag == TypeTag.UINT) {
1086 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1087 } else if (type_node.tag == TypeTag.LONG) {
1088 type.unresolved_symbol = new UnresolvedSymbol (null, "long");
1089 } else if (type_node.tag == TypeTag.ULONG) {
1090 type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1091 } else if (type_node.tag == TypeTag.SSIZE) {
1092 type.unresolved_symbol = new UnresolvedSymbol (null, "ssize_t");
1093 } else if (type_node.tag == TypeTag.SIZE) {
1094 type.unresolved_symbol = new UnresolvedSymbol (null, "size_t");
1095 } else if (type_node.tag == TypeTag.FLOAT) {
1096 type.unresolved_symbol = new UnresolvedSymbol (null, "float");
1097 } else if (type_node.tag == TypeTag.DOUBLE) {
1098 type.unresolved_symbol = new UnresolvedSymbol (null, "double");
1099 } else if (type_node.tag == TypeTag.UTF8) {
1100 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1101 } else if (type_node.tag == TypeTag.FILENAME) {
1102 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1103 } else if (type_node.tag == TypeTag.ARRAY) {
1104 var element_type = parse_type (type_node.parameter_type1);
1105 type = element_type as UnresolvedType;
1106 if (type == null) {
1107 return element_type;
1109 return new ArrayType (element_type, 1, element_type.source_reference);
1110 } else if (type_node.tag == TypeTag.LIST) {
1111 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "List");
1112 } else if (type_node.tag == TypeTag.SLIST) {
1113 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "SList");
1114 } else if (type_node.tag == TypeTag.HASH) {
1115 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "HashTable");
1116 } else if (type_node.tag == TypeTag.ERROR) {
1117 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Error");
1118 } else if (type_node.is_interface) {
1119 var n = type_node.@interface;
1121 if (n == "") {
1122 return null;
1125 if (n.has_prefix ("const-")) {
1126 n = n.offset ("const-".len ());
1129 if (type_node.is_pointer &&
1130 (n == "gchar" || n == "char")) {
1131 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1132 if (type_node.unparsed.has_suffix ("**")) {
1133 dir = ParameterDirection.OUT;
1135 } else if (n == "gunichar") {
1136 type.unresolved_symbol = new UnresolvedSymbol (null, "unichar");
1137 } else if (n == "gchar") {
1138 type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1139 } else if (n == "guchar" || n == "guint8") {
1140 type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1141 if (type_node.is_pointer) {
1142 return new ArrayType (type, 1, type.source_reference);
1144 } else if (n == "gushort") {
1145 type.unresolved_symbol = new UnresolvedSymbol (null, "ushort");
1146 } else if (n == "gshort") {
1147 type.unresolved_symbol = new UnresolvedSymbol (null, "short");
1148 } else if (n == "gconstpointer" || n == "void") {
1149 return new PointerType (new VoidType ());
1150 } else if (n == "goffset" || n == "off_t") {
1151 type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1152 } else if (n == "value_array") {
1153 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "ValueArray");
1154 } else if (n == "time_t") {
1155 type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1156 } else if (n == "socklen_t") {
1157 type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
1158 } else if (n == "mode_t") {
1159 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1160 } else if (n == "gint" || n == "pid_t") {
1161 type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1162 } else if (n == "unsigned" || n == "unsigned-int") {
1163 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1164 } else if (n == "FILE") {
1165 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "FileStream");
1166 } else if (n == "struct") {
1167 return new PointerType (new VoidType ());
1168 } else if (n == "iconv_t") {
1169 return new PointerType (new VoidType ());
1170 } else if (n == "GType") {
1171 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Type");
1172 if (type_node.is_pointer) {
1173 return new ArrayType (type, 1, type.source_reference);
1175 } else if (n == "GStrv") {
1176 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1177 return new ArrayType (type, 1, type.source_reference);
1178 } else {
1179 var named_type = parse_type_string (n);
1180 type = named_type as UnresolvedType;
1181 if (type == null) {
1182 return named_type;
1184 if (is_simple_type (n)) {
1185 if (type_node.is_pointer) {
1186 dir = ParameterDirection.OUT;
1188 } else if (type_node.unparsed.has_suffix ("**")) {
1189 dir = ParameterDirection.OUT;
1192 } else {
1193 stdout.printf ("%d\n", type_node.tag);
1195 if (&direction != null) {
1196 direction = dir;
1198 return type;
1201 private bool is_simple_type (string type_name) {
1202 var st = cname_type_map[type_name] as Struct;
1203 if (st != null && st.is_simple_type ()) {
1204 return true;
1207 return false;
1210 private DataType parse_type_string (string n) {
1211 if (n == "va_list") {
1212 // unsupported
1213 return new PointerType (new VoidType ());
1216 var type = new UnresolvedType ();
1218 var dt = cname_type_map[n];
1219 if (dt != null) {
1220 UnresolvedSymbol parent_symbol = null;
1221 if (dt.parent_symbol.name != null) {
1222 parent_symbol = new UnresolvedSymbol (null, dt.parent_symbol.name);
1224 type.unresolved_symbol = new UnresolvedSymbol (parent_symbol, dt.name);
1225 return type;
1228 var type_attributes = get_attributes (n);
1230 string ns_name = null;
1232 if (null != type_attributes) {
1233 foreach (string attr in type_attributes) {
1234 var nv = attr.split ("=", 2);
1236 if (nv[0] == "cprefix") {
1237 type.unresolved_symbol = new UnresolvedSymbol (null, n.offset (eval (nv[1]).len ()));
1238 } else if (nv[0] == "name") {
1239 type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1240 } else if (nv[0] == "namespace") {
1241 ns_name = eval (nv[1]);
1242 } else if (nv[0] == "rename_to") {
1243 type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1248 if (type.unresolved_symbol != null) {
1249 if (type.unresolved_symbol.name == "pointer") {
1250 return new PointerType (new VoidType ());
1252 if (ns_name != null) {
1253 type.unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
1255 return type;
1258 if (n.has_prefix (current_namespace.name)) {
1259 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, current_namespace.name), n.offset (current_namespace.name.len ()));
1260 } else if (n.has_prefix ("G")) {
1261 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), n.offset (1));
1262 } else {
1263 var name_parts = n.split (".", 2);
1264 if (name_parts[1] == null) {
1265 type.unresolved_symbol = new UnresolvedSymbol (null, name_parts[0]);
1266 } else {
1267 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, name_parts[0]), name_parts[1]);
1271 return type;
1274 private DataType? parse_param (IdlNodeParam param, out ParameterDirection direction = null) {
1275 var type = parse_type (param.type, out direction);
1277 // disable for now as null_ok not yet correctly set
1278 // type.non_null = !param.null_ok;
1280 return type;
1283 private Method? create_method (string name, string symbol, IdlNodeParam? res, GLib.List<IdlNodeParam>? parameters, bool is_constructor, bool is_interface) {
1284 DataType return_type = null;
1285 if (res != null) {
1286 return_type = parse_param (res);
1289 Method m;
1290 if (!is_interface && (is_constructor || name.has_prefix ("new"))) {
1291 m = new CreationMethod (null, name, current_source_reference);
1292 m.has_construct_function = false;
1293 if (m.name == "new") {
1294 m.name = null;
1295 } else if (m.name.has_prefix ("new_")) {
1296 m.name = m.name.offset ("new_".len ());
1298 // For classes, check whether a creation method return type equals to the
1299 // type of the class created. If the types do not match (e.g. in most
1300 // gtk widgets) add an attribute to the creation method indicating the used
1301 // return type.
1302 if (current_data_type is Class && res != null) {
1303 if ("%s*".printf (current_data_type.get_cname()) != res.type.unparsed) {
1304 ((CreationMethod)m).custom_return_type_cname = res.type.unparsed;
1307 } else {
1308 m = new Method (name, return_type, current_source_reference);
1310 m.access = SymbolAccessibility.PUBLIC;
1312 if (current_type_symbol_set != null) {
1313 current_type_symbol_set.add (name);
1316 if (current_data_type != null) {
1317 var sig_attributes = get_attributes ("%s::%s".printf (current_data_type.get_cname (), name));
1318 if (sig_attributes != null) {
1319 foreach (string attr in sig_attributes) {
1320 var nv = attr.split ("=", 2);
1321 if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
1322 return null;
1328 bool add_ellipsis = false;
1329 bool suppress_throws = false;
1331 var attributes = get_attributes (symbol);
1332 if (attributes != null) {
1333 foreach (string attr in attributes) {
1334 var nv = attr.split ("=", 2);
1335 if (nv[0] == "name") {
1336 m.set_cname (m.name);
1337 m.name = eval (nv[1]);
1338 } else if (nv[0] == "hidden") {
1339 if (eval (nv[1]) == "1") {
1340 return null;
1342 } else if (nv[0] == "ellipsis") {
1343 if (eval (nv[1]) == "1") {
1344 add_ellipsis = true;
1346 } else if (nv[0] == "transfer_ownership") {
1347 if (eval (nv[1]) == "1") {
1348 return_type.value_owned = true;
1350 } else if (nv[0] == "nullable") {
1351 if (eval (nv[1]) == "1") {
1352 return_type.nullable = true;
1354 } else if (nv[0] == "sentinel") {
1355 m.sentinel = eval (nv[1]);
1356 } else if (nv[0] == "is_array") {
1357 if (eval (nv[1]) == "1") {
1358 return_type = new ArrayType (return_type, 1, return_type.source_reference);
1359 m.return_type = return_type;
1361 } else if (nv[0] == "throws") {
1362 if (eval (nv[1]) == "0") {
1363 suppress_throws = true;
1365 } else if (nv[0] == "no_array_length") {
1366 if (eval (nv[1]) == "1") {
1367 m.no_array_length = true;
1369 } else if (nv[0] == "type_name") {
1370 var sym = new UnresolvedSymbol (null, eval (nv[1]));
1371 if (return_type is UnresolvedType) {
1372 ((UnresolvedType) return_type).unresolved_symbol = sym;
1373 } else {
1374 // Overwrite old return_type, so "type_name" must be before any
1375 // other return type modifying metadata
1376 m.return_type = return_type = new UnresolvedType.from_symbol (sym, return_type.source_reference);
1378 } else if (nv[0] == "type_arguments") {
1379 var type_args = eval (nv[1]).split (",");
1380 foreach (string type_arg in type_args) {
1381 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1382 arg_type.value_owned = true;
1383 return_type.add_type_argument (arg_type);
1385 } else if (nv[0] == "cheader_filename") {
1386 m.add_cheader_filename (eval (nv[1]));
1387 } else if (nv[0] == "abstract") {
1388 if (eval (nv[1]) == "1") {
1389 m.is_abstract = true;
1391 } else if (nv[0] == "virtual") {
1392 if (eval (nv[1]) == "1") {
1393 m.is_virtual = true;
1400 m.set_cname (symbol);
1402 bool first = true;
1403 FormalParameter last_param = null;
1404 DataType last_param_type = null;
1405 foreach (weak IdlNodeParam param in parameters) {
1406 weak IdlNode param_node = (IdlNode) param;
1408 if (first) {
1409 first = false;
1410 if (!(m is CreationMethod) &&
1411 current_data_type != null &&
1412 param.type.is_interface &&
1413 (param_node.name == "self" ||
1414 param.type.@interface.has_suffix (current_data_type.get_cname ()))) {
1415 // instance method
1416 continue;
1417 } else if (!(m is CreationMethod) &&
1418 current_data_type != null &&
1419 param.type.is_interface &&
1420 (param_node.name == "klass" ||
1421 param.type.@interface.has_suffix ("%sClass".printf(current_data_type.get_cname ())))) {
1422 // class method
1423 m.binding = MemberBinding.CLASS;
1424 if (m.name.has_prefix ("class_")) {
1425 m.name = m.name.substring ("class_".len (), m.name.len () - "class_".len ());
1427 continue;
1428 } else {
1429 // static method
1430 m.binding = MemberBinding.STATIC;
1434 if (suppress_throws == false && param_is_exception (param)) {
1435 m.add_error_type (parse_type (param.type));
1436 continue;
1439 string param_name = param_node.name;
1440 if (param_name == "result") {
1441 // avoid conflict with generated result variable
1442 param_name = "_result";
1443 } else if (param_name == "string") {
1444 // avoid conflict with string type
1445 param_name = "str";
1447 ParameterDirection direction;
1448 var param_type = parse_param (param, out direction);
1449 var p = new FormalParameter (param_name, param_type);
1450 p.direction = direction;
1452 bool hide_param = false;
1453 bool show_param = false;
1454 bool set_array_length_pos = false;
1455 double array_length_pos = 0;
1456 bool set_delegate_target_pos = false;
1457 double delegate_target_pos = 0;
1458 bool array_requested = false;
1459 attributes = get_attributes ("%s.%s".printf (symbol, param_node.name));
1460 if (attributes != null) {
1461 foreach (string attr in attributes) {
1462 var nv = attr.split ("=", 2);
1463 if (nv[0] == "is_array") {
1464 if (eval (nv[1]) == "1") {
1465 param_type = new ArrayType (param_type, 1, param_type.source_reference);
1466 p.parameter_type = param_type;
1467 p.direction = ParameterDirection.IN;
1468 array_requested = true;
1470 } else if (nv[0] == "is_out") {
1471 if (eval (nv[1]) == "1") {
1472 p.direction = ParameterDirection.OUT;
1473 if (!array_requested && param_type is ArrayType) {
1474 var array_type = (ArrayType) param_type;
1475 param_type = array_type.element_type;
1476 p.parameter_type = param_type;
1479 } else if (nv[0] == "is_ref") {
1480 if (eval (nv[1]) == "1") {
1481 p.direction = ParameterDirection.REF;
1482 if (!array_requested && param_type is ArrayType) {
1483 var array_type = (ArrayType) param_type;
1484 param_type = array_type.element_type;
1485 p.parameter_type = param_type;
1488 } else if (nv[0] == "nullable") {
1489 if (eval (nv[1]) == "1") {
1490 param_type.nullable = true;
1492 } else if (nv[0] == "transfer_ownership") {
1493 if (eval (nv[1]) == "1") {
1494 param_type.value_owned = true;
1496 } else if (nv[0] == "takes_ownership") {
1497 if (eval (nv[1]) == "1") {
1498 param_type.value_owned = true;
1500 } else if (nv[0] == "value_owned") {
1501 if (eval (nv[1]) == "0") {
1502 param_type.value_owned = false;
1503 } else if (eval (nv[1]) == "1") {
1504 param_type.value_owned = true;
1506 } else if (nv[0] == "hidden") {
1507 if (eval (nv[1]) == "1") {
1508 hide_param = true;
1509 } else if (eval (nv[1]) == "0") {
1510 show_param = true;
1512 } else if (nv[0] == "array_length_pos") {
1513 set_array_length_pos = true;
1514 array_length_pos = eval (nv[1]).to_double ();
1515 } else if (nv[0] == "delegate_target_pos") {
1516 set_delegate_target_pos = true;
1517 delegate_target_pos = eval (nv[1]).to_double ();
1518 } else if (nv[0] == "type_name") {
1519 ((UnresolvedType) param_type).unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1520 } else if (nv[0] == "ctype") {
1521 p.ctype = eval (nv[1]);
1522 } else if (nv[0] == "type_arguments") {
1523 var type_args = eval (nv[1]).split (",");
1524 foreach (string type_arg in type_args) {
1525 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1526 arg_type.value_owned = true;
1527 param_type.add_type_argument (arg_type);
1533 if (last_param != null && p.name == "n_" + last_param.name) {
1534 // last_param is array, p is array length
1535 last_param_type = new ArrayType (last_param_type, 1, last_param_type.source_reference);
1536 last_param.parameter_type = last_param_type;
1537 last_param.direction = ParameterDirection.IN;
1539 // hide array length param
1540 hide_param = true;
1541 } else if (last_param != null && p.name == "user_data") {
1542 // last_param is delegate
1544 // hide deleate target param
1545 hide_param = true;
1548 if (show_param || !hide_param) {
1549 m.add_parameter (p);
1550 if (set_array_length_pos) {
1551 p.carray_length_parameter_position = array_length_pos;
1553 if (set_delegate_target_pos) {
1554 p.cdelegate_target_parameter_position = delegate_target_pos;
1558 last_param = p;
1559 last_param_type = param_type;
1562 if (first) {
1563 // no parameters => static method
1564 m.binding = MemberBinding.STATIC;
1567 if (last_param != null && last_param.name.has_prefix ("first_")) {
1568 last_param.ellipsis = true;
1569 } else if (add_ellipsis) {
1570 m.add_parameter (new FormalParameter.with_ellipsis ());
1573 return m;
1576 private bool param_is_exception (IdlNodeParam param) {
1577 if (!param.type.is_error) {
1578 return false;
1580 var s = param.type.unparsed.chomp ();
1581 if (s.has_suffix ("**")) {
1582 return true;
1584 return false;
1587 private Method? parse_function (IdlNodeFunction f, bool is_interface = false) {
1588 weak IdlNode node = (IdlNode) f;
1590 if (f.deprecated) {
1591 return null;
1594 return create_method (node.name, f.symbol, f.result, f.parameters, f.is_constructor, is_interface);
1597 private Method parse_virtual (IdlNodeVFunc v, IdlNodeFunction? func, bool is_interface = false) {
1598 weak IdlNode node = (IdlNode) v;
1599 string symbol = "%s%s".printf (current_data_type.get_lower_case_cprefix(), node.name);
1601 if (func != null) {
1602 symbol = func.symbol;
1605 Method m = create_method (node.name, symbol, v.result, func != null ? func.parameters : v.parameters, false, is_interface);
1606 if (m != null) {
1607 m.binding = MemberBinding.INSTANCE;
1608 m.is_virtual = !(m.is_abstract || is_interface);
1609 m.is_abstract = m.is_abstract || is_interface;
1611 if (func == null) {
1612 m.attributes.append (new Attribute ("NoWrapper", null));
1616 return m;
1619 private string fix_prop_name (string name) {
1620 var str = new StringBuilder ();
1622 string i = name;
1624 while (i.len () > 0) {
1625 unichar c = i.get_char ();
1626 if (c == '-') {
1627 str.append_c ('_');
1628 } else {
1629 str.append_unichar (c);
1632 i = i.next_char ();
1635 return str.str;
1638 private Property? parse_property (IdlNodeProperty prop_node) {
1639 weak IdlNode node = (IdlNode) prop_node;
1641 if (prop_node.deprecated) {
1642 return null;
1645 if (!prop_node.readable && !prop_node.writable) {
1646 // buggy GIDL definition
1647 prop_node.readable = true;
1648 prop_node.writable = true;
1651 PropertyAccessor get_acc = null;
1652 PropertyAccessor set_acc = null;
1653 if (prop_node.readable) {
1654 get_acc = new PropertyAccessor (true, false, false, null, null);
1656 if (prop_node.writable) {
1657 set_acc = new PropertyAccessor (false, false, false, null, null);
1658 if (prop_node.construct_only) {
1659 set_acc.construction = true;
1660 } else {
1661 set_acc.writable = true;
1662 set_acc.construction = prop_node.@construct;
1666 var prop = new Property (fix_prop_name (node.name), parse_type (prop_node.type), get_acc, set_acc, current_source_reference);
1667 prop.access = SymbolAccessibility.PUBLIC;
1668 prop.interface_only = true;
1670 var attributes = get_attributes ("%s:%s".printf (current_data_type.get_cname (), node.name));
1671 if (attributes != null) {
1672 foreach (string attr in attributes) {
1673 var nv = attr.split ("=", 2);
1674 if (nv[0] == "hidden") {
1675 if (eval (nv[1]) == "1") {
1676 return null;
1678 } else if (nv[0] == "type_arguments") {
1679 var type_args = eval (nv[1]).split (",");
1680 foreach (string type_arg in type_args) {
1681 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1682 arg_type.value_owned = true;
1683 prop.property_type.add_type_argument (arg_type);
1689 if (current_type_symbol_set != null) {
1690 current_type_symbol_set.add (prop.name);
1693 return prop;
1696 private Constant? parse_constant (IdlNodeConstant const_node) {
1697 weak IdlNode node = (IdlNode) const_node;
1699 var type = parse_type (const_node.type);
1700 if (type == null) {
1701 return null;
1704 var c = new Constant (node.name, type, null, current_source_reference);
1706 string[] attributes = get_attributes (node.name);
1707 if (attributes != null) {
1708 foreach (string attr in attributes) {
1709 var nv = attr.split ("=", 2);
1710 if (nv[0] == "cheader_filename") {
1711 c.add_cheader_filename (eval (nv[1]));
1712 } else if (nv[0] == "hidden") {
1713 if (eval (nv[1]) == "1") {
1714 return null;
1720 c.access = SymbolAccessibility.PUBLIC;
1722 return c;
1725 private Field? parse_field (IdlNodeField field_node) {
1726 weak IdlNode node = (IdlNode) field_node;
1727 bool unhidden = false;
1729 var type = parse_type (field_node.type);
1730 if (type == null) {
1731 return null;
1734 string cheader_filename = null;
1735 string ctype = null;
1737 var attributes = get_attributes ("%s.%s".printf (current_data_type.get_cname (), node.name));
1738 if (attributes != null) {
1739 foreach (string attr in attributes) {
1740 var nv = attr.split ("=", 2);
1741 if (nv[0] == "hidden") {
1742 if (eval (nv[1]) == "1") {
1743 return null;
1744 } else {
1745 unhidden = true;
1747 } else if (nv[0] == "is_array") {
1748 if (eval (nv[1]) == "1") {
1749 type = new ArrayType (type, 1, type.source_reference);
1751 } else if (nv[0] == "weak") {
1752 if (eval (nv[1]) == "0") {
1753 type.value_owned = true;
1755 } else if (nv[0] == "type_name") {
1756 ((UnresolvedType) type).unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1757 } else if (nv[0] == "type_arguments") {
1758 var type_args = eval (nv[1]).split (",");
1759 foreach (string type_arg in type_args) {
1760 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1761 arg_type.value_owned = true;
1762 type.add_type_argument (arg_type);
1764 } else if (nv[0] == "cheader_filename") {
1765 cheader_filename = eval (nv[1]);
1766 } else if (nv[0] == "ctype") {
1767 ctype = eval (nv[1]);
1772 if (node.name.has_prefix("_") && !unhidden) {
1773 return null;
1776 if (current_type_symbol_set != null) {
1777 current_type_symbol_set.add (node.name);
1780 string field_name = node.name;
1781 if (field_name == "string") {
1782 // avoid conflict with string type
1783 field_name = "str";
1786 var field = new Field (field_name, type, null, current_source_reference);
1787 field.access = SymbolAccessibility.PUBLIC;
1789 if (field_name != node.name) {
1790 field.set_cname (node.name);
1793 if (ctype != null) {
1794 field.set_ctype (ctype);
1797 if (cheader_filename != null) {
1798 field.add_cheader_filename (cheader_filename);
1801 field.no_array_length = true;
1803 return field;
1806 [NoArrayLength]
1807 private string[]? get_attributes (string codenode) {
1808 var attributes = codenode_attributes_map.get (codenode);
1810 if (attributes == null) {
1811 var dot_required = (null != codenode.chr (-1, '.'));
1812 var colon_required = (null != codenode.chr (-1, ':'));
1814 var pattern_specs = codenode_attributes_patterns.get_keys ();
1815 foreach (PatternSpec* pattern in pattern_specs) {
1816 var pspec = codenode_attributes_patterns[pattern];
1818 if ((dot_required && null == pspec.chr (-1, '.')) ||
1819 (colon_required && null == pspec.chr (-1, ':'))) {
1820 continue;
1823 if (pattern->match_string (codenode)) {
1824 return get_attributes (pspec);
1829 if (attributes == null) {
1830 return null;
1833 return attributes.split (" ");
1836 private string eval (string s) {
1837 return s.offset (1).ndup (s.size () - 2);
1840 private Signal? parse_signal (IdlNodeSignal sig_node) {
1841 weak IdlNode node = (IdlNode) sig_node;
1843 if (sig_node.deprecated || sig_node.result == null) {
1844 return null;
1847 var sig = new Signal (fix_prop_name (node.name), parse_param (sig_node.result), current_source_reference);
1848 sig.access = SymbolAccessibility.PUBLIC;
1850 var attributes = get_attributes ("%s::%s".printf (current_data_type.get_cname (), sig.name));
1851 if (attributes != null) {
1852 foreach (string attr in attributes) {
1853 var nv = attr.split ("=", 2);
1854 if (nv[0] == "name") {
1855 sig.set_cname (sig.name);
1856 sig.name = eval (nv[1]);
1857 } else if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
1858 sig.has_emitter = true;
1859 } else if (nv[0] == "hidden") {
1860 if (eval (nv[1]) == "1") {
1861 return null;
1867 sig.is_virtual = true;
1869 bool first = true;
1871 foreach (weak IdlNodeParam param in sig_node.parameters) {
1872 if (first) {
1873 // ignore implicit first signal parameter (sender)
1874 first = false;
1875 continue;
1878 weak IdlNode param_node = (IdlNode) param;
1880 ParameterDirection direction;
1881 var param_type = parse_param (param, out direction);
1882 var p = new FormalParameter (param_node.name, param_type);
1883 p.direction = direction;
1884 sig.add_parameter (p);
1886 attributes = get_attributes ("%s::%s.%s".printf (current_data_type.get_cname (), sig.name, param_node.name));
1887 if (attributes != null) {
1888 string ns_name = null;
1889 foreach (string attr in attributes) {
1890 var nv = attr.split ("=", 2);
1891 if (nv[0] == "is_array") {
1892 if (eval (nv[1]) == "1") {
1893 param_type = new ArrayType (param_type, 1, param_type.source_reference);
1894 p.parameter_type = param_type;
1895 p.direction = ParameterDirection.IN;
1897 } else if (nv[0] == "is_out") {
1898 if (eval (nv[1]) == "1") {
1899 p.direction = ParameterDirection.OUT;
1901 } else if (nv[0] == "is_ref") {
1902 if (eval (nv[1]) == "1") {
1903 p.direction = ParameterDirection.REF;
1905 } else if (nv[0] == "nullable") {
1906 if (eval (nv[1]) == "1") {
1907 param_type.nullable = true;
1909 } else if (nv[0] == "type_name") {
1910 ((UnresolvedType) param_type).unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1911 } else if (nv[0] == "namespace_name") {
1912 ns_name = eval (nv[1]);
1915 if (ns_name != null) {
1916 ((UnresolvedType) param_type).unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
1921 return sig;