update for 0.4.0 release
[vala-lang.git] / vapigen / valagidlparser.vala
blobb48e5715da23075cfbd16057d6993eccc55e32e7
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 ulong metadata_len;
112 FileUtils.get_contents (metadata_filename, out metadata, out metadata_len);
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.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;
317 uint remaining_params = f_node.parameters.length ();
318 foreach (weak IdlNodeParam param in f_node.parameters) {
319 weak IdlNode param_node = (IdlNode) param;
321 if (check_has_target && remaining_params == 1 && (param_node.name == "user_data" || param_node.name == "data")) {
322 // hide user_data parameter for instance delegates
323 cb.has_target = true;
324 } else {
325 string param_name = param_node.name;
326 if (param_name == "string") {
327 // avoid conflict with string type
328 param_name = "str";
329 } else if (param_name == "self") {
330 // avoid conflict with delegate target
331 param_name = "_self";
334 ParameterDirection direction;
335 var p = new FormalParameter (param_name, parse_param (param, out direction));
336 p.direction = direction;
337 cb.add_parameter (p);
340 remaining_params--;
343 return cb;
346 private bool is_reference_type (string cname) {
347 var st_attributes = get_attributes (cname);
348 if (st_attributes != null) {
349 foreach (string attr in st_attributes) {
350 var nv = attr.split ("=", 2);
351 if (nv[0] == "is_value_type" && eval (nv[1]) == "1") {
352 return false;
356 return true;
359 private void parse_struct (IdlNodeStruct st_node, Namespace ns, IdlModule module) {
360 weak IdlNode node = (IdlNode) st_node;
362 if (st_node.deprecated) {
363 return;
366 string name = fix_type_name (node.name, ns);
368 if (!is_reference_type (node.name)) {
369 var st = ns.scope.lookup (name) as Struct;
370 if (st == null) {
371 st = new Struct (name, current_source_reference);
372 st.access = SymbolAccessibility.PUBLIC;
374 var st_attributes = get_attributes (node.name);
375 if (st_attributes != null) {
376 foreach (string attr in st_attributes) {
377 var nv = attr.split ("=", 2);
378 if (nv[0] == "cheader_filename") {
379 st.add_cheader_filename (eval (nv[1]));
380 } else if (nv[0] == "hidden") {
381 if (eval (nv[1]) == "1") {
382 return;
384 } else if (nv[0] == "simple_type") {
385 if (eval (nv[1]) == "1") {
386 st.set_simple_type (true);
392 ns.add_struct (st);
393 current_source_file.add_node (st);
396 current_data_type = st;
398 foreach (weak IdlNode member in st_node.members) {
399 if (member.type == IdlNodeTypeId.FUNCTION) {
400 var m = parse_function ((IdlNodeFunction) member);
401 if (m != null) {
402 st.add_method (m);
404 } else if (member.type == IdlNodeTypeId.FIELD) {
405 var f = parse_field ((IdlNodeField) member);
406 if (f != null) {
407 st.add_field (f);
412 current_data_type = null;
413 } else {
414 var cl = ns.scope.lookup (name) as Class;
415 if (cl == null) {
416 string base_class = null;
418 cl = new Class (name, current_source_reference);
419 cl.access = SymbolAccessibility.PUBLIC;
420 cl.is_compact = true;
422 var cl_attributes = get_attributes (node.name);
423 if (cl_attributes != null) {
424 foreach (string attr in cl_attributes) {
425 var nv = attr.split ("=", 2);
426 if (nv[0] == "cheader_filename") {
427 cl.add_cheader_filename (eval (nv[1]));
428 } else if (nv[0] == "base_class") {
429 base_class = eval (nv[1]);
430 } else if (nv[0] == "hidden") {
431 if (eval (nv[1]) == "1") {
432 return;
434 } else if (nv[0] == "is_immutable") {
435 if (eval (nv[1]) == "1") {
436 cl.is_immutable = true;
438 } else if (nv[0] == "is_fundamental") {
439 if (eval (nv[1]) == "1") {
440 cl.is_compact = false;
442 } else if (nv[0] == "abstract" && base_class != null) {
443 if (eval (nv[1]) == "1") {
444 cl.is_abstract = true;
450 ns.add_class (cl);
451 current_source_file.add_node (cl);
453 if (base_class != null) {
454 var parent = parse_type_string (base_class);
455 cl.add_base_type (parent);
459 current_data_type = cl;
461 string ref_function = null;
462 string unref_function = null;
463 string copy_function = null;
464 string free_function = null;
466 foreach (weak IdlNode member in st_node.members) {
467 if (member.type == IdlNodeTypeId.FUNCTION) {
468 if (member.name == "ref") {
469 ref_function = ((IdlNodeFunction) member).symbol;
470 } else if (member.name == "unref") {
471 unref_function = ((IdlNodeFunction) member).symbol;
472 } else if (member.name == "free" || member.name == "destroy") {
473 free_function = ((IdlNodeFunction) member).symbol;
474 } else {
475 if (member.name == "copy") {
476 copy_function = ((IdlNodeFunction) member).symbol;
478 var m = parse_function ((IdlNodeFunction) member);
479 if (m != null) {
480 cl.add_method (m);
483 } else if (member.type == IdlNodeTypeId.FIELD) {
484 var f = parse_field ((IdlNodeField) member);
485 if (f != null) {
486 cl.add_field (f);
491 if (ref_function != null) {
492 cl.set_ref_function (ref_function);
494 if (copy_function != null) {
495 cl.set_dup_function (copy_function);
497 if (unref_function != null) {
498 cl.set_unref_function (unref_function);
499 } else if (free_function != null) {
500 cl.set_free_function (free_function);
503 current_data_type = null;
507 private void parse_union (IdlNodeUnion un_node, Namespace ns, IdlModule module) {
508 weak IdlNode node = (IdlNode) un_node;
510 if (un_node.deprecated) {
511 return;
514 string name = fix_type_name (node.name, ns);
516 if (!is_reference_type (node.name)) {
517 var st = ns.scope.lookup (name) as Struct;
518 if (st == null) {
519 st = new Struct (name, current_source_reference);
520 st.access = SymbolAccessibility.PUBLIC;
522 var st_attributes = get_attributes (node.name);
523 if (st_attributes != null) {
524 foreach (string attr in st_attributes) {
525 var nv = attr.split ("=", 2);
526 if (nv[0] == "cheader_filename") {
527 st.add_cheader_filename (eval (nv[1]));
528 } else if (nv[0] == "hidden") {
529 if (eval (nv[1]) == "1") {
530 return;
536 ns.add_struct (st);
537 current_source_file.add_node (st);
540 current_data_type = st;
542 foreach (weak IdlNode member in un_node.members) {
543 if (member.type == IdlNodeTypeId.FUNCTION) {
544 var m = parse_function ((IdlNodeFunction) member);
545 if (m != null) {
546 st.add_method (m);
548 } else if (member.type == IdlNodeTypeId.FIELD) {
549 var f = parse_field ((IdlNodeField) member);
550 if (f != null) {
551 st.add_field (f);
556 current_data_type = null;
557 } else {
558 var cl = ns.scope.lookup (name) as Class;
559 if (cl == null) {
560 cl = new Class (name, current_source_reference);
561 cl.access = SymbolAccessibility.PUBLIC;
562 cl.is_compact = true;
564 var cl_attributes = get_attributes (node.name);
565 if (cl_attributes != null) {
566 foreach (string attr in cl_attributes) {
567 var nv = attr.split ("=", 2);
568 if (nv[0] == "cheader_filename") {
569 cl.add_cheader_filename (eval (nv[1]));
570 } else if (nv[0] == "hidden") {
571 if (eval (nv[1]) == "1") {
572 return;
578 ns.add_class (cl);
579 current_source_file.add_node (cl);
582 current_data_type = cl;
584 string ref_function = null;
585 string unref_function = null;
586 string copy_function = null;
587 string free_function = null;
589 foreach (weak IdlNode member in un_node.members) {
590 if (member.type == IdlNodeTypeId.FUNCTION) {
591 if (member.name == "ref") {
592 ref_function = ((IdlNodeFunction) member).symbol;
593 } else if (member.name == "unref") {
594 unref_function = ((IdlNodeFunction) member).symbol;
595 } else if (member.name == "free" || member.name == "destroy") {
596 free_function = ((IdlNodeFunction) member).symbol;
597 } else {
598 if (member.name == "copy") {
599 copy_function = ((IdlNodeFunction) member).symbol;
601 var m = parse_function ((IdlNodeFunction) member);
602 if (m != null) {
603 cl.add_method (m);
606 } else if (member.type == IdlNodeTypeId.FIELD) {
607 var f = parse_field ((IdlNodeField) member);
608 if (f != null) {
609 cl.add_field (f);
614 if (ref_function != null) {
615 cl.set_ref_function (ref_function);
617 if (copy_function != null) {
618 cl.set_dup_function (copy_function);
620 if (unref_function != null) {
621 cl.set_unref_function (unref_function);
622 } else if (free_function != null) {
623 cl.set_free_function (free_function);
626 current_data_type = null;
630 private void parse_boxed (IdlNodeBoxed boxed_node, Namespace ns, IdlModule module) {
631 weak IdlNode node = (IdlNode) boxed_node;
633 string name = fix_type_name (node.name, ns);
635 var node_attributes = get_attributes (node.name);
636 if (node_attributes != null) {
637 foreach (string attr in node_attributes) {
638 var nv = attr.split ("=", 2);
639 if (nv[0] == "hidden") {
640 return;
645 if (!is_reference_type (node.name)) {
646 var st = ns.scope.lookup (name) as Struct;
647 if (st == null) {
648 st = new Struct (name, current_source_reference);
649 st.access = SymbolAccessibility.PUBLIC;
651 var st_attributes = get_attributes (node.name);
652 if (st_attributes != null) {
653 foreach (string attr in st_attributes) {
654 var nv = attr.split ("=", 2);
655 if (nv[0] == "cheader_filename") {
656 st.add_cheader_filename (eval (nv[1]));
661 ns.add_struct (st);
662 st.set_type_id (st.get_upper_case_cname ("TYPE_"));
663 current_source_file.add_node (st);
666 current_data_type = st;
668 foreach (weak IdlNode member in boxed_node.members) {
669 if (member.type == IdlNodeTypeId.FUNCTION) {
670 var m = parse_function ((IdlNodeFunction) member);
671 if (m != null) {
672 st.add_method (m);
674 } else if (member.type == IdlNodeTypeId.FIELD) {
675 var f = parse_field ((IdlNodeField) member);
676 if (f != null) {
677 st.add_field (f);
682 current_data_type = null;
683 } else {
684 var cl = ns.scope.lookup (name) as Class;
685 if (cl == null) {
686 cl = new Class (name, current_source_reference);
687 cl.access = SymbolAccessibility.PUBLIC;
688 cl.is_compact = true;
690 var cl_attributes = get_attributes (node.name);
691 if (cl_attributes != null) {
692 foreach (string attr in cl_attributes) {
693 var nv = attr.split ("=", 2);
694 if (nv[0] == "cheader_filename") {
695 cl.add_cheader_filename (eval (nv[1]));
696 } else if (nv[0] == "is_immutable") {
697 if (eval (nv[1]) == "1") {
698 cl.is_immutable = true;
704 ns.add_class (cl);
705 cl.set_type_id (cl.get_upper_case_cname ("TYPE_"));
706 current_source_file.add_node (cl);
709 current_data_type = cl;
711 string ref_function = null;
712 string unref_function = null;
713 string copy_function = null;
714 string free_function = null;
716 foreach (weak IdlNode member in boxed_node.members) {
717 if (member.type == IdlNodeTypeId.FUNCTION) {
718 if (member.name == "ref") {
719 ref_function = ((IdlNodeFunction) member).symbol;
720 } else if (member.name == "unref") {
721 unref_function = ((IdlNodeFunction) member).symbol;
722 } else if (member.name == "free" || member.name == "destroy") {
723 free_function = ((IdlNodeFunction) member).symbol;
724 } else {
725 if (member.name == "copy") {
726 copy_function = ((IdlNodeFunction) member).symbol;
728 var m = parse_function ((IdlNodeFunction) member);
729 if (m != null) {
730 cl.add_method (m);
733 } else if (member.type == IdlNodeTypeId.FIELD) {
734 var f = parse_field ((IdlNodeField) member);
735 if (f != null) {
736 cl.add_field (f);
741 if (ref_function != null) {
742 cl.set_ref_function (ref_function);
744 if (copy_function != null) {
745 cl.set_dup_function (copy_function);
747 if (unref_function != null) {
748 cl.set_unref_function (unref_function);
749 } else if (free_function != null) {
750 cl.set_free_function (free_function);
753 current_data_type = null;
757 private TypeSymbol? parse_enum (IdlNodeEnum en_node) {
758 weak IdlNode node = (IdlNode) en_node;
760 var en = new Enum (node.name, current_source_reference);
761 en.access = SymbolAccessibility.PUBLIC;
762 en.has_type_id = (en_node.gtype_name != null && en_node.gtype_name != "");
764 string common_prefix = null;
766 foreach (weak IdlNode value in en_node.values) {
767 if (common_prefix == null) {
768 common_prefix = value.name;
769 while (common_prefix.len () > 0 && !common_prefix.has_suffix ("_")) {
770 // FIXME: could easily be made faster
771 common_prefix = common_prefix.ndup (common_prefix.size () - 1);
773 } else {
774 while (!value.name.has_prefix (common_prefix)) {
775 common_prefix = common_prefix.ndup (common_prefix.size () - 1);
778 while (common_prefix.len () > 0 && (!common_prefix.has_suffix ("_") ||
779 (value.name.offset (common_prefix.size ()).get_char ().isdigit ()) && (value.name.len () - common_prefix.len ()) <= 1)) {
780 // enum values may not consist solely of digits
781 common_prefix = common_prefix.ndup (common_prefix.size () - 1);
785 bool is_errordomain = false;
787 var cheader_filenames = new ArrayList<string> ();
789 var en_attributes = get_attributes (node.name);
790 if (en_attributes != null) {
791 foreach (string attr in en_attributes) {
792 var nv = attr.split ("=", 2);
793 if (nv[0] == "common_prefix") {
794 common_prefix = eval (nv[1]);
795 } else if (nv[0] == "cheader_filename") {
796 cheader_filenames.add (eval (nv[1]));
797 en.add_cheader_filename (eval (nv[1]));
798 } else if (nv[0] == "hidden") {
799 if (eval (nv[1]) == "1") {
800 return null;
802 } else if (nv[0] == "rename_to") {
803 en.name = eval (nv[1]);
804 } else if (nv[0] == "errordomain") {
805 if (eval (nv[1]) == "1") {
806 is_errordomain = true;
812 en.set_cprefix (common_prefix);
814 foreach (weak IdlNode value2 in en_node.values) {
815 var ev = new EnumValue (value2.name.offset (common_prefix.len ()));
816 en.add_value (ev);
819 if (is_errordomain) {
820 var ed = new ErrorDomain (en.name);
821 ed.access = SymbolAccessibility.PUBLIC;
822 ed.set_cprefix (common_prefix);
824 foreach (string filename in cheader_filenames) {
825 ed.add_cheader_filename (filename);
828 foreach (EnumValue ev in en.get_values ()) {
829 ed.add_code (new ErrorCode (ev.name));
832 return ed;
835 return en;
838 private void parse_object (IdlNodeInterface node, Namespace ns, IdlModule module) {
839 string name = fix_type_name (((IdlNode) node).name, ns);
841 string base_class = null;
843 var cl = ns.scope.lookup (name) as Class;
844 if (cl == null) {
845 cl = new Class (name, current_source_reference);
846 cl.access = SymbolAccessibility.PUBLIC;
848 var attributes = get_attributes (node.gtype_name);
849 if (attributes != null) {
850 foreach (string attr in attributes) {
851 var nv = attr.split ("=", 2);
852 if (nv[0] == "cheader_filename") {
853 cl.add_cheader_filename (eval (nv[1]));
854 } else if (nv[0] == "base_class") {
855 base_class = eval (nv[1]);
856 } else if (nv[0] == "hidden") {
857 if (eval (nv[1]) == "1") {
858 return;
860 } else if (nv[0] == "type_check_function") {
861 cl.type_check_function = eval (nv[1]);
862 } else if (nv[0] == "abstract") {
863 if (eval (nv[1]) == "1") {
864 cl.is_abstract = true;
870 ns.add_class (cl);
871 current_source_file.add_node (cl);
874 if (base_class != null) {
875 var parent = parse_type_string (base_class);
876 cl.add_base_type (parent);
877 } else if (node.parent != null) {
878 var parent = parse_type_string (node.parent);
879 cl.add_base_type (parent);
880 } else {
881 var gobject_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Object");
882 cl.add_base_type (new UnresolvedType.from_symbol (gobject_symbol));
885 foreach (string iface_name in node.interfaces) {
886 var iface = parse_type_string (iface_name);
887 cl.add_base_type (iface);
890 current_data_type = cl;
892 current_type_symbol_set = new HashSet<string> (str_hash, str_equal);
893 var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
894 var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
896 foreach (weak IdlNode member in node.members) {
897 if (member.type == IdlNodeTypeId.FUNCTION) {
898 current_type_func_map.set (member.name, (IdlNodeFunction) member);
900 if (member.type == IdlNodeTypeId.VFUNC) {
901 current_type_vfunc_map.set (member.name, "1");
905 foreach (weak IdlNode member in node.members) {
906 if (member.type == IdlNodeTypeId.FUNCTION) {
907 // Ignore if vfunc (handled below)
908 if (!current_type_vfunc_map.contains (member.name)) {
909 var m = parse_function ((IdlNodeFunction) member);
910 if (m != null) {
911 cl.add_method (m);
914 } else if (member.type == IdlNodeTypeId.VFUNC) {
915 var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name));
916 if (m != null) {
917 cl.add_method (m);
919 } else if (member.type == IdlNodeTypeId.PROPERTY) {
920 var prop = parse_property ((IdlNodeProperty) member);
921 if (prop != null) {
922 cl.add_property (prop);
924 } else if (member.type == IdlNodeTypeId.SIGNAL) {
925 var sig = parse_signal ((IdlNodeSignal) member);
926 if (sig != null) {
927 cl.add_signal (sig);
932 foreach (weak IdlNode member in node.members) {
933 if (member.type == IdlNodeTypeId.FIELD) {
934 if (!current_type_symbol_set.contains (member.name)) {
935 var f = parse_field ((IdlNodeField) member);
936 if (f != null) {
937 cl.add_field (f);
943 foreach (Property prop in cl.get_properties ()) {
944 var getter = "get_%s".printf (prop.name);
946 if (prop.get_accessor != null && !current_type_symbol_set.contains (getter)) {
947 prop.no_accessor_method = true;
950 var setter = "set_%s".printf (prop.name);
952 if (prop.set_accessor != null && !current_type_symbol_set.contains (setter)) {
953 prop.no_accessor_method = true;
957 current_data_type = null;
958 current_type_symbol_set = null;
961 private void parse_interface (IdlNodeInterface node, Namespace ns, IdlModule module) {
962 string name = fix_type_name (node.gtype_name, ns);
964 var iface = ns.scope.lookup (name) as Interface;
965 if (iface == null) {
966 iface = new Interface (name, current_source_reference);
967 iface.access = SymbolAccessibility.PUBLIC;
969 var attributes = get_attributes (node.gtype_name);
970 if (attributes != null) {
971 foreach (string attr in attributes) {
972 var nv = attr.split ("=", 2);
973 if (nv[0] == "cheader_filename") {
974 iface.add_cheader_filename (eval (nv[1]));
975 } else if (nv[0] == "lower_case_csuffix") {
976 iface.set_lower_case_csuffix (eval (nv[1]));
981 foreach (string prereq_name in node.prerequisites) {
982 var prereq = parse_type_string (prereq_name);
983 iface.add_prerequisite (prereq);
986 ns.add_interface (iface);
987 current_source_file.add_node (iface);
990 current_data_type = iface;
992 var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
993 var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
995 foreach (weak IdlNode member in node.members) {
996 if (member.type == IdlNodeTypeId.FUNCTION) {
997 current_type_func_map.set (member.name, (IdlNodeFunction) member);
999 if (member.type == IdlNodeTypeId.VFUNC) {
1000 current_type_vfunc_map.set (member.name, "1");
1004 foreach (weak IdlNode member in node.members) {
1005 if (member.type == IdlNodeTypeId.FUNCTION) {
1006 // Ignore if vfunc (handled below)
1007 if (!current_type_vfunc_map.contains (member.name)) {
1008 var m = parse_function ((IdlNodeFunction) member, true);
1009 if (m != null) {
1010 iface.add_method (m);
1013 } else if (member.type == IdlNodeTypeId.VFUNC) {
1014 var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name), true);
1015 if (m != null) {
1016 iface.add_method (m);
1018 } else if (member.type == IdlNodeTypeId.PROPERTY) {
1019 var prop = parse_property ((IdlNodeProperty) member);
1020 if (prop != null) {
1021 iface.add_property (prop);
1023 } else if (member.type == IdlNodeTypeId.SIGNAL) {
1024 var sig = parse_signal ((IdlNodeSignal) member);
1025 if (sig != null) {
1026 iface.add_signal (sig);
1031 current_data_type = null;
1034 private DataType? parse_type (IdlNodeType type_node, out ParameterDirection direction = null) {
1035 ParameterDirection dir = ParameterDirection.IN;
1037 var type = new UnresolvedType ();
1038 if (type_node.tag == TypeTag.VOID) {
1039 if (type_node.is_pointer) {
1040 return new PointerType (new VoidType ());
1041 } else {
1042 return new VoidType ();
1044 } else if (type_node.tag == TypeTag.BOOLEAN) {
1045 type.unresolved_symbol = new UnresolvedSymbol (null, "bool");
1046 } else if (type_node.tag == TypeTag.INT8) {
1047 type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1048 } else if (type_node.tag == TypeTag.UINT8) {
1049 type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1050 } else if (type_node.tag == TypeTag.INT16) {
1051 type.unresolved_symbol = new UnresolvedSymbol (null, "short");
1052 } else if (type_node.tag == TypeTag.UINT16) {
1053 type.unresolved_symbol = new UnresolvedSymbol (null, "ushort");
1054 } else if (type_node.tag == TypeTag.INT32) {
1055 type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1056 } else if (type_node.tag == TypeTag.UINT32) {
1057 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1058 } else if (type_node.tag == TypeTag.INT64) {
1059 type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1060 } else if (type_node.tag == TypeTag.UINT64) {
1061 type.unresolved_symbol = new UnresolvedSymbol (null, "uint64");
1062 } else if (type_node.tag == TypeTag.INT) {
1063 type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1064 } else if (type_node.tag == TypeTag.UINT) {
1065 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1066 } else if (type_node.tag == TypeTag.LONG) {
1067 type.unresolved_symbol = new UnresolvedSymbol (null, "long");
1068 } else if (type_node.tag == TypeTag.ULONG) {
1069 type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1070 } else if (type_node.tag == TypeTag.SSIZE) {
1071 type.unresolved_symbol = new UnresolvedSymbol (null, "long");
1072 } else if (type_node.tag == TypeTag.SIZE) {
1073 type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1074 } else if (type_node.tag == TypeTag.FLOAT) {
1075 type.unresolved_symbol = new UnresolvedSymbol (null, "float");
1076 } else if (type_node.tag == TypeTag.DOUBLE) {
1077 type.unresolved_symbol = new UnresolvedSymbol (null, "double");
1078 } else if (type_node.tag == TypeTag.UTF8) {
1079 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1080 } else if (type_node.tag == TypeTag.FILENAME) {
1081 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1082 } else if (type_node.tag == TypeTag.ARRAY) {
1083 var element_type = parse_type (type_node.parameter_type1);
1084 type = element_type as UnresolvedType;
1085 if (type == null) {
1086 return element_type;
1088 return new ArrayType (element_type, 1, element_type.source_reference);
1089 } else if (type_node.tag == TypeTag.LIST) {
1090 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "List");
1091 } else if (type_node.tag == TypeTag.SLIST) {
1092 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "SList");
1093 } else if (type_node.tag == TypeTag.HASH) {
1094 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "HashTable");
1095 } else if (type_node.tag == TypeTag.ERROR) {
1096 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Error");
1097 } else if (type_node.is_interface) {
1098 var n = type_node.@interface;
1100 if (n == "") {
1101 return null;
1104 if (n.has_prefix ("const-")) {
1105 n = n.offset ("const-".len ());
1108 if (type_node.is_pointer &&
1109 (n == "gchar" || n == "char")) {
1110 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1111 if (type_node.unparsed.has_suffix ("**")) {
1112 dir = ParameterDirection.OUT;
1114 } else if (n == "gunichar") {
1115 type.unresolved_symbol = new UnresolvedSymbol (null, "unichar");
1116 } else if (n == "gchar") {
1117 type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1118 } else if (n == "guchar" || n == "guint8") {
1119 type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1120 if (type_node.is_pointer) {
1121 return new ArrayType (type, 1, type.source_reference);
1123 } else if (n == "gushort") {
1124 type.unresolved_symbol = new UnresolvedSymbol (null, "ushort");
1125 } else if (n == "gshort") {
1126 type.unresolved_symbol = new UnresolvedSymbol (null, "short");
1127 } else if (n == "gconstpointer" || n == "void") {
1128 return new PointerType (new VoidType ());
1129 } else if (n == "goffset" || n == "off_t") {
1130 type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1131 } else if (n == "value_array") {
1132 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "ValueArray");
1133 } else if (n == "time_t") {
1134 type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1135 } else if (n == "socklen_t") {
1136 type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
1137 } else if (n == "mode_t") {
1138 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1139 } else if (n == "gint" || n == "pid_t") {
1140 type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1141 } else if (n == "unsigned" || n == "unsigned-int") {
1142 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1143 } else if (n == "FILE") {
1144 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "FileStream");
1145 } else if (n == "struct") {
1146 return new PointerType (new VoidType ());
1147 } else if (n == "iconv_t") {
1148 return new PointerType (new VoidType ());
1149 } else if (n == "GType") {
1150 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Type");
1151 if (type_node.is_pointer) {
1152 return new ArrayType (type, 1, type.source_reference);
1154 } else if (n == "GStrv") {
1155 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1156 return new ArrayType (type, 1, type.source_reference);
1157 } else {
1158 var named_type = parse_type_string (n);
1159 type = named_type as UnresolvedType;
1160 if (type == null) {
1161 return named_type;
1163 if (is_simple_type (n)) {
1164 if (type_node.is_pointer) {
1165 dir = ParameterDirection.OUT;
1167 } else if (type_node.unparsed.has_suffix ("**")) {
1168 dir = ParameterDirection.OUT;
1171 } else {
1172 stdout.printf ("%d\n", type_node.tag);
1174 if (&direction != null) {
1175 direction = dir;
1177 return type;
1180 private bool is_simple_type (string type_name) {
1181 var st = cname_type_map[type_name] as Struct;
1182 if (st != null && st.is_simple_type ()) {
1183 return true;
1186 return false;
1189 private DataType parse_type_string (string n) {
1190 if (n == "va_list") {
1191 // unsupported
1192 return new PointerType (new VoidType ());
1195 var type = new UnresolvedType ();
1197 var dt = cname_type_map[n];
1198 if (dt != null) {
1199 UnresolvedSymbol parent_symbol = null;
1200 if (dt.parent_symbol.name != null) {
1201 parent_symbol = new UnresolvedSymbol (null, dt.parent_symbol.name);
1203 type.unresolved_symbol = new UnresolvedSymbol (parent_symbol, dt.name);
1204 return type;
1207 var type_attributes = get_attributes (n);
1209 string ns_name = null;
1211 if (null != type_attributes) {
1212 foreach (string attr in type_attributes) {
1213 var nv = attr.split ("=", 2);
1215 if (nv[0] == "cprefix") {
1216 type.unresolved_symbol = new UnresolvedSymbol (null, n.offset (eval (nv[1]).len ()));
1217 } else if (nv[0] == "name") {
1218 type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1219 } else if (nv[0] == "namespace") {
1220 ns_name = eval (nv[1]);
1221 } else if (nv[0] == "rename_to") {
1222 type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1227 if (type.unresolved_symbol != null) {
1228 if (type.unresolved_symbol.name == "pointer") {
1229 return new PointerType (new VoidType ());
1231 if (ns_name != null) {
1232 type.unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
1234 return type;
1237 if (n.has_prefix (current_namespace.name)) {
1238 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, current_namespace.name), n.offset (current_namespace.name.len ()));
1239 } else if (n.has_prefix ("G")) {
1240 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), n.offset (1));
1241 } else {
1242 var name_parts = n.split (".", 2);
1243 if (name_parts[1] == null) {
1244 type.unresolved_symbol = new UnresolvedSymbol (null, name_parts[0]);
1245 } else {
1246 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, name_parts[0]), name_parts[1]);
1250 return type;
1253 private DataType? parse_param (IdlNodeParam param, out ParameterDirection direction = null) {
1254 var type = parse_type (param.type, out direction);
1256 // disable for now as null_ok not yet correctly set
1257 // type.non_null = !param.null_ok;
1259 return type;
1262 private Method? create_method (string name, string symbol, IdlNodeParam? res, GLib.List<IdlNodeParam>? parameters, bool is_constructor, bool is_interface) {
1263 DataType return_type = null;
1264 if (res != null) {
1265 return_type = parse_param (res);
1268 Method m;
1269 if (!is_interface && (is_constructor || name.has_prefix ("new"))) {
1270 m = new CreationMethod (null, name, current_source_reference);
1271 m.has_construct_function = false;
1272 if (m.name == "new") {
1273 m.name = null;
1274 } else if (m.name.has_prefix ("new_")) {
1275 m.name = m.name.offset ("new_".len ());
1277 // For classes, check whether a creation method return type equals to the
1278 // type of the class created. If the types do not match (e.g. in most
1279 // gtk widgets) add an attribute to the creation method indicating the used
1280 // return type.
1281 if (current_data_type is Class && res != null) {
1282 if ("%s*".printf (current_data_type.get_cname()) != res.type.unparsed) {
1283 ((CreationMethod)m).custom_return_type_cname = res.type.unparsed;
1286 } else {
1287 m = new Method (name, return_type, current_source_reference);
1289 m.access = SymbolAccessibility.PUBLIC;
1291 if (current_type_symbol_set != null) {
1292 current_type_symbol_set.add (name);
1295 if (current_data_type != null) {
1296 var sig_attributes = get_attributes ("%s::%s".printf (current_data_type.get_cname (), name));
1297 if (sig_attributes != null) {
1298 foreach (string attr in sig_attributes) {
1299 var nv = attr.split ("=", 2);
1300 if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
1301 return null;
1307 bool add_ellipsis = false;
1308 bool suppress_throws = false;
1310 var attributes = get_attributes (symbol);
1311 if (attributes != null) {
1312 foreach (string attr in attributes) {
1313 var nv = attr.split ("=", 2);
1314 if (nv[0] == "name") {
1315 m.set_cname (m.name);
1316 m.name = eval (nv[1]);
1317 } else if (nv[0] == "hidden") {
1318 if (eval (nv[1]) == "1") {
1319 return null;
1321 } else if (nv[0] == "ellipsis") {
1322 if (eval (nv[1]) == "1") {
1323 add_ellipsis = true;
1325 } else if (nv[0] == "transfer_ownership") {
1326 if (eval (nv[1]) == "1") {
1327 return_type.value_owned = true;
1329 } else if (nv[0] == "nullable") {
1330 if (eval (nv[1]) == "1") {
1331 return_type.nullable = true;
1333 } else if (nv[0] == "sentinel") {
1334 m.sentinel = eval (nv[1]);
1335 } else if (nv[0] == "is_array") {
1336 if (eval (nv[1]) == "1") {
1337 return_type = new ArrayType (return_type, 1, return_type.source_reference);
1338 m.return_type = return_type;
1340 } else if (nv[0] == "throws") {
1341 if (eval (nv[1]) == "0") {
1342 suppress_throws = true;
1344 } else if (nv[0] == "no_array_length") {
1345 if (eval (nv[1]) == "1") {
1346 m.no_array_length = true;
1348 } else if (nv[0] == "type_name") {
1349 var sym = new UnresolvedSymbol (null, eval (nv[1]));
1350 if (return_type is UnresolvedType) {
1351 ((UnresolvedType) return_type).unresolved_symbol = sym;
1352 } else {
1353 // Overwrite old return_type, so "type_name" must be before any
1354 // other return type modifying metadata
1355 m.return_type = return_type = new UnresolvedType.from_symbol (sym, return_type.source_reference);
1357 } else if (nv[0] == "type_arguments") {
1358 var type_args = eval (nv[1]).split (",");
1359 foreach (string type_arg in type_args) {
1360 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1361 arg_type.value_owned = true;
1362 return_type.add_type_argument (arg_type);
1364 } else if (nv[0] == "cheader_filename") {
1365 m.add_cheader_filename (eval (nv[1]));
1366 } else if (nv[0] == "abstract") {
1367 if (eval (nv[1]) == "1") {
1368 m.is_abstract = true;
1370 } else if (nv[0] == "virtual") {
1371 if (eval (nv[1]) == "1") {
1372 m.is_virtual = true;
1379 m.set_cname (symbol);
1381 bool first = true;
1382 FormalParameter last_param = null;
1383 DataType last_param_type = null;
1384 foreach (weak IdlNodeParam param in parameters) {
1385 weak IdlNode param_node = (IdlNode) param;
1387 if (first) {
1388 first = false;
1389 if (!(m is CreationMethod) &&
1390 current_data_type != null &&
1391 param.type.is_interface &&
1392 (param_node.name == "self" ||
1393 param.type.@interface.has_suffix (current_data_type.get_cname ()))) {
1394 // instance method
1395 continue;
1396 } else if (!(m is CreationMethod) &&
1397 current_data_type != null &&
1398 param.type.is_interface &&
1399 (param_node.name == "klass" ||
1400 param.type.@interface.has_suffix ("%sClass".printf(current_data_type.get_cname ())))) {
1401 // class method
1402 m.binding = MemberBinding.CLASS;
1403 if (m.name.has_prefix ("class_")) {
1404 m.name = m.name.substring ("class_".len (), m.name.len () - "class_".len ());
1406 continue;
1407 } else {
1408 // static method
1409 m.binding = MemberBinding.STATIC;
1413 if (suppress_throws == false && param_is_exception (param)) {
1414 m.add_error_type (parse_type (param.type));
1415 continue;
1418 string param_name = param_node.name;
1419 if (param_name == "result") {
1420 // avoid conflict with generated result variable
1421 param_name = "_result";
1422 } else if (param_name == "string") {
1423 // avoid conflict with string type
1424 param_name = "str";
1426 ParameterDirection direction;
1427 var param_type = parse_param (param, out direction);
1428 var p = new FormalParameter (param_name, param_type);
1429 p.direction = direction;
1431 bool hide_param = false;
1432 bool show_param = false;
1433 bool set_array_length_pos = false;
1434 double array_length_pos = 0;
1435 bool set_delegate_target_pos = false;
1436 double delegate_target_pos = 0;
1437 bool array_requested = false;
1438 var attributes = get_attributes ("%s.%s".printf (symbol, param_node.name));
1439 if (attributes != null) {
1440 foreach (string attr in attributes) {
1441 var nv = attr.split ("=", 2);
1442 if (nv[0] == "is_array") {
1443 if (eval (nv[1]) == "1") {
1444 param_type = new ArrayType (param_type, 1, param_type.source_reference);
1445 p.parameter_type = param_type;
1446 p.direction = ParameterDirection.IN;
1447 array_requested = true;
1449 } else if (nv[0] == "is_out") {
1450 if (eval (nv[1]) == "1") {
1451 p.direction = ParameterDirection.OUT;
1452 if (!array_requested && param_type is ArrayType) {
1453 var array_type = (ArrayType) param_type;
1454 param_type = array_type.element_type;
1455 p.parameter_type = param_type;
1458 } else if (nv[0] == "is_ref") {
1459 if (eval (nv[1]) == "1") {
1460 p.direction = ParameterDirection.REF;
1461 if (!array_requested && param_type is ArrayType) {
1462 var array_type = (ArrayType) param_type;
1463 param_type = array_type.element_type;
1464 p.parameter_type = param_type;
1467 } else if (nv[0] == "nullable") {
1468 if (eval (nv[1]) == "1") {
1469 param_type.nullable = true;
1471 } else if (nv[0] == "transfer_ownership") {
1472 if (eval (nv[1]) == "1") {
1473 param_type.value_owned = true;
1475 } else if (nv[0] == "takes_ownership") {
1476 if (eval (nv[1]) == "1") {
1477 param_type.value_owned = true;
1479 } else if (nv[0] == "value_owned") {
1480 if (eval (nv[1]) == "0") {
1481 param_type.value_owned = false;
1482 } else if (eval (nv[1]) == "1") {
1483 param_type.value_owned = true;
1485 } else if (nv[0] == "hidden") {
1486 if (eval (nv[1]) == "1") {
1487 hide_param = true;
1488 } else if (eval (nv[1]) == "0") {
1489 show_param = true;
1491 } else if (nv[0] == "array_length_pos") {
1492 set_array_length_pos = true;
1493 array_length_pos = eval (nv[1]).to_double ();
1494 } else if (nv[0] == "delegate_target_pos") {
1495 set_delegate_target_pos = true;
1496 delegate_target_pos = eval (nv[1]).to_double ();
1497 } else if (nv[0] == "type_name") {
1498 ((UnresolvedType) param_type).unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1499 } else if (nv[0] == "ctype") {
1500 p.ctype = eval (nv[1]);
1501 } else if (nv[0] == "type_arguments") {
1502 var type_args = eval (nv[1]).split (",");
1503 foreach (string type_arg in type_args) {
1504 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1505 arg_type.value_owned = true;
1506 param_type.add_type_argument (arg_type);
1512 if (last_param != null && p.name == "n_" + last_param.name) {
1513 // last_param is array, p is array length
1514 last_param_type = new ArrayType (last_param_type, 1, last_param_type.source_reference);
1515 last_param.parameter_type = last_param_type;
1516 last_param.direction = ParameterDirection.IN;
1518 // hide array length param
1519 hide_param = true;
1520 } else if (last_param != null && p.name == "user_data") {
1521 // last_param is delegate
1523 // hide deleate target param
1524 hide_param = true;
1527 if (show_param || !hide_param) {
1528 m.add_parameter (p);
1529 if (set_array_length_pos) {
1530 p.carray_length_parameter_position = array_length_pos;
1532 if (set_delegate_target_pos) {
1533 p.cdelegate_target_parameter_position = delegate_target_pos;
1537 last_param = p;
1538 last_param_type = param_type;
1541 if (first) {
1542 // no parameters => static method
1543 m.binding = MemberBinding.STATIC;
1546 if (last_param != null && last_param.name.has_prefix ("first_")) {
1547 last_param.ellipsis = true;
1548 } else if (add_ellipsis) {
1549 m.add_parameter (new FormalParameter.with_ellipsis ());
1552 return m;
1555 private bool param_is_exception (IdlNodeParam param) {
1556 if (!param.type.is_error) {
1557 return false;
1559 var s = param.type.unparsed.chomp ();
1560 if (s.has_suffix ("**")) {
1561 return true;
1563 return false;
1566 private Method? parse_function (IdlNodeFunction f, bool is_interface = false) {
1567 weak IdlNode node = (IdlNode) f;
1569 if (f.deprecated) {
1570 return null;
1573 return create_method (node.name, f.symbol, f.result, f.parameters, f.is_constructor, is_interface);
1576 private Method parse_virtual (IdlNodeVFunc v, IdlNodeFunction? func, bool is_interface = false) {
1577 weak IdlNode node = (IdlNode) v;
1578 string symbol = "%s%s".printf (current_data_type.get_lower_case_cprefix(), node.name);
1580 if (func != null) {
1581 symbol = func.symbol;
1584 Method m = create_method (node.name, symbol, v.result, func != null ? func.parameters : v.parameters, false, is_interface);
1585 if (m != null) {
1586 m.binding = MemberBinding.INSTANCE;
1587 m.is_virtual = !(m.is_abstract || is_interface);
1588 m.is_abstract = m.is_abstract || is_interface;
1590 if (func == null) {
1591 m.attributes.append (new Attribute ("NoWrapper", null));
1595 return m;
1598 private string fix_prop_name (string name) {
1599 var str = new StringBuilder ();
1601 string i = name;
1603 while (i.len () > 0) {
1604 unichar c = i.get_char ();
1605 if (c == '-') {
1606 str.append_c ('_');
1607 } else {
1608 str.append_unichar (c);
1611 i = i.next_char ();
1614 return str.str;
1617 private Property? parse_property (IdlNodeProperty prop_node) {
1618 weak IdlNode node = (IdlNode) prop_node;
1620 if (prop_node.deprecated) {
1621 return null;
1624 if (!prop_node.readable && !prop_node.writable) {
1625 // buggy GIDL definition
1626 prop_node.readable = true;
1627 prop_node.writable = true;
1630 PropertyAccessor get_acc = null;
1631 PropertyAccessor set_acc = null;
1632 if (prop_node.readable) {
1633 get_acc = new PropertyAccessor (true, false, false, null, null);
1635 if (prop_node.writable) {
1636 set_acc = new PropertyAccessor (false, false, false, null, null);
1637 if (prop_node.construct_only) {
1638 set_acc.construction = true;
1639 } else {
1640 set_acc.writable = true;
1641 set_acc.construction = prop_node.@construct;
1645 var prop = new Property (fix_prop_name (node.name), parse_type (prop_node.type), get_acc, set_acc, current_source_reference);
1646 prop.access = SymbolAccessibility.PUBLIC;
1647 prop.interface_only = true;
1649 var attributes = get_attributes ("%s:%s".printf (current_data_type.get_cname (), node.name));
1650 if (attributes != null) {
1651 foreach (string attr in attributes) {
1652 var nv = attr.split ("=", 2);
1653 if (nv[0] == "hidden") {
1654 if (eval (nv[1]) == "1") {
1655 return null;
1657 } else if (nv[0] == "type_arguments") {
1658 var type_args = eval (nv[1]).split (",");
1659 foreach (string type_arg in type_args) {
1660 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1661 arg_type.value_owned = true;
1662 prop.property_type.add_type_argument (arg_type);
1668 if (current_type_symbol_set != null) {
1669 current_type_symbol_set.add (prop.name);
1672 return prop;
1675 private Constant? parse_constant (IdlNodeConstant const_node) {
1676 weak IdlNode node = (IdlNode) const_node;
1678 var type = parse_type (const_node.type);
1679 if (type == null) {
1680 return null;
1683 var c = new Constant (node.name, type, null, current_source_reference);
1685 string[] attributes = get_attributes (node.name);
1686 if (attributes != null) {
1687 foreach (string attr in attributes) {
1688 var nv = attr.split ("=", 2);
1689 if (nv[0] == "cheader_filename") {
1690 c.add_cheader_filename (eval (nv[1]));
1691 } else if (nv[0] == "hidden") {
1692 if (eval (nv[1]) == "1") {
1693 return null;
1699 c.access = SymbolAccessibility.PUBLIC;
1701 return c;
1704 private Field? parse_field (IdlNodeField field_node) {
1705 weak IdlNode node = (IdlNode) field_node;
1706 bool unhidden = false;
1708 var type = parse_type (field_node.type);
1709 if (type == null) {
1710 return null;
1713 string cheader_filename = null;
1714 string ctype = null;
1716 var attributes = get_attributes ("%s.%s".printf (current_data_type.get_cname (), node.name));
1717 if (attributes != null) {
1718 foreach (string attr in attributes) {
1719 var nv = attr.split ("=", 2);
1720 if (nv[0] == "hidden") {
1721 if (eval (nv[1]) == "1") {
1722 return null;
1723 } else {
1724 unhidden = true;
1726 } else if (nv[0] == "is_array") {
1727 if (eval (nv[1]) == "1") {
1728 type = new ArrayType (type, 1, type.source_reference);
1730 } else if (nv[0] == "weak") {
1731 if (eval (nv[1]) == "0") {
1732 type.value_owned = true;
1734 } else if (nv[0] == "type_name") {
1735 ((UnresolvedType) type).unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1736 } else if (nv[0] == "type_arguments") {
1737 var type_args = eval (nv[1]).split (",");
1738 foreach (string type_arg in type_args) {
1739 var arg_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_arg));
1740 arg_type.value_owned = true;
1741 type.add_type_argument (arg_type);
1743 } else if (nv[0] == "cheader_filename") {
1744 cheader_filename = eval (nv[1]);
1745 } else if (nv[0] == "ctype") {
1746 ctype = eval (nv[1]);
1751 if (node.name.has_prefix("_") && !unhidden) {
1752 return null;
1755 if (current_type_symbol_set != null) {
1756 current_type_symbol_set.add (node.name);
1759 string field_name = node.name;
1760 if (field_name == "string") {
1761 // avoid conflict with string type
1762 field_name = "str";
1765 var field = new Field (field_name, type, null, current_source_reference);
1766 field.access = SymbolAccessibility.PUBLIC;
1768 if (field_name != node.name) {
1769 field.set_cname (node.name);
1772 if (ctype != null) {
1773 field.set_ctype (ctype);
1776 if (cheader_filename != null) {
1777 field.add_cheader_filename (cheader_filename);
1780 field.no_array_length = true;
1782 return field;
1785 [NoArrayLength]
1786 private string[]? get_attributes (string codenode) {
1787 var attributes = codenode_attributes_map.get (codenode);
1789 if (attributes == null) {
1790 var dot_required = (null != codenode.chr (-1, '.'));
1791 var colon_required = (null != codenode.chr (-1, ':'));
1793 var pattern_specs = codenode_attributes_patterns.get_keys ();
1794 foreach (PatternSpec* pattern in pattern_specs) {
1795 var pspec = codenode_attributes_patterns[pattern];
1797 if ((dot_required && null == pspec.chr (-1, '.')) ||
1798 (colon_required && null == pspec.chr (-1, ':'))) {
1799 continue;
1802 if (pattern->match_string (codenode)) {
1803 return get_attributes (pspec);
1808 if (attributes == null) {
1809 return null;
1812 return attributes.split (" ");
1815 private string eval (string s) {
1816 return s.offset (1).ndup (s.size () - 2);
1819 private Signal? parse_signal (IdlNodeSignal sig_node) {
1820 weak IdlNode node = (IdlNode) sig_node;
1822 if (sig_node.deprecated || sig_node.result == null) {
1823 return null;
1826 var sig = new Signal (fix_prop_name (node.name), parse_param (sig_node.result), current_source_reference);
1827 sig.access = SymbolAccessibility.PUBLIC;
1829 var attributes = get_attributes ("%s::%s".printf (current_data_type.get_cname (), sig.name));
1830 if (attributes != null) {
1831 foreach (string attr in attributes) {
1832 var nv = attr.split ("=", 2);
1833 if (nv[0] == "name") {
1834 sig.set_cname (sig.name);
1835 sig.name = eval (nv[1]);
1836 } else if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
1837 sig.has_emitter = true;
1838 } else if (nv[0] == "hidden") {
1839 if (eval (nv[1]) == "1") {
1840 return null;
1846 sig.is_virtual = true;
1848 bool first = true;
1850 foreach (weak IdlNodeParam param in sig_node.parameters) {
1851 if (first) {
1852 // ignore implicit first signal parameter (sender)
1853 first = false;
1854 continue;
1857 weak IdlNode param_node = (IdlNode) param;
1859 ParameterDirection direction;
1860 var param_type = parse_param (param, out direction);
1861 var p = new FormalParameter (param_node.name, param_type);
1862 p.direction = direction;
1863 sig.add_parameter (p);
1865 var attributes = get_attributes ("%s::%s.%s".printf (current_data_type.get_cname (), sig.name, param_node.name));
1866 if (attributes != null) {
1867 string ns_name = null;
1868 foreach (string attr in attributes) {
1869 var nv = attr.split ("=", 2);
1870 if (nv[0] == "is_array") {
1871 if (eval (nv[1]) == "1") {
1872 param_type = new ArrayType (param_type, 1, param_type.source_reference);
1873 p.parameter_type = param_type;
1874 p.direction = ParameterDirection.IN;
1876 } else if (nv[0] == "is_out") {
1877 if (eval (nv[1]) == "1") {
1878 p.direction = ParameterDirection.OUT;
1880 } else if (nv[0] == "is_ref") {
1881 if (eval (nv[1]) == "1") {
1882 p.direction = ParameterDirection.REF;
1884 } else if (nv[0] == "nullable") {
1885 if (eval (nv[1]) == "1") {
1886 param_type.nullable = true;
1888 } else if (nv[0] == "type_name") {
1889 ((UnresolvedType) param_type).unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1890 } else if (nv[0] == "namespace_name") {
1891 ns_name = eval (nv[1]);
1894 if (ns_name != null) {
1895 ((UnresolvedType) param_type).unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
1900 return sig;