girparser: Support reparenting static methods in namespace
[vala-lang.git] / vapigen / valagidlparser.vala
blobca185ee4b6f7f4a312aa03cc3a6d0102ef3a806e
1 /* valagidlparser.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using GLib;
27 /**
28 * Code visitor parsing all GIDL files.
30 public class Vala.GIdlParser : CodeVisitor {
31 private CodeContext context;
33 private SourceFile current_source_file;
35 private SourceReference current_source_reference;
37 private Namespace current_namespace;
38 private TypeSymbol current_data_type;
39 private Map<string,string> codenode_attributes_map;
40 private Map<PatternSpec*,string> codenode_attributes_patterns;
41 private Set<string> current_type_symbol_set;
43 private Map<string,TypeSymbol> cname_type_map;
45 static GLib.Regex type_from_string_regex;
47 /**
48 * Parse all source files in the specified code context and build a
49 * code tree.
51 * @param context a code context
53 public void parse (CodeContext context) {
54 cname_type_map = new HashMap<string,TypeSymbol> (str_hash, str_equal);
56 this.context = context;
57 context.accept (this);
59 cname_type_map = null;
62 public override void visit_namespace (Namespace ns) {
63 ns.accept_children (this);
66 public override void visit_class (Class cl) {
67 visit_type (cl);
70 public override void visit_struct (Struct st) {
71 visit_type (st);
74 public override void visit_interface (Interface iface) {
75 visit_type (iface);
78 public override void visit_enum (Enum en) {
79 visit_type (en);
82 public override void visit_error_domain (ErrorDomain ed) {
83 visit_type (ed);
86 public override void visit_delegate (Delegate d) {
87 visit_type (d);
90 private void visit_type (TypeSymbol t) {
91 if (!cname_type_map.contains (t.get_cname ())) {
92 cname_type_map[t.get_cname ()] = t;
96 public override void visit_source_file (SourceFile source_file) {
97 if (source_file.filename.has_suffix (".gi")) {
98 parse_file (source_file);
102 private void parse_file (SourceFile source_file) {
103 string metadata_filename = "%s.metadata".printf (source_file.filename.substring (0, source_file.filename.length - ".gi".length));
105 current_source_file = source_file;
107 codenode_attributes_map = new HashMap<string,string> (str_hash, str_equal);
108 codenode_attributes_patterns = new HashMap<PatternSpec*,string> (direct_hash, (EqualFunc) PatternSpec.equal);
110 if (FileUtils.test (metadata_filename, FileTest.EXISTS)) {
111 try {
112 string metadata;
113 FileUtils.get_contents (metadata_filename, out metadata, null);
115 foreach (string line in metadata.split ("\n")) {
116 if (line.has_prefix ("#")) {
117 // ignore comment lines
118 continue;
121 var tokens = line.split (" ", 2);
123 if (null == tokens[0]) {
124 continue;
127 if (-1 != tokens[0].index_of_char ('*')) {
128 PatternSpec* pattern = new PatternSpec (tokens[0]);
129 codenode_attributes_patterns[pattern] = tokens[0];
132 codenode_attributes_map[tokens[0]] = tokens[1];
134 } catch (FileError e) {
135 Report.error (null, "Unable to read metadata file: %s".printf (e.message));
139 try {
140 var modules = Idl.parse_file (source_file.filename);
142 current_source_reference = new SourceReference (source_file);
144 foreach (weak IdlModule module in modules) {
145 var ns = parse_module (module);
146 if (ns != null) {
147 context.root.add_namespace (ns);
150 } catch (MarkupError e) {
151 Report.error (null, "Unable to parse GIDL file: %s".printf (e.message));
155 private string fix_type_name (string type_name, Symbol container) {
156 var attributes = get_attributes (type_name);
157 if (attributes != null) {
158 foreach (string attr in attributes) {
159 var nv = attr.split ("=", 2);
160 if (nv[0] == "name") {
161 return eval (nv[1]);
166 if (type_name.has_prefix (container.name)) {
167 return type_name.substring (container.name.length);
168 } else if (container.name == "GLib" && type_name.has_prefix ("G")) {
169 return type_name.substring (1);
170 } else {
171 string best_match = null;
172 if (container is Namespace) {
173 foreach (string cprefix in ((Namespace) container).get_cprefixes ()) {
174 if (type_name.has_prefix (cprefix)) {
175 if (best_match == null || cprefix.length > best_match.length)
176 best_match = cprefix;
179 } else {
180 best_match = container.get_cprefix ();
183 if (best_match != null) {
184 return type_name.substring (best_match.length);;
188 return type_name;
191 private string fix_const_name (string const_name, Symbol container) {
192 var pref = container.get_lower_case_cprefix ().up ();
193 if (const_name.has_prefix (pref)) {
194 return const_name.substring (pref.length);
196 return const_name;
199 private string[] get_attributes_for_node (IdlNode node) {
200 string name;
202 if (node.type == IdlNodeTypeId.FUNCTION) {
203 name = ((IdlNodeFunction) node).symbol;
204 } else if (node.type == IdlNodeTypeId.SIGNAL) {
205 name = "%s::%s".printf (current_data_type.get_cname (), node.name);
206 } else if (node.type == IdlNodeTypeId.PROPERTY) {
207 name = "%s:%s".printf (current_data_type.get_cname (), node.name);
208 } else if (node.type == IdlNodeTypeId.FIELD) {
209 name = "%s.%s".printf (current_data_type.get_cname (), node.name);
210 } else {
211 name = node.name;
214 return get_attributes (name);
217 private void add_symbol_to_container (Symbol container, Symbol sym) {
218 if (container is Class) {
219 unowned Class cl = (Class) container;
221 if (sym is Class) {
222 cl.add_class ((Class) sym);
223 } else if (sym is Constant) {
224 cl.add_constant ((Constant) sym);
225 } else if (sym is Enum) {
226 cl.add_enum ((Enum) sym);
227 } else if (sym is Field) {
228 cl.add_field ((Field) sym);
229 } else if (sym is Method) {
230 cl.add_method ((Method) sym);
231 } else if (sym is Property) {
232 cl.add_property ((Property) sym);
233 } else if (sym is Signal) {
234 cl.add_signal ((Signal) sym);
235 } else if (sym is Struct) {
236 cl.add_struct ((Struct) sym);
238 } else if (container is Enum) {
239 unowned Enum en = (Enum) container;
241 if (sym is EnumValue) {
242 en.add_value ((EnumValue) sym);
243 } else if (sym is Constant) {
244 en.add_constant ((Constant) sym);
245 } else if (sym is Method) {
246 en.add_method ((Method) sym);
248 } else if (container is Interface) {
249 unowned Interface iface = (Interface) container;
251 if (sym is Class) {
252 iface.add_class ((Class) sym);
253 } else if (sym is Constant) {
254 iface.add_constant ((Constant) sym);
255 } else if (sym is Enum) {
256 iface.add_enum ((Enum) sym);
257 } else if (sym is Field) {
258 iface.add_field ((Field) sym);
259 } else if (sym is Method) {
260 iface.add_method ((Method) sym);
261 } else if (sym is Property) {
262 iface.add_property ((Property) sym);
263 } else if (sym is Signal) {
264 iface.add_signal ((Signal) sym);
265 } else if (sym is Struct) {
266 iface.add_struct ((Struct) sym);
268 } else if (container is Namespace) {
269 unowned Namespace ns = (Namespace) container;
271 if (sym is Namespace) {
272 ns.add_namespace ((Namespace) sym);
273 } else if (sym is Class) {
274 ns.add_class ((Class) sym);
275 } else if (sym is Constant) {
276 ns.add_constant ((Constant) sym);
277 } else if (sym is Delegate) {
278 ns.add_delegate ((Delegate) sym);
279 } else if (sym is Enum) {
280 ns.add_enum ((Enum) sym);
281 } else if (sym is ErrorDomain) {
282 ns.add_error_domain ((ErrorDomain) sym);
283 } else if (sym is Field) {
284 ns.add_field ((Field) sym);
285 } else if (sym is Interface) {
286 ns.add_interface ((Interface) sym);
287 } else if (sym is Method) {
288 ns.add_method ((Method) sym);
289 } else if (sym is Namespace) {
290 ns.add_namespace ((Namespace) sym);
291 } else if (sym is Struct) {
292 ns.add_struct ((Struct) sym);
294 } else if (container is Struct) {
295 unowned Struct st = (Struct) container;
297 if (sym is Constant) {
298 st.add_constant ((Constant) sym);
299 } else if (sym is Field) {
300 st.add_field ((Field) sym);
301 } else if (sym is Method) {
302 st.add_method ((Method) sym);
303 } else if (sym is Property) {
304 st.add_property ((Property) sym);
309 private void parse_node (IdlNode node, IdlModule module, Symbol container) {
310 if (node.type == IdlNodeTypeId.CALLBACK) {
311 var cb = parse_delegate ((IdlNodeFunction) node);
312 if (cb == null) {
313 return;
315 cb.name = fix_type_name (cb.name, container);
316 add_symbol_to_container (container, cb);
317 current_source_file.add_node (cb);
318 } else if (node.type == IdlNodeTypeId.STRUCT) {
319 parse_struct ((IdlNodeStruct) node, container, module);
320 } else if (node.type == IdlNodeTypeId.UNION) {
321 parse_union ((IdlNodeUnion) node, container, module);
322 } else if (node.type == IdlNodeTypeId.BOXED) {
323 parse_boxed ((IdlNodeBoxed) node, container, module);
324 } else if (node.type == IdlNodeTypeId.ENUM) {
325 parse_enum ((IdlNodeEnum) node, container, module, false);
326 } else if (node.type == IdlNodeTypeId.FLAGS) {
327 parse_enum ((IdlNodeEnum) node, container, module, true);
328 } else if (node.type == IdlNodeTypeId.OBJECT) {
329 parse_object ((IdlNodeInterface) node, container, module);
330 } else if (node.type == IdlNodeTypeId.INTERFACE) {
331 parse_interface ((IdlNodeInterface) node, container, module);
332 } else if (node.type == IdlNodeTypeId.CONSTANT) {
333 var c = parse_constant ((IdlNodeConstant) node);
334 if (c != null) {
335 c.name = fix_const_name (c.name, container);
336 add_symbol_to_container (container, c);
337 current_source_file.add_node (c);
339 } else if (node.type == IdlNodeTypeId.FUNCTION) {
340 var m = parse_function ((IdlNodeFunction) node);
341 if (m != null) {
342 m.binding = MemberBinding.STATIC;
343 add_symbol_to_container (container, m);
344 current_source_file.add_node (m);
349 private Symbol? get_container_from_name (string name) {
350 var path = name.split (".");
351 Symbol? cp = current_namespace;
352 Symbol? cc = null;
354 foreach ( unowned string tok in path ) {
355 cc = cp.scope.lookup (tok) as Symbol;
356 if ( cc == null ) {
357 cc = new Namespace (tok, current_source_reference);
358 ((Namespace) cc).add_cprefix (cp.get_cprefix () + tok);
359 add_symbol_to_container (cp, cc);
361 cp = cc;
364 return cc;
367 private Namespace? parse_module (IdlModule module) {
368 Symbol sym = context.root.scope.lookup (module.name);
369 Namespace ns;
370 if (sym is Namespace) {
371 ns = (Namespace) sym;
372 if (ns.external_package) {
373 ns.attributes = null;
374 ns.source_reference = current_source_reference;
376 } else {
377 ns = new Namespace (module.name, current_source_reference);
380 current_namespace = ns;
382 var attributes = get_attributes (ns.name);
383 if (attributes != null) {
384 foreach (string attr in attributes) {
385 var nv = attr.split ("=", 2);
386 if (nv[0] == "cheader_filename") {
387 ns.set_cheader_filename (eval (nv[1]));
388 } else if (nv[0] == "cprefix") {
389 var cprefixes = eval (nv[1]).split (",");
390 foreach(string name in cprefixes) {
391 ns.add_cprefix (name);
393 } else if (nv[0] == "lower_case_cprefix") {
394 ns.set_lower_case_cprefix (eval (nv[1]));
395 } else if (nv[0] == "gir_namespace") {
396 ns.source_reference.file.gir_namespace = eval (nv[1]);
397 } else if (nv[0] == "gir_version") {
398 ns.source_reference.file.gir_version = eval (nv[1]);
403 var deferred = new ArrayList<unowned IdlNode> ();
405 foreach (weak IdlNode node in module.entries) {
406 bool is_deferred = false;
407 var child_attributes = get_attributes_for_node (node);
408 if (child_attributes != null) {
409 foreach (unowned string attr in child_attributes) {
410 var nv = attr.split ("=", 2);
411 if (nv[0] == "parent") {
412 deferred.add (node);
413 is_deferred = true;
418 if (!is_deferred) {
419 parse_node (node, module, ns);
423 foreach (unowned IdlNode node in deferred) {
424 Symbol container = ns;
425 var child_attributes = get_attributes_for_node (node);
426 if (child_attributes != null) {
427 foreach (unowned string attr in child_attributes) {
428 var nv = attr.split ("=", 2);
429 if (nv[0] == "parent") {
430 container = get_container_from_name (eval (nv[1]));
435 parse_node (node, module, container);
438 current_namespace = null;
440 if (sym is Namespace) {
441 return null;
443 return ns;
446 private Delegate? parse_delegate (IdlNodeFunction f_node) {
447 weak IdlNode node = (IdlNode) f_node;
449 var return_type = parse_param (f_node.result);
451 var cb = new Delegate (node.name, return_type, current_source_reference);
452 cb.access = SymbolAccessibility.PUBLIC;
454 bool check_has_target = true;
456 var attributes = get_attributes (node.name);
457 if (attributes != null) {
458 foreach (string attr in attributes) {
459 var nv = attr.split ("=", 2);
460 if (nv[0] == "hidden") {
461 if (eval (nv[1]) == "1") {
462 return null;
464 } else if (nv[0] == "cheader_filename") {
465 cb.add_cheader_filename (eval (nv[1]));
466 } else if (nv[0] == "has_target") {
467 if (eval (nv[1]) == "0") {
468 check_has_target = false;
469 } else if (eval (nv[1]) == "1") {
470 cb.has_target = true;
472 } else if (nv[0] == "transfer_ownership") {
473 if (eval (nv[1]) == "1") {
474 return_type.value_owned = true;
476 } else if (nv[0] == "deprecated") {
477 if (eval (nv[1]) == "1") {
478 cb.deprecated = true;
480 } else if (nv[0] == "replacement") {
481 cb.replacement = eval (nv[1]);
482 } else if (nv[0] == "deprecated_since") {
483 cb.deprecated_since = eval (nv[1]);
484 } else if (nv[0] == "type_arguments") {
485 parse_type_arguments_from_string (return_type, eval (nv[1]));
486 } else if (nv[0] == "instance_pos") {
487 cb.cinstance_parameter_position = double.parse (eval (nv[1]));
488 } else if (nv[0] == "type_parameters") {
489 foreach (string type_param_name in eval (nv[1]).split (",")) {
490 cb.add_type_parameter (new TypeParameter (type_param_name, current_source_reference));
492 } else if (nv[0] == "experimental") {
493 if (eval (nv[1]) == "1") {
494 cb.experimental = true;
500 uint remaining_params = f_node.parameters.length ();
501 foreach (weak IdlNodeParam param in f_node.parameters) {
502 weak IdlNode param_node = (IdlNode) param;
504 if (check_has_target && remaining_params == 1 && (param_node.name == "user_data" || param_node.name == "data")) {
505 // hide user_data parameter for instance delegates
506 cb.has_target = true;
507 } else {
508 string param_name = param_node.name;
509 if (param_name == "string") {
510 // avoid conflict with string type
511 param_name = "str";
512 } else if (param_name == "self") {
513 // avoid conflict with delegate target
514 param_name = "_self";
517 ParameterDirection direction;
518 var param_type = parse_param (param, out direction);
519 var p = new Parameter (param_name, param_type);
520 p.direction = direction;
522 bool hide_param = false;
523 bool show_param = false;
524 bool array_requested = false;
525 bool out_requested = false;
526 attributes = get_attributes ("%s.%s".printf (node.name, param_node.name));
527 if (attributes != null) {
528 foreach (string attr in attributes) {
529 var nv = attr.split ("=", 2);
530 if (nv[0] == "hidden") {
531 if (eval (nv[1]) == "1") {
532 hide_param = true;
533 } else if (eval (nv[1]) == "0") {
534 show_param = true;
536 } else if (nv[0] == "is_array") {
537 if (eval (nv[1]) == "1") {
538 param_type = new ArrayType (param_type, 1, param_type.source_reference);
539 p.variable_type = param_type;
540 if (!out_requested) {
541 p.direction = ParameterDirection.IN;
543 array_requested = true;
545 } else if (nv[0] == "is_out") {
546 if (eval (nv[1]) == "1") {
547 p.direction = ParameterDirection.OUT;
548 out_requested = true;
549 if (!array_requested && param_type is ArrayType) {
550 var array_type = (ArrayType) param_type;
551 param_type = array_type.element_type;
552 p.variable_type = param_type;
555 } else if (nv[0] == "is_ref") {
556 if (eval (nv[1]) == "1") {
557 p.direction = ParameterDirection.REF;
558 if (!array_requested && param_type is ArrayType) {
559 var array_type = (ArrayType) param_type;
560 param_type = array_type.element_type;
561 p.variable_type = param_type;
564 } else if (nv[0] == "takes_ownership") {
565 if (eval (nv[1]) == "1") {
566 param_type.value_owned = true;
568 } else if (nv[0] == "nullable") {
569 if (eval (nv[1]) == "1") {
570 param_type.nullable = true;
572 } else if (nv[0] == "type_arguments") {
573 parse_type_arguments_from_string (param_type, eval (nv[1]));
574 } else if (nv[0] == "no_array_length") {
575 if (eval (nv[1]) == "1") {
576 p.no_array_length = true;
578 } else if (nv[0] == "array_length_type") {
579 p.array_length_type = eval (nv[1]);
580 } else if (nv[0] == "array_null_terminated") {
581 if (eval (nv[1]) == "1") {
582 p.no_array_length = true;
583 p.array_null_terminated = true;
585 } else if (nv[0] == "type_name") {
586 p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
591 if (show_param || !hide_param) {
592 cb.add_parameter (p);
596 remaining_params--;
599 return cb;
602 private bool is_reference_type (string cname) {
603 var st_attributes = get_attributes (cname);
604 if (st_attributes != null) {
605 foreach (string attr in st_attributes) {
606 var nv = attr.split ("=", 2);
607 if (nv[0] == "is_value_type" && eval (nv[1]) == "1") {
608 return false;
612 return true;
615 private void parse_struct (IdlNodeStruct st_node, Symbol container, IdlModule module) {
616 weak IdlNode node = (IdlNode) st_node;
618 if (st_node.deprecated) {
619 return;
622 string name = fix_type_name (node.name, container);
624 if (!is_reference_type (node.name)) {
625 var st = container.scope.lookup (name) as Struct;
626 if (st == null) {
627 st = new Struct (name, current_source_reference);
628 st.access = SymbolAccessibility.PUBLIC;
630 var st_attributes = get_attributes (node.name);
631 if (st_attributes != null) {
632 foreach (string attr in st_attributes) {
633 var nv = attr.split ("=", 2);
634 if (nv[0] == "cheader_filename") {
635 st.add_cheader_filename (eval (nv[1]));
636 } else if (nv[0] == "hidden") {
637 if (eval (nv[1]) == "1") {
638 return;
640 } else if (nv[0] == "base_type") {
641 st.base_type = parse_type_string (eval (nv[1]));
642 } else if (nv[0] == "rank") {
643 st.set_rank (int.parse (eval (nv[1])));
644 } else if (nv[0] == "simple_type") {
645 if (eval (nv[1]) == "1") {
646 st.set_simple_type (true);
648 } else if (nv[0] == "immutable") {
649 if (eval (nv[1]) == "1") {
650 st.is_immutable = true;
652 } else if (nv[0] == "has_type_id") {
653 if (eval (nv[1]) == "0") {
654 st.has_type_id = false;
656 } else if (nv[0] == "type_id") {
657 st.set_type_id (eval (nv[1]));
658 } else if (nv[0] == "has_copy_function") {
659 if (eval (nv[1]) == "0") {
660 st.has_copy_function = false;
662 } else if (nv[0] == "deprecated") {
663 if (eval (nv[1]) == "1") {
664 st.deprecated = true;
666 } else if (nv[0] == "replacement") {
667 st.replacement = eval (nv[1]);
668 } else if (nv[0] == "deprecated_since") {
669 st.deprecated_since = eval (nv[1]);
670 } else if (nv[0] == "has_destroy_function") {
671 if (eval (nv[1]) == "0") {
672 st.has_destroy_function = false;
674 } else if (nv[0] == "experimental") {
675 if (eval (nv[1]) == "1") {
676 st.experimental = true;
682 add_symbol_to_container (container, st);
683 current_source_file.add_node (st);
686 current_data_type = st;
688 foreach (weak IdlNode member in st_node.members) {
689 if (member.type == IdlNodeTypeId.FUNCTION) {
690 var m = parse_function ((IdlNodeFunction) member);
691 if (m != null) {
692 st.add_method (m);
694 } else if (member.type == IdlNodeTypeId.FIELD) {
695 var f = parse_field ((IdlNodeField) member);
696 if (f != null) {
697 st.add_field (f);
702 current_data_type = null;
703 } else {
704 bool ref_function_void = false;
705 string ref_function = null;
706 string unref_function = null;
707 string copy_function = null;
708 string free_function = null;
710 var cl = container.scope.lookup (name) as Class;
711 if (cl == null) {
712 string base_class = null;
714 cl = new Class (name, current_source_reference);
715 cl.access = SymbolAccessibility.PUBLIC;
716 cl.is_compact = true;
718 var cl_attributes = get_attributes (node.name);
719 if (cl_attributes != null) {
720 foreach (string attr in cl_attributes) {
721 var nv = attr.split ("=", 2);
722 if (nv[0] == "cheader_filename") {
723 cl.add_cheader_filename (eval (nv[1]));
724 } else if (nv[0] == "base_class") {
725 base_class = eval (nv[1]);
726 } else if (nv[0] == "hidden") {
727 if (eval (nv[1]) == "1") {
728 return;
730 } else if (nv[0] == "is_immutable") {
731 if (eval (nv[1]) == "1") {
732 cl.is_immutable = true;
734 } else if (nv[0] == "const_cname") {
735 cl.const_cname = eval (nv[1]);
736 } else if (nv[0] == "is_fundamental") {
737 if (eval (nv[1]) == "1") {
738 cl.is_compact = false;
740 } else if (nv[0] == "abstract" && base_class != null) {
741 if (eval (nv[1]) == "1") {
742 cl.is_abstract = true;
744 } else if (nv[0] == "free_function") {
745 free_function = eval (nv[1]);
746 } else if (nv[0] == "ref_function") {
747 ref_function = eval (nv[1]);
748 } else if (nv[0] == "unref_function") {
749 unref_function = eval (nv[1]);
750 } else if (nv[0] == "copy_function") {
751 copy_function = eval (nv[1]);
752 } else if (nv[0] == "ref_function_void") {
753 if (eval (nv[1]) == "1") {
754 ref_function_void = true;
756 } else if (nv[0] == "deprecated") {
757 if (eval (nv[1]) == "1") {
758 cl.deprecated = true;
760 } else if (nv[0] == "replacement") {
761 cl.replacement = eval (nv[1]);
762 } else if (nv[0] == "deprecated_since") {
763 cl.deprecated_since = eval (nv[1]);
764 } else if (nv[0] == "type_parameters") {
765 foreach (string type_param_name in eval (nv[1]).split (",")) {
766 cl.add_type_parameter (new TypeParameter (type_param_name, current_source_reference));
768 } else if (nv[0] == "experimental") {
769 if (eval (nv[1]) == "1") {
770 cl.experimental = true;
776 add_symbol_to_container (container, cl);
777 current_source_file.add_node (cl);
779 if (base_class != null) {
780 var parent = parse_type_string (base_class);
781 cl.add_base_type (parent);
785 current_data_type = cl;
787 foreach (weak IdlNode member in st_node.members) {
788 if (member.type == IdlNodeTypeId.FUNCTION) {
789 if ((ref_function == null) && (member.name == "ref")) {
790 ref_function = ((IdlNodeFunction) member).symbol;
791 ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
792 } else if ((unref_function == null) && (member.name == "unref")) {
793 unref_function = ((IdlNodeFunction) member).symbol;
794 } else if ((free_function == null) && (member.name == "free" || member.name == "destroy")) {
795 free_function = ((IdlNodeFunction) member).symbol;
796 } else {
797 if ((copy_function == null) && (member.name == "copy")) {
798 copy_function = ((IdlNodeFunction) member).symbol;
800 var m = parse_function ((IdlNodeFunction) member);
801 if (m != null) {
802 cl.add_method (m);
805 } else if (member.type == IdlNodeTypeId.FIELD) {
806 var f = parse_field ((IdlNodeField) member);
807 if (f != null) {
808 cl.add_field (f);
813 if (ref_function != null) {
814 cl.set_ref_function (ref_function);
815 cl.ref_function_void = ref_function_void;
817 if (copy_function != null) {
818 cl.set_dup_function (copy_function);
820 if (unref_function != null) {
821 cl.set_unref_function (unref_function);
822 } else if (free_function != null) {
823 cl.set_free_function (free_function);
826 current_data_type = null;
830 private void parse_union (IdlNodeUnion un_node, Symbol container, IdlModule module) {
831 weak IdlNode node = (IdlNode) un_node;
833 if (un_node.deprecated) {
834 return;
837 string name = fix_type_name (node.name, container);
839 if (!is_reference_type (node.name)) {
840 var st = container.scope.lookup (name) as Struct;
841 if (st == null) {
842 st = new Struct (name, current_source_reference);
843 st.access = SymbolAccessibility.PUBLIC;
845 var st_attributes = get_attributes (node.name);
846 if (st_attributes != null) {
847 foreach (string attr in st_attributes) {
848 var nv = attr.split ("=", 2);
849 if (nv[0] == "cheader_filename") {
850 st.add_cheader_filename (eval (nv[1]));
851 } else if (nv[0] == "deprecated") {
852 if (eval (nv[1]) == "1") {
853 st.deprecated = true;
855 } else if (nv[0] == "replacement") {
856 st.replacement = eval (nv[1]);
857 } else if (nv[0] == "deprecated_since") {
858 st.deprecated_since = eval (nv[1]);
859 } else if (nv[0] == "hidden") {
860 if (eval (nv[1]) == "1") {
861 return;
863 } else if (nv[0] == "experimental") {
864 if (eval (nv[1]) == "1") {
865 st.experimental = true;
871 add_symbol_to_container (container, st);
872 current_source_file.add_node (st);
875 current_data_type = st;
877 foreach (weak IdlNode member in un_node.members) {
878 if (member.type == IdlNodeTypeId.FUNCTION) {
879 var m = parse_function ((IdlNodeFunction) member);
880 if (m != null) {
881 st.add_method (m);
883 } else if (member.type == IdlNodeTypeId.FIELD) {
884 var f = parse_field ((IdlNodeField) member);
885 if (f != null) {
886 st.add_field (f);
891 current_data_type = null;
892 } else {
893 var cl = container.scope.lookup (name) as Class;
894 if (cl == null) {
895 cl = new Class (name, current_source_reference);
896 cl.access = SymbolAccessibility.PUBLIC;
897 cl.is_compact = true;
899 var cl_attributes = get_attributes (node.name);
900 if (cl_attributes != null) {
901 foreach (string attr in cl_attributes) {
902 var nv = attr.split ("=", 2);
903 if (nv[0] == "cheader_filename") {
904 cl.add_cheader_filename (eval (nv[1]));
905 } else if (nv[0] == "hidden") {
906 if (eval (nv[1]) == "1") {
907 return;
913 add_symbol_to_container (container, cl);
914 current_source_file.add_node (cl);
917 current_data_type = cl;
919 bool ref_function_void = false;
920 string ref_function = null;
921 string unref_function = null;
922 string copy_function = null;
923 string free_function = null;
925 foreach (weak IdlNode member in un_node.members) {
926 if (member.type == IdlNodeTypeId.FUNCTION) {
927 if (member.name == "ref") {
928 ref_function = ((IdlNodeFunction) member).symbol;
929 ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
930 } else if (member.name == "unref") {
931 unref_function = ((IdlNodeFunction) member).symbol;
932 } else if (member.name == "free" || member.name == "destroy") {
933 free_function = ((IdlNodeFunction) member).symbol;
934 } else {
935 if (member.name == "copy") {
936 copy_function = ((IdlNodeFunction) member).symbol;
938 var m = parse_function ((IdlNodeFunction) member);
939 if (m != null) {
940 cl.add_method (m);
943 } else if (member.type == IdlNodeTypeId.FIELD) {
944 var f = parse_field ((IdlNodeField) member);
945 if (f != null) {
946 cl.add_field (f);
951 if (ref_function != null) {
952 cl.set_ref_function (ref_function);
953 cl.ref_function_void = ref_function_void;
955 if (copy_function != null) {
956 cl.set_dup_function (copy_function);
958 if (unref_function != null) {
959 cl.set_unref_function (unref_function);
960 } else if (free_function != null) {
961 cl.set_free_function (free_function);
964 current_data_type = null;
968 private void parse_boxed (IdlNodeBoxed boxed_node, Symbol container, IdlModule module) {
969 weak IdlNode node = (IdlNode) boxed_node;
971 string name = fix_type_name (node.name, container);
973 var node_attributes = get_attributes (node.name);
974 if (node_attributes != null) {
975 foreach (string attr in node_attributes) {
976 var nv = attr.split ("=", 2);
977 if (nv[0] == "hidden") {
978 return;
983 if (!is_reference_type (node.name)) {
984 var st = container.scope.lookup (name) as Struct;
985 if (st == null) {
986 st = new Struct (name, current_source_reference);
987 st.access = SymbolAccessibility.PUBLIC;
989 var st_attributes = get_attributes (node.name);
990 if (st_attributes != null) {
991 foreach (string attr in st_attributes) {
992 var nv = attr.split ("=", 2);
993 if (nv[0] == "cheader_filename") {
994 st.add_cheader_filename (eval (nv[1]));
995 } else if (nv[0] == "deprecated") {
996 if (eval (nv[1]) == "1") {
997 st.deprecated = true;
999 } else if (nv[0] == "replacement") {
1000 st.replacement = eval (nv[1]);
1001 } else if (nv[0] == "deprecated_since") {
1002 st.deprecated_since = eval (nv[1]);
1003 } else if (nv[0] == "immutable") {
1004 if (eval (nv[1]) == "1") {
1005 st.is_immutable = true;
1007 } else if (nv[0] == "has_copy_function") {
1008 if (eval (nv[1]) == "0") {
1009 st.has_copy_function = false;
1011 } else if (nv[0] == "has_destroy_function") {
1012 if (eval (nv[1]) == "0") {
1013 st.has_destroy_function = false;
1015 } else if (nv[0] == "experimental") {
1016 if (eval (nv[1]) == "1") {
1017 st.experimental = true;
1023 add_symbol_to_container (container, st);
1024 st.set_type_id (st.get_upper_case_cname ("TYPE_"));
1025 current_source_file.add_node (st);
1028 current_data_type = st;
1030 foreach (weak IdlNode member in boxed_node.members) {
1031 if (member.type == IdlNodeTypeId.FUNCTION) {
1032 var m = parse_function ((IdlNodeFunction) member);
1033 if (m != null) {
1034 st.add_method (m);
1036 } else if (member.type == IdlNodeTypeId.FIELD) {
1037 var f = parse_field ((IdlNodeField) member);
1038 if (f != null) {
1039 st.add_field (f);
1044 current_data_type = null;
1045 } else {
1046 bool ref_function_void = false;
1047 string ref_function = null;
1048 string unref_function = null;
1049 string copy_function = null;
1050 string free_function = null;
1052 var cl = container.scope.lookup (name) as Class;
1053 if (cl == null) {
1054 string base_class = null;
1056 cl = new Class (name, current_source_reference);
1057 cl.access = SymbolAccessibility.PUBLIC;
1058 cl.is_compact = true;
1060 var cl_attributes = get_attributes (node.name);
1061 if (cl_attributes != null) {
1062 foreach (string attr in cl_attributes) {
1063 var nv = attr.split ("=", 2);
1064 if (nv[0] == "cheader_filename") {
1065 cl.add_cheader_filename (eval (nv[1]));
1066 } else if (nv[0] == "base_class") {
1067 base_class = eval (nv[1]);
1068 } else if (nv[0] == "is_immutable") {
1069 if (eval (nv[1]) == "1") {
1070 cl.is_immutable = true;
1072 } else if (nv[0] == "deprecated") {
1073 if (eval (nv[1]) == "1") {
1074 cl.deprecated = true;
1076 } else if (nv[0] == "replacement") {
1077 cl.replacement = eval (nv[1]);
1078 } else if (nv[0] == "deprecated_since") {
1079 cl.deprecated_since = eval (nv[1]);
1080 } else if (nv[0] == "const_cname") {
1081 cl.const_cname = eval (nv[1]);
1082 } else if (nv[0] == "free_function") {
1083 free_function = eval (nv[1]);
1084 } else if (nv[0] == "ref_function") {
1085 ref_function = eval (nv[1]);
1086 } else if (nv[0] == "unref_function") {
1087 unref_function = eval (nv[1]);
1088 } else if (nv[0] == "copy_function") {
1089 copy_function = eval (nv[1]);
1090 } else if (nv[0] == "ref_function_void") {
1091 if (eval (nv[1]) == "1") {
1092 ref_function_void = true;
1094 } else if (nv[0] == "experimental") {
1095 if (eval (nv[1]) == "1") {
1096 cl.experimental = true;
1102 add_symbol_to_container (container, cl);
1103 cl.set_type_id (cl.get_upper_case_cname ("TYPE_"));
1104 current_source_file.add_node (cl);
1106 if (base_class != null) {
1107 var parent = parse_type_string (base_class);
1108 cl.add_base_type (parent);
1112 current_data_type = cl;
1114 foreach (weak IdlNode member in boxed_node.members) {
1115 if (member.type == IdlNodeTypeId.FUNCTION) {
1116 if (member.name == "ref") {
1117 ref_function = ((IdlNodeFunction) member).symbol;
1118 ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
1119 } else if (member.name == "unref") {
1120 unref_function = ((IdlNodeFunction) member).symbol;
1121 } else if (member.name == "free" || member.name == "destroy") {
1122 free_function = ((IdlNodeFunction) member).symbol;
1123 } else {
1124 if (member.name == "copy") {
1125 copy_function = ((IdlNodeFunction) member).symbol;
1127 var m = parse_function ((IdlNodeFunction) member);
1128 if (m != null) {
1129 cl.add_method (m);
1132 } else if (member.type == IdlNodeTypeId.FIELD) {
1133 var f = parse_field ((IdlNodeField) member);
1134 if (f != null) {
1135 cl.add_field (f);
1140 if (ref_function != null) {
1141 cl.set_ref_function (ref_function);
1142 cl.ref_function_void = ref_function_void;
1144 if (copy_function != null) {
1145 cl.set_dup_function (copy_function);
1147 if (unref_function != null) {
1148 cl.set_unref_function (unref_function);
1149 } else if (free_function != null) {
1150 cl.set_free_function (free_function);
1153 current_data_type = null;
1157 private void parse_enum (IdlNodeEnum en_node, Symbol container, IdlModule module, bool is_flags) {
1158 weak IdlNode node = (IdlNode) en_node;
1159 string name = fix_type_name (node.name, container);
1160 bool existing = true;
1162 var en = container.scope.lookup (name) as Enum;
1163 if (en == null) {
1164 en = new Enum (name, current_source_reference);
1165 en.access = SymbolAccessibility.PUBLIC;
1166 existing = false;
1167 } else {
1168 // ignore dummy enum values in -custom.vala files
1169 // they exist for syntactical reasons
1170 var dummy = (EnumValue) en.scope.lookup ("__DUMMY__");
1171 if (dummy != null) {
1172 en.get_values ().remove (dummy);
1173 en.scope.remove ("__DUMMY__");
1177 en.has_type_id = (en_node.gtype_name != null && en_node.gtype_name != "");
1179 string common_prefix = null;
1181 foreach (weak IdlNode value in en_node.values) {
1182 var val_attributes = get_attributes (value.name);
1183 bool is_hidden = false;
1184 if (val_attributes != null) {
1185 foreach (string attr in val_attributes) {
1186 var nv = attr.split ("=", 2);
1187 if (nv[0] == "hidden" && eval(nv[1]) == "1") {
1188 is_hidden = true;
1193 if (is_hidden) {
1194 continue;
1197 if (common_prefix == null) {
1198 common_prefix = value.name;
1199 while (common_prefix.length > 0 && !common_prefix.has_suffix ("_")) {
1200 // FIXME: could easily be made faster
1201 common_prefix = common_prefix.substring (0, common_prefix.length - 1);
1203 } else {
1204 while (!value.name.has_prefix (common_prefix)) {
1205 common_prefix = common_prefix.substring (0, common_prefix.length - 1);
1208 while (common_prefix.length > 0 && (!common_prefix.has_suffix ("_") ||
1209 (value.name.get_char (common_prefix.length).isdigit ()) && (value.name.length - common_prefix.length) <= 1)) {
1210 // enum values may not consist solely of digits
1211 common_prefix = common_prefix.substring (0, common_prefix.length - 1);
1215 bool is_errordomain = false;
1217 var cheader_filenames = new ArrayList<string> ();
1219 var en_attributes = get_attributes (node.name);
1220 if (en_attributes != null) {
1221 foreach (string attr in en_attributes) {
1222 var nv = attr.split ("=", 2);
1223 if (nv[0] == "common_prefix") {
1224 common_prefix = eval (nv[1]);
1225 } else if (nv[0] == "cheader_filename") {
1226 cheader_filenames.add (eval (nv[1]));
1227 en.add_cheader_filename (eval (nv[1]));
1228 } else if (nv[0] == "hidden") {
1229 if (eval (nv[1]) == "1") {
1230 return;
1232 } else if (nv[0] == "deprecated") {
1233 if (eval (nv[1]) == "1") {
1234 en.deprecated = true;
1236 } else if (nv[0] == "replacement") {
1237 en.replacement = eval (nv[1]);
1238 } else if (nv[0] == "deprecated_since") {
1239 en.deprecated_since = eval (nv[1]);
1240 } else if (nv[0] == "rename_to") {
1241 en.name = eval (nv[1]);
1242 } else if (nv[0] == "errordomain") {
1243 if (eval (nv[1]) == "1") {
1244 is_errordomain = true;
1246 } else if (nv[0] == "to_string") {
1247 var return_type = new UnresolvedType ();
1248 return_type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1249 return_type.value_owned = false;
1250 var m = new Method ("to_string", return_type, current_source_reference);
1251 m.access = SymbolAccessibility.PUBLIC;
1252 m.set_cname (eval(nv[1]));
1253 en.add_method (m);
1254 } else if (nv[0] == "experimental") {
1255 if (eval (nv[1]) == "1") {
1256 en.experimental = true;
1262 en.set_cprefix (common_prefix);
1264 foreach (weak IdlNode value2 in en_node.values) {
1265 var val_attributes = get_attributes (value2.name);
1266 bool is_hidden = false;
1267 if (val_attributes != null) {
1268 foreach (string attr in val_attributes) {
1269 var nv = attr.split ("=", 2);
1270 if (nv[0] == "hidden" && eval(nv[1]) == "1") {
1271 is_hidden = true;
1276 if (!is_hidden) {
1277 var ev = new EnumValue (value2.name.substring (common_prefix.length), null);
1278 en.add_value (ev);
1282 if (is_errordomain) {
1283 var ed = new ErrorDomain (en.name, current_source_reference);
1284 ed.access = SymbolAccessibility.PUBLIC;
1285 ed.set_cprefix (common_prefix);
1287 foreach (string filename in cheader_filenames) {
1288 ed.add_cheader_filename (filename);
1291 foreach (EnumValue ev in en.get_values ()) {
1292 ed.add_code (new ErrorCode (ev.name));
1295 current_source_file.add_node (ed);
1296 if (!existing) {
1297 add_symbol_to_container (container, ed);
1299 } else {
1300 en.is_flags = is_flags;
1301 current_source_file.add_node (en);
1302 if (!existing) {
1303 add_symbol_to_container (container, en);
1308 private void parse_object (IdlNodeInterface node, Symbol container, IdlModule module) {
1309 string name = fix_type_name (((IdlNode) node).name, container);
1311 string base_class = null;
1313 var cl = container.scope.lookup (name) as Class;
1314 if (cl == null) {
1315 cl = new Class (name, current_source_reference);
1316 cl.access = SymbolAccessibility.PUBLIC;
1318 var attributes = get_attributes (node.gtype_name);
1319 if (attributes != null) {
1320 foreach (string attr in attributes) {
1321 var nv = attr.split ("=", 2);
1322 if (nv[0] == "cheader_filename") {
1323 cl.add_cheader_filename (eval (nv[1]));
1324 } else if (nv[0] == "base_class") {
1325 base_class = eval (nv[1]);
1326 } else if (nv[0] == "hidden") {
1327 if (eval (nv[1]) == "1") {
1328 return;
1330 } else if (nv[0] == "type_check_function") {
1331 cl.type_check_function = eval (nv[1]);
1332 } else if (nv[0] == "deprecated") {
1333 if (eval (nv[1]) == "1") {
1334 cl.deprecated = true;
1336 } else if (nv[0] == "replacement") {
1337 cl.replacement = eval (nv[1]);
1338 } else if (nv[0] == "deprecated_since") {
1339 cl.deprecated_since = eval (nv[1]);
1340 } else if (nv[0] == "type_id") {
1341 cl.set_type_id (eval (nv[1]));
1342 } else if (nv[0] == "abstract") {
1343 if (eval (nv[1]) == "1") {
1344 cl.is_abstract = true;
1346 } else if (nv[0] == "experimental") {
1347 if (eval (nv[1]) == "1") {
1348 cl.experimental = true;
1354 add_symbol_to_container (container, cl);
1355 current_source_file.add_node (cl);
1358 if (base_class != null) {
1359 var parent = parse_type_string (base_class);
1360 cl.add_base_type (parent);
1361 } else if (node.parent != null) {
1362 var parent = parse_type_string (node.parent);
1363 cl.add_base_type (parent);
1364 } else {
1365 var gobject_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Object");
1366 cl.add_base_type (new UnresolvedType.from_symbol (gobject_symbol));
1369 foreach (string iface_name in node.interfaces) {
1370 bool skip_iface = false;
1372 var attributes = get_attributes (iface_name);
1373 if (attributes != null) {
1374 foreach (string attr in attributes) {
1375 var nv = attr.split ("=", 2);
1376 if (nv[0] == "hidden") {
1377 if (eval (nv[1]) == "1") {
1378 skip_iface = true;
1384 if (skip_iface) {
1385 continue;
1388 var iface = parse_type_string (iface_name);
1389 cl.add_base_type (iface);
1392 current_data_type = cl;
1394 current_type_symbol_set = new HashSet<string> (str_hash, str_equal);
1395 var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
1396 var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
1398 foreach (weak IdlNode member in node.members) {
1399 if (member.type == IdlNodeTypeId.FUNCTION) {
1400 current_type_func_map.set (member.name, (IdlNodeFunction) member);
1402 if (member.type == IdlNodeTypeId.VFUNC) {
1403 current_type_vfunc_map.set (member.name, "1");
1407 foreach (weak IdlNode member in node.members) {
1408 if (member.type == IdlNodeTypeId.FUNCTION) {
1409 // Ignore if vfunc (handled below)
1410 if (!current_type_vfunc_map.contains (member.name)) {
1411 var m = parse_function ((IdlNodeFunction) member);
1412 if (m != null) {
1413 cl.add_method (m);
1416 } else if (member.type == IdlNodeTypeId.VFUNC) {
1417 var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name));
1418 if (m != null) {
1419 cl.add_method (m);
1421 } else if (member.type == IdlNodeTypeId.PROPERTY) {
1422 var prop = parse_property ((IdlNodeProperty) member);
1423 if (prop != null) {
1424 cl.add_property (prop);
1426 } else if (member.type == IdlNodeTypeId.SIGNAL) {
1427 var sig = parse_signal ((IdlNodeSignal) member);
1428 if (sig != null) {
1429 cl.add_signal (sig);
1434 foreach (weak IdlNode member in node.members) {
1435 if (member.type == IdlNodeTypeId.FIELD) {
1436 if (!current_type_symbol_set.contains (member.name)) {
1437 var f = parse_field ((IdlNodeField) member);
1438 if (f != null) {
1439 cl.add_field (f);
1445 foreach (Property prop in cl.get_properties ()) {
1446 var getter = "get_%s".printf (prop.name);
1448 if (prop.get_accessor != null && !current_type_symbol_set.contains (getter)) {
1449 prop.no_accessor_method = true;
1452 var setter = "set_%s".printf (prop.name);
1454 if (prop.set_accessor != null && prop.set_accessor.writable
1455 && !current_type_symbol_set.contains (setter)) {
1456 prop.no_accessor_method = true;
1459 if (prop.no_accessor_method && prop.get_accessor != null) {
1460 prop.get_accessor.value_type.value_owned = true;
1464 handle_async_methods (cl);
1466 if (cl.default_construction_method == null) {
1467 // always provide constructor in generated bindings
1468 // to indicate that implicit Object () chainup is allowed
1469 var cm = new CreationMethod (null, null, cl.source_reference);
1470 cm.has_construct_function = false;
1471 cm.access = SymbolAccessibility.PROTECTED;
1472 cl.add_method (cm);
1475 current_data_type = null;
1476 current_type_symbol_set = null;
1479 private void parse_interface (IdlNodeInterface node, Symbol container, IdlModule module) {
1480 string name = fix_type_name (node.gtype_name, container);
1482 var iface = container.scope.lookup (name) as Interface;
1483 if (iface == null) {
1484 iface = new Interface (name, current_source_reference);
1485 iface.access = SymbolAccessibility.PUBLIC;
1487 var attributes = get_attributes (node.gtype_name);
1488 if (attributes != null) {
1489 foreach (string attr in attributes) {
1490 var nv = attr.split ("=", 2);
1491 if (nv[0] == "cheader_filename") {
1492 iface.add_cheader_filename (eval (nv[1]));
1493 } else if (nv[0] == "type_cname") {
1494 iface.set_type_cname (eval (nv[1]));
1495 } else if (nv[0] == "lower_case_csuffix") {
1496 iface.set_lower_case_csuffix (eval (nv[1]));
1501 foreach (string prereq_name in node.prerequisites) {
1502 var prereq = parse_type_string (prereq_name);
1503 iface.add_prerequisite (prereq);
1506 add_symbol_to_container (container, iface);
1507 current_source_file.add_node (iface);
1510 current_data_type = iface;
1512 var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
1513 var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
1515 foreach (weak IdlNode member in node.members) {
1516 if (member.type == IdlNodeTypeId.FUNCTION) {
1517 current_type_func_map.set (member.name, (IdlNodeFunction) member);
1519 if (member.type == IdlNodeTypeId.VFUNC) {
1520 current_type_vfunc_map.set (member.name, "1");
1524 foreach (weak IdlNode member in node.members) {
1525 if (member.type == IdlNodeTypeId.FUNCTION) {
1526 // Ignore if vfunc (handled below)
1527 if (!current_type_vfunc_map.contains (member.name)) {
1528 var m = parse_function ((IdlNodeFunction) member, true);
1529 if (m != null) {
1530 iface.add_method (m);
1533 } else if (member.type == IdlNodeTypeId.VFUNC) {
1534 var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name), true);
1535 if (m != null) {
1536 iface.add_method (m);
1538 } else if (member.type == IdlNodeTypeId.PROPERTY) {
1539 var prop = parse_property ((IdlNodeProperty) member);
1540 if (prop != null) {
1541 iface.add_property (prop);
1543 } else if (member.type == IdlNodeTypeId.SIGNAL) {
1544 var sig = parse_signal ((IdlNodeSignal) member);
1545 if (sig != null) {
1546 iface.add_signal (sig);
1547 sig.is_virtual = false;
1552 handle_async_methods (iface);
1554 current_data_type = null;
1557 void handle_async_methods (ObjectTypeSymbol type_symbol) {
1558 Set<Method> finish_methods = new HashSet<Method> ();
1559 var methods = type_symbol.get_methods ();
1561 foreach (Method m in methods) {
1562 if (m.coroutine) {
1563 string finish_method_base;
1564 if (m.name.has_suffix ("_async")) {
1565 finish_method_base = m.name.substring (0, m.name.length - "_async".length);
1566 } else {
1567 finish_method_base = m.name;
1569 var finish_method = type_symbol.scope.lookup (finish_method_base + "_finish") as Method;
1571 // check if the method is using non-standard finish method name
1572 if (finish_method == null) {
1573 var method_cname = m.get_finish_cname ();
1574 foreach (Method method in type_symbol.get_methods ()) {
1575 if (method.get_cname () == method_cname) {
1576 finish_method = method;
1577 break;
1582 if (finish_method != null) {
1583 m.return_type = finish_method.return_type.copy ();
1584 m.no_array_length = finish_method.no_array_length;
1585 m.array_null_terminated = finish_method.array_null_terminated;
1586 foreach (var param in finish_method.get_parameters ()) {
1587 if (param.direction == ParameterDirection.OUT) {
1588 var async_param = param.copy ();
1589 if (m.scope.lookup (param.name) != null) {
1590 // parameter name conflict
1591 async_param.name += "_out";
1593 m.add_parameter (async_param);
1596 foreach (DataType error_type in finish_method.get_error_types ()) {
1597 m.add_error_type (error_type.copy ());
1599 finish_methods.add (finish_method);
1604 foreach (Method m in finish_methods)
1606 type_symbol.scope.remove (m.name);
1607 methods.remove (m);
1611 private DataType? parse_type (IdlNodeType type_node, out ParameterDirection direction = null) {
1612 ParameterDirection dir = ParameterDirection.IN;
1614 var type = new UnresolvedType ();
1615 if (type_node.tag == TypeTag.VOID) {
1616 if (type_node.is_pointer) {
1617 return new PointerType (new VoidType ());
1618 } else {
1619 return new VoidType ();
1621 } else if (type_node.tag == TypeTag.BOOLEAN) {
1622 type.unresolved_symbol = new UnresolvedSymbol (null, "bool");
1623 } else if (type_node.tag == TypeTag.INT8) {
1624 type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1625 } else if (type_node.tag == TypeTag.UINT8) {
1626 type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1627 } else if (type_node.tag == TypeTag.INT16) {
1628 type.unresolved_symbol = new UnresolvedSymbol (null, "int16");
1629 } else if (type_node.tag == TypeTag.UINT16) {
1630 type.unresolved_symbol = new UnresolvedSymbol (null, "uint16");
1631 } else if (type_node.tag == TypeTag.INT32) {
1632 type.unresolved_symbol = new UnresolvedSymbol (null, "int32");
1633 } else if (type_node.tag == TypeTag.UINT32) {
1634 type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
1635 } else if (type_node.tag == TypeTag.INT64) {
1636 type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1637 } else if (type_node.tag == TypeTag.UINT64) {
1638 type.unresolved_symbol = new UnresolvedSymbol (null, "uint64");
1639 } else if (type_node.tag == TypeTag.INT) {
1640 type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1641 } else if (type_node.tag == TypeTag.UINT) {
1642 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1643 } else if (type_node.tag == TypeTag.LONG) {
1644 type.unresolved_symbol = new UnresolvedSymbol (null, "long");
1645 } else if (type_node.tag == TypeTag.ULONG) {
1646 type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1647 } else if (type_node.tag == TypeTag.SSIZE) {
1648 type.unresolved_symbol = new UnresolvedSymbol (null, "ssize_t");
1649 } else if (type_node.tag == TypeTag.SIZE) {
1650 type.unresolved_symbol = new UnresolvedSymbol (null, "size_t");
1651 } else if (type_node.tag == TypeTag.FLOAT) {
1652 type.unresolved_symbol = new UnresolvedSymbol (null, "float");
1653 } else if (type_node.tag == TypeTag.DOUBLE) {
1654 type.unresolved_symbol = new UnresolvedSymbol (null, "double");
1655 } else if (type_node.tag == TypeTag.UTF8) {
1656 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1657 } else if (type_node.tag == TypeTag.FILENAME) {
1658 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1659 } else if (type_node.tag == TypeTag.ARRAY) {
1660 var element_type = parse_type (type_node.parameter_type1);
1661 type = element_type as UnresolvedType;
1662 if (type == null) {
1663 return element_type;
1665 return new ArrayType (element_type, 1, element_type.source_reference);
1666 } else if (type_node.tag == TypeTag.LIST) {
1667 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "List");
1668 } else if (type_node.tag == TypeTag.SLIST) {
1669 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "SList");
1670 } else if (type_node.tag == TypeTag.HASH) {
1671 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "HashTable");
1672 } else if (type_node.tag == TypeTag.ERROR) {
1673 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Error");
1674 } else if (type_node.is_interface) {
1675 var n = type_node.@interface;
1677 if (n == "") {
1678 return null;
1681 if (n.has_prefix ("const-")) {
1682 n = n.substring ("const-".length);
1685 if (type_node.is_pointer &&
1686 (n == "gchar" || n == "char")) {
1687 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1688 if (type_node.unparsed.has_suffix ("**")) {
1689 dir = ParameterDirection.OUT;
1691 } else if (n == "gunichar") {
1692 type.unresolved_symbol = new UnresolvedSymbol (null, "unichar");
1693 } else if (n == "gchar") {
1694 type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1695 } else if (n == "guchar" || n == "guint8") {
1696 type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1697 if (type_node.is_pointer) {
1698 return new ArrayType (type, 1, type.source_reference);
1700 } else if (n == "gushort") {
1701 type.unresolved_symbol = new UnresolvedSymbol (null, "ushort");
1702 } else if (n == "gshort") {
1703 type.unresolved_symbol = new UnresolvedSymbol (null, "short");
1704 } else if (n == "gconstpointer" || n == "void") {
1705 return new PointerType (new VoidType ());
1706 } else if (n == "goffset" || n == "off_t") {
1707 type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1708 } else if (n == "value_array") {
1709 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "ValueArray");
1710 } else if (n == "time_t") {
1711 type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1712 } else if (n == "socklen_t") {
1713 type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
1714 } else if (n == "mode_t") {
1715 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1716 } else if (n == "gint" || n == "pid_t") {
1717 type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1718 } else if (n == "unsigned" || n == "unsigned-int") {
1719 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1720 } else if (n == "FILE") {
1721 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "FileStream");
1722 } else if (n == "struct") {
1723 return new PointerType (new VoidType ());
1724 } else if (n == "iconv_t") {
1725 return new PointerType (new VoidType ());
1726 } else if (n == "GType") {
1727 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Type");
1728 if (type_node.is_pointer) {
1729 return new ArrayType (type, 1, type.source_reference);
1731 } else if (n == "GStrv") {
1732 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1733 return new ArrayType (type, 1, type.source_reference);
1734 } else {
1735 var named_type = parse_type_string (n);
1736 type = named_type as UnresolvedType;
1737 if (type == null) {
1738 return named_type;
1740 if (is_simple_type (n)) {
1741 if (type_node.is_pointer) {
1742 dir = ParameterDirection.OUT;
1744 } else if (type_node.unparsed.has_suffix ("**")) {
1745 dir = ParameterDirection.OUT;
1748 } else {
1749 stdout.printf ("%d\n", type_node.tag);
1751 if (&direction != null) {
1752 direction = dir;
1754 return type;
1757 private bool is_simple_type (string type_name) {
1758 var st = cname_type_map[type_name] as Struct;
1759 if (st != null && st.is_simple_type ()) {
1760 return true;
1763 return false;
1766 private DataType parse_type_string (string n) {
1767 if (n == "va_list") {
1768 // unsupported
1769 return new PointerType (new VoidType ());
1772 var type = new UnresolvedType ();
1774 var dt = cname_type_map[n];
1775 if (dt != null) {
1776 UnresolvedSymbol parent_symbol = null;
1777 if (dt.parent_symbol.name != null) {
1778 parent_symbol = new UnresolvedSymbol (null, dt.parent_symbol.name);
1780 type.unresolved_symbol = new UnresolvedSymbol (parent_symbol, dt.name);
1781 return type;
1784 var type_attributes = get_attributes (n);
1786 string ns_name = null;
1788 if (null != type_attributes) {
1789 foreach (string attr in type_attributes) {
1790 var nv = attr.split ("=", 2);
1792 if (nv[0] == "cprefix") {
1793 type.unresolved_symbol = new UnresolvedSymbol (null, n.substring (eval (nv[1]).length));
1794 } else if (nv[0] == "name") {
1795 type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1796 } else if (nv[0] == "namespace") {
1797 ns_name = eval (nv[1]);
1798 } else if (nv[0] == "rename_to") {
1799 type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1804 if (type.unresolved_symbol != null) {
1805 if (type.unresolved_symbol.name == "pointer") {
1806 return new PointerType (new VoidType ());
1808 if (ns_name != null) {
1809 type.unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
1811 return type;
1814 if (n.has_prefix (current_namespace.name)) {
1815 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, current_namespace.name), n.substring (current_namespace.name.length));
1816 } else if (n.has_prefix ("G")) {
1817 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), n.substring (1));
1818 } else {
1819 var name_parts = n.split (".", 2);
1820 if (name_parts[1] == null) {
1821 type.unresolved_symbol = new UnresolvedSymbol (null, name_parts[0]);
1822 } else {
1823 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, name_parts[0]), name_parts[1]);
1827 return type;
1830 private DataType? parse_param (IdlNodeParam param, out ParameterDirection direction = null) {
1831 var type = parse_type (param.type, out direction);
1833 // disable for now as null_ok not yet correctly set
1834 // type.non_null = !param.null_ok;
1836 return type;
1839 private UnresolvedSymbol? parse_symbol_from_string (string symbol_string, SourceReference? source_reference = null) {
1840 UnresolvedSymbol? sym = null;
1841 foreach (unowned string s in symbol_string.split (".")) {
1842 sym = new UnresolvedSymbol (sym, s, source_reference);
1844 if (sym == null) {
1845 Report.error (source_reference, "a symbol must be specified");
1847 return sym;
1850 private bool parse_type_arguments_from_string (DataType parent_type, string type_arguments, SourceReference? source_reference = null) {
1851 int type_arguments_length = (int) type_arguments.length;
1852 GLib.StringBuilder current = new GLib.StringBuilder.sized (type_arguments_length);
1854 int depth = 0;
1855 for (var c = 0 ; c < type_arguments_length ; c++) {
1856 if (type_arguments[c] == '<' || type_arguments[c] == '[') {
1857 depth++;
1858 current.append_unichar (type_arguments[c]);
1859 } else if (type_arguments[c] == '>' || type_arguments[c] == ']') {
1860 depth--;
1861 current.append_unichar (type_arguments[c]);
1862 } else if (type_arguments[c] == ',') {
1863 if (depth == 0) {
1864 var dt = parse_type_from_string (current.str, true, source_reference);
1865 if (dt == null) {
1866 return false;
1868 parent_type.add_type_argument (dt);
1869 current.truncate ();
1870 } else {
1871 current.append_unichar (type_arguments[c]);
1873 } else {
1874 current.append_unichar (type_arguments[c]);
1878 var dt = parse_type_from_string (current.str, true, source_reference);
1879 if (dt == null) {
1880 return false;
1882 parent_type.add_type_argument (dt);
1884 return true;
1887 private DataType? parse_type_from_string (string type_string, bool owned_by_default, SourceReference? source_reference = null) {
1888 if (type_from_string_regex == null) {
1889 try {
1890 type_from_string_regex = new GLib.Regex ("^(?:(owned|unowned|weak) +)?([0-9a-zA-Z_\\.]+)(?:<(.+)>)?(\\*+)?(\\[(,*)?\\])?(\\?)?$", GLib.RegexCompileFlags.ANCHORED | GLib.RegexCompileFlags.DOLLAR_ENDONLY | GLib.RegexCompileFlags.OPTIMIZE);
1891 } catch (GLib.RegexError e) {
1892 GLib.error ("Unable to compile regex: %s", e.message);
1896 GLib.MatchInfo match;
1897 if (!type_from_string_regex.match (type_string, 0, out match)) {
1898 Report.error (source_reference, "unable to parse type");
1899 return null;
1902 DataType? type = null;
1904 var ownership_data = match.fetch (1);
1905 var type_name = match.fetch (2);
1906 var type_arguments_data = match.fetch (3);
1907 var pointers_data = match.fetch (4);
1908 var array_data = match.fetch (5);
1909 var array_dimension_data = match.fetch (6);
1910 var nullable_data = match.fetch (7);
1912 var nullable = nullable_data != null && nullable_data.length > 0;
1914 if (ownership_data == null && type_name == "void") {
1915 if (array_data == null && !nullable) {
1916 type = new VoidType (source_reference);
1917 if (pointers_data != null) {
1918 for (int i=0; i < pointers_data.length; i++) {
1919 type = new PointerType (type);
1922 return type;
1923 } else {
1924 Report.error (source_reference, "invalid void type");
1925 return null;
1929 bool value_owned = owned_by_default;
1931 if (ownership_data == "owned") {
1932 value_owned = true;
1933 } else if (ownership_data == "unowned") {
1934 value_owned = false;
1937 var sym = parse_symbol_from_string (type_name, source_reference);
1938 if (sym == null) {
1939 return null;
1941 type = new UnresolvedType.from_symbol (sym, source_reference);
1943 if (type_arguments_data != null && type_arguments_data.length > 0) {
1944 if (!parse_type_arguments_from_string (type, type_arguments_data, source_reference)) {
1945 return null;
1949 if (pointers_data != null) {
1950 for (int i=0; i < pointers_data.length; i++) {
1951 type = new PointerType (type);
1955 if (array_data != null && array_data.length > 0) {
1956 type = new ArrayType (type, array_dimension_data.length + 1, source_reference);
1959 type.nullable = nullable;
1960 type.value_owned = value_owned;
1961 return type;
1964 private Method? create_method (string name, string symbol, IdlNodeParam? res, GLib.List<IdlNodeParam>? parameters, bool is_constructor, bool is_interface) {
1965 DataType return_type = null;
1966 if (res != null) {
1967 return_type = parse_param (res);
1970 Method m;
1971 if (!is_interface && (is_constructor || name.has_prefix ("new"))) {
1972 m = new CreationMethod (null, name, current_source_reference);
1973 m.has_construct_function = false;
1974 if (m.name == "new") {
1975 m.name = null;
1976 } else if (m.name.has_prefix ("new_")) {
1977 m.name = m.name.substring ("new_".length);
1979 // For classes, check whether a creation method return type equals to the
1980 // type of the class created. If the types do not match (e.g. in most
1981 // gtk widgets) add an attribute to the creation method indicating the used
1982 // return type.
1983 if (current_data_type is Class && res != null) {
1984 if ("%s*".printf (current_data_type.get_cname()) != res.type.unparsed) {
1985 ((CreationMethod)m).custom_return_type_cname = res.type.unparsed;
1988 } else {
1989 m = new Method (name, return_type, current_source_reference);
1991 m.access = SymbolAccessibility.PUBLIC;
1993 if (current_type_symbol_set != null) {
1994 current_type_symbol_set.add (name);
1997 if (current_data_type != null) {
1998 var sig_attributes = get_attributes ("%s::%s".printf (current_data_type.get_cname (), name));
1999 if (sig_attributes != null) {
2000 foreach (string attr in sig_attributes) {
2001 var nv = attr.split ("=", 2);
2002 if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
2003 return null;
2009 bool add_ellipsis = false;
2010 bool suppress_throws = false;
2011 string? error_types = null;
2013 var attributes = get_attributes (symbol);
2014 if (attributes != null) {
2015 foreach (string attr in attributes) {
2016 var nv = attr.split ("=", 2);
2017 if (nv[0] == "name") {
2018 m.set_cname (m.name);
2019 m.name = eval (nv[1]);
2020 } else if (nv[0] == "hidden") {
2021 if (eval (nv[1]) == "1") {
2022 return null;
2024 } else if (nv[0] == "ellipsis") {
2025 if (eval (nv[1]) == "1") {
2026 add_ellipsis = true;
2028 } else if (nv[0] == "printf_format") {
2029 if (eval (nv[1]) == "1") {
2030 m.printf_format = true;
2032 } else if (nv[0] == "transfer_ownership") {
2033 if (eval (nv[1]) == "1") {
2034 return_type.value_owned = true;
2036 } else if (nv[0] == "nullable") {
2037 if (eval (nv[1]) == "1") {
2038 return_type.nullable = true;
2040 } else if (nv[0] == "sentinel") {
2041 m.sentinel = eval (nv[1]);
2042 } else if (nv[0] == "is_array") {
2043 if (eval (nv[1]) == "1") {
2044 return_type = new ArrayType (return_type, 1, return_type.source_reference);
2045 m.return_type = return_type;
2047 } else if (nv[0] == "throws") {
2048 if (eval (nv[1]) == "0") {
2049 suppress_throws = true;
2051 } else if (nv[0] == "error_types") {
2052 error_types = eval (nv[1]);
2053 } else if (nv[0] == "no_array_length") {
2054 if (eval (nv[1]) == "1") {
2055 m.no_array_length = true;
2057 } else if (nv[0] == "array_null_terminated") {
2058 if (eval (nv[1]) == "1") {
2059 m.no_array_length = true;
2060 m.array_null_terminated = true;
2062 } else if (nv[0] == "array_length_type") {
2063 m.array_length_type = eval (nv[1]);
2064 } else if (nv[0] == "type_name") {
2065 m.return_type = return_type = parse_type_from_string (eval (nv[1]), return_type.value_owned);
2066 } else if (nv[0] == "type_arguments") {
2067 parse_type_arguments_from_string (return_type, eval (nv[1]));
2068 } else if (nv[0] == "deprecated") {
2069 if (eval (nv[1]) == "1") {
2070 m.deprecated = true;
2072 } else if (nv[0] == "replacement") {
2073 m.replacement = eval (nv[1]);
2074 } else if (nv[0] == "deprecated_since") {
2075 m.deprecated_since = eval (nv[1]);
2076 } else if (nv[0] == "cheader_filename") {
2077 m.add_cheader_filename (eval (nv[1]));
2078 } else if (nv[0] == "abstract") {
2079 if (eval (nv[1]) == "1") {
2080 m.is_abstract = true;
2082 } else if (nv[0] == "virtual") {
2083 if (eval (nv[1]) == "1") {
2084 m.is_virtual = true;
2086 } else if (nv[0] == "vfunc_name") {
2087 m.vfunc_name = eval (nv[1]);
2088 } else if (nv[0] == "finish_name") {
2089 m.set_finish_cname (eval (nv[1]));
2090 } else if (nv[0] == "async") {
2091 if (eval (nv[1]) == "1") {
2092 // force async function, even if it doesn't end in _async
2093 m.coroutine = true;
2095 } else if (nv[0] == "parent") {
2096 Symbol container = get_container_from_name (eval (nv[1]));
2097 var prefix = container.get_lower_case_cprefix ();
2098 if (symbol.has_prefix (prefix)) {
2099 m.set_cname (m.name);
2100 m.name = symbol.substring (prefix.length);
2102 } else if (nv[0] == "experimental") {
2103 if (eval (nv[1]) == "1") {
2104 m.experimental = true;
2110 m.set_cname (symbol);
2112 bool first = true;
2113 Parameter last_param = null;
2114 DataType last_param_type = null;
2115 foreach (weak IdlNodeParam param in parameters) {
2116 weak IdlNode param_node = (IdlNode) param;
2118 if (first) {
2119 first = false;
2120 if (!(m is CreationMethod) &&
2121 current_data_type != null &&
2122 param.type.is_interface &&
2123 (param_node.name == "self" ||
2124 param.type.@interface.has_suffix (current_data_type.get_cname ()))) {
2125 // instance method
2126 continue;
2127 } else if (!(m is CreationMethod) &&
2128 current_data_type != null &&
2129 param.type.is_interface &&
2130 (param_node.name == "klass" ||
2131 param.type.@interface.has_suffix ("%sClass".printf(current_data_type.get_cname ())))) {
2132 // class method
2133 m.binding = MemberBinding.CLASS;
2134 if (m.name.has_prefix ("class_")) {
2135 m.name = m.name.substring ("class_".length, m.name.length - "class_".length);
2137 continue;
2138 } else {
2139 // static method
2140 m.binding = MemberBinding.STATIC;
2144 if (param.type.@interface == "GAsyncReadyCallback" && (symbol.has_suffix ("_async") || m.coroutine)) {
2145 // async method
2146 m.coroutine = true;
2147 continue;
2150 if (suppress_throws == false && param_is_exception (param)) {
2151 if (error_types == null)
2152 m.add_error_type (parse_type (param.type));
2153 continue;
2156 string param_name = param_node.name;
2157 if (param_name == "result") {
2158 // avoid conflict with generated result variable
2159 param_name = "_result";
2160 } else if (param_name == "string") {
2161 // avoid conflict with string type
2162 param_name = "str";
2164 ParameterDirection direction;
2165 var param_type = parse_param (param, out direction);
2166 var p = new Parameter (param_name, param_type);
2167 p.direction = direction;
2169 bool hide_param = false;
2170 bool show_param = false;
2171 bool set_array_length_pos = false;
2172 double array_length_pos = 0;
2173 bool set_delegate_target_pos = false;
2174 double delegate_target_pos = 0;
2175 bool array_requested = false;
2176 bool out_requested = false;
2177 attributes = get_attributes ("%s.%s".printf (symbol, param_node.name));
2178 if (attributes != null) {
2179 foreach (string attr in attributes) {
2180 var nv = attr.split ("=", 2);
2181 if (nv[0] == "is_array") {
2182 if (eval (nv[1]) == "1") {
2183 param_type = new ArrayType (param_type, 1, param_type.source_reference);
2184 p.variable_type = param_type;
2185 if (!out_requested) {
2186 p.direction = ParameterDirection.IN;
2188 array_requested = true;
2190 } else if (nv[0] == "is_out") {
2191 if (eval (nv[1]) == "1") {
2192 p.direction = ParameterDirection.OUT;
2193 out_requested = true;
2194 if (!array_requested && param_type is ArrayType) {
2195 var array_type = (ArrayType) param_type;
2196 param_type = array_type.element_type;
2197 p.variable_type = param_type;
2200 } else if (nv[0] == "is_ref") {
2201 if (eval (nv[1]) == "1") {
2202 p.direction = ParameterDirection.REF;
2203 if (!array_requested && param_type is ArrayType) {
2204 var array_type = (ArrayType) param_type;
2205 param_type = array_type.element_type;
2206 p.variable_type = param_type;
2209 } else if (nv[0] == "nullable") {
2210 if (eval (nv[1]) == "1") {
2211 param_type.nullable = true;
2213 } else if (nv[0] == "transfer_ownership") {
2214 if (eval (nv[1]) == "1") {
2215 param_type.value_owned = true;
2217 } else if (nv[0] == "takes_ownership") {
2218 if (eval (nv[1]) == "1") {
2219 param_type.value_owned = true;
2221 } else if (nv[0] == "value_owned") {
2222 if (eval (nv[1]) == "0") {
2223 param_type.value_owned = false;
2224 } else if (eval (nv[1]) == "1") {
2225 param_type.value_owned = true;
2227 } else if (nv[0] == "hidden") {
2228 if (eval (nv[1]) == "1") {
2229 hide_param = true;
2230 } else if (eval (nv[1]) == "0") {
2231 show_param = true;
2233 } else if (nv[0] == "no_array_length") {
2234 if (eval (nv[1]) == "1") {
2235 p.no_array_length = true;
2237 } else if (nv[0] == "array_length_type") {
2238 p.array_length_type = eval (nv[1]);
2239 } else if (nv[0] == "array_null_terminated") {
2240 if (eval (nv[1]) == "1") {
2241 p.no_array_length = true;
2242 p.array_null_terminated = true;
2244 } else if (nv[0] == "array_length_pos") {
2245 set_array_length_pos = true;
2246 array_length_pos = double.parse (eval (nv[1]));
2247 } else if (nv[0] == "delegate_target_pos") {
2248 set_delegate_target_pos = true;
2249 delegate_target_pos = double.parse (eval (nv[1]));
2250 } else if (nv[0] == "type_name") {
2251 p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
2252 } else if (nv[0] == "ctype") {
2253 p.ctype = eval (nv[1]);
2254 } else if (nv[0] == "type_arguments") {
2255 parse_type_arguments_from_string (param_type, eval (nv[1]));
2256 } else if (nv[0] == "default_value") {
2257 var val = eval (nv[1]);
2258 if (val == "null") {
2259 p.initializer = new NullLiteral (param_type.source_reference);
2260 } else if (val == "true") {
2261 p.initializer = new BooleanLiteral (true, param_type.source_reference);
2262 } else if (val == "false") {
2263 p.initializer = new BooleanLiteral (false, param_type.source_reference);
2264 } else if (val == "") {
2265 p.initializer = new StringLiteral ("\"\"", param_type.source_reference);
2266 } else {
2267 if (int64.try_parse (val)) {
2268 p.initializer = new IntegerLiteral (val, param_type.source_reference);
2269 } else {
2270 if (double.try_parse (val)) {
2271 p.initializer = new RealLiteral (val, param_type.source_reference);
2272 } else {
2273 if (val.has_prefix ("\"") && val.has_suffix ("\"")) {
2274 p.initializer = new StringLiteral (val, param_type.source_reference);
2275 } else {
2276 foreach (var member in val.split (".")) {
2277 p.initializer = new MemberAccess (p.initializer, member, param_type.source_reference);
2287 if (last_param != null && p.name == "n_" + last_param.name) {
2288 if (!(last_param_type is ArrayType)) {
2289 // last_param is array, p is array length
2290 last_param_type = new ArrayType (last_param_type, 1, last_param_type.source_reference);
2291 last_param.variable_type = last_param_type;
2292 last_param.direction = ParameterDirection.IN;
2295 // hide array length param
2296 hide_param = true;
2297 } else if (last_param != null && p.name == "user_data") {
2298 // last_param is delegate
2300 // hide deleate target param
2301 hide_param = true;
2304 if (show_param || !hide_param) {
2305 m.add_parameter (p);
2306 if (set_array_length_pos) {
2307 p.carray_length_parameter_position = array_length_pos;
2309 if (set_delegate_target_pos) {
2310 p.cdelegate_target_parameter_position = delegate_target_pos;
2314 last_param = p;
2315 last_param_type = param_type;
2318 if (suppress_throws == false && error_types != null) {
2319 var type_args = eval (error_types).split (",");
2320 foreach (string type_arg in type_args) {
2321 m.add_error_type (parse_type_from_string (type_arg, true));
2325 if (first) {
2326 // no parameters => static method
2327 m.binding = MemberBinding.STATIC;
2330 if (last_param != null && last_param.name.has_prefix ("first_")) {
2331 last_param.ellipsis = true;
2332 } else if (add_ellipsis) {
2333 m.add_parameter (new Parameter.with_ellipsis ());
2336 return m;
2339 private bool param_is_exception (IdlNodeParam param) {
2340 if (!param.type.is_error) {
2341 return false;
2343 var s = param.type.unparsed.chomp ();
2344 if (s.has_suffix ("**")) {
2345 return true;
2347 return false;
2350 private Method? parse_function (IdlNodeFunction f, bool is_interface = false) {
2351 weak IdlNode node = (IdlNode) f;
2353 if (f.deprecated) {
2354 return null;
2357 return create_method (node.name, f.symbol, f.result, f.parameters, f.is_constructor, is_interface);
2360 private Method parse_virtual (IdlNodeVFunc v, IdlNodeFunction? func, bool is_interface = false) {
2361 weak IdlNode node = (IdlNode) v;
2362 string symbol = "%s%s".printf (current_data_type.get_lower_case_cprefix(), node.name);
2364 if (func != null) {
2365 symbol = func.symbol;
2368 Method m = create_method (node.name, symbol, v.result, func != null ? func.parameters : v.parameters, false, is_interface);
2369 if (m != null) {
2370 m.binding = MemberBinding.INSTANCE;
2371 m.is_virtual = !(m.is_abstract || is_interface);
2372 m.is_abstract = m.is_abstract || is_interface;
2374 var attributes = get_attributes (symbol);
2375 if (attributes != null) {
2376 foreach (string attr in attributes) {
2377 var nv = attr.split ("=", 2);
2378 if (nv[0] == "virtual") {
2379 if (eval (nv[1]) == "0") {
2380 m.is_virtual = false;
2381 m.is_abstract = false;
2382 } else {
2383 m.is_virtual = true;
2384 m.is_abstract = false;
2390 if (func == null) {
2391 m.attributes.append (new Attribute ("NoWrapper", null));
2395 return m;
2398 private string fix_prop_name (string name) {
2399 var str = new StringBuilder ();
2401 string i = name;
2403 while (i.length > 0) {
2404 unichar c = i.get_char ();
2405 if (c == '-') {
2406 str.append_c ('_');
2407 } else {
2408 str.append_unichar (c);
2411 i = i.next_char ();
2414 return str.str;
2417 private Property? parse_property (IdlNodeProperty prop_node) {
2418 weak IdlNode node = (IdlNode) prop_node;
2420 if (prop_node.deprecated) {
2421 return null;
2424 if (!prop_node.readable && !prop_node.writable) {
2425 // buggy GIDL definition
2426 prop_node.readable = true;
2427 prop_node.writable = true;
2430 var prop = new Property (fix_prop_name (node.name), parse_type (prop_node.type), null, null, current_source_reference);
2431 prop.access = SymbolAccessibility.PUBLIC;
2432 prop.interface_only = true;
2434 if (prop_node.type.is_interface && prop_node.type.interface == "GStrv") {
2435 prop.no_array_length = true;
2436 prop.array_null_terminated = true;
2439 if (prop_node.readable) {
2440 prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, null);
2442 if (prop_node.writable) {
2443 prop.set_accessor = new PropertyAccessor (false, false, false, prop.property_type.copy (), null, null);
2444 if (prop_node.construct_only) {
2445 prop.set_accessor.construction = true;
2446 } else {
2447 prop.set_accessor.writable = true;
2448 prop.set_accessor.construction = prop_node.@construct;
2452 var attributes = get_attributes ("%s:%s".printf (current_data_type.get_cname (), node.name));
2453 if (attributes != null) {
2454 foreach (string attr in attributes) {
2455 var nv = attr.split ("=", 2);
2456 if (nv[0] == "hidden") {
2457 if (eval (nv[1]) == "1") {
2458 return null;
2460 } else if (nv[0] == "type_arguments") {
2461 parse_type_arguments_from_string (prop.property_type, eval (nv[1]));
2462 } else if (nv[0] == "deprecated") {
2463 if (eval (nv[1]) == "1") {
2464 prop.deprecated = true;
2466 } else if (nv[0] == "replacement") {
2467 prop.replacement = eval (nv[1]);
2468 } else if (nv[0] == "deprecated_since") {
2469 prop.deprecated_since = eval (nv[1]);
2470 } else if (nv[0] == "accessor_method") {
2471 if (eval (nv[1]) == "0") {
2472 prop.no_accessor_method = true;
2474 } else if (nv[0] == "owned_get") {
2475 if (eval (nv[1]) == "1") {
2476 prop.get_accessor.value_type.value_owned = true;
2478 } else if (nv[0] == "type_name") {
2479 prop.property_type = parse_type_from_string (eval (nv[1]), false);
2480 } else if (nv[0] == "experimental") {
2481 if (eval (nv[1]) == "1") {
2482 prop.experimental = true;
2488 if (current_type_symbol_set != null) {
2489 current_type_symbol_set.add (prop.name);
2492 return prop;
2495 private Constant? parse_constant (IdlNodeConstant const_node) {
2496 weak IdlNode node = (IdlNode) const_node;
2498 var type = parse_type (const_node.type);
2499 if (type == null) {
2500 return null;
2503 var c = new Constant (node.name, type, null, current_source_reference);
2504 c.external = true;
2506 string[] attributes = get_attributes (node.name);
2507 if (attributes != null) {
2508 foreach (string attr in attributes) {
2509 var nv = attr.split ("=", 2);
2510 if (nv[0] == "cheader_filename") {
2511 c.add_cheader_filename (eval (nv[1]));
2512 } else if (nv[0] == "deprecated") {
2513 if (eval (nv[1]) == "1") {
2514 c.deprecated = true;
2516 } else if (nv[0] == "replacement") {
2517 c.replacement = eval (nv[1]);
2518 } else if (nv[0] == "deprecated_since") {
2519 c.deprecated_since = eval (nv[1]);
2520 } else if (nv[0] == "hidden") {
2521 if (eval (nv[1]) == "1") {
2522 return null;
2524 } else if (nv[0] == "experimental") {
2525 if (eval (nv[1]) == "1") {
2526 c.experimental = true;
2532 c.access = SymbolAccessibility.PUBLIC;
2534 return c;
2537 private Field? parse_field (IdlNodeField field_node) {
2538 weak IdlNode node = (IdlNode) field_node;
2539 bool unhidden = false;
2541 var type = parse_type (field_node.type);
2542 if (type == null) {
2543 return null;
2546 string cheader_filename = null;
2547 string ctype = null;
2548 string array_length_cname = null;
2549 string array_length_type = null;
2550 bool array_null_terminated = false;
2551 bool deprecated = false;
2552 string deprecated_since = null;
2553 string replacement = null;
2554 bool experimental = false;
2556 var attributes = get_attributes ("%s.%s".printf (current_data_type.get_cname (), node.name));
2557 if (attributes != null) {
2558 foreach (string attr in attributes) {
2559 var nv = attr.split ("=", 2);
2560 if (nv[0] == "hidden") {
2561 if (eval (nv[1]) == "1") {
2562 return null;
2563 } else {
2564 unhidden = true;
2566 } else if (nv[0] == "is_array") {
2567 if (eval (nv[1]) == "1") {
2568 type = new ArrayType (type, 1, type.source_reference);
2570 } else if (nv[0] == "weak") {
2571 if (eval (nv[1]) == "0") {
2572 type.value_owned = true;
2574 } else if (nv[0] == "value_owned") {
2575 if (eval (nv[1]) == "0") {
2576 type.value_owned = false;
2577 } else if (eval (nv[1]) == "1") {
2578 type.value_owned = true;
2580 } else if (nv[0] == "type_name") {
2581 type = parse_type_from_string (eval (nv[1]), true);
2582 } else if (nv[0] == "type_arguments") {
2583 parse_type_arguments_from_string (type, eval (nv[1]));
2584 } else if (nv[0] == "deprecated") {
2585 if (eval (nv[1]) == "1") {
2586 deprecated = true;
2588 } else if (nv[0] == "replacement") {
2589 replacement = eval (nv[1]);
2590 } else if (nv[0] == "deprecated_since") {
2591 deprecated_since = eval (nv[1]);
2592 } else if (nv[0] == "cheader_filename") {
2593 cheader_filename = eval (nv[1]);
2594 } else if (nv[0] == "ctype") {
2595 ctype = eval (nv[1]);
2596 } else if (nv[0] == "array_null_terminated") {
2597 if (eval (nv[1]) == "1") {
2598 array_null_terminated = true;
2600 } else if (nv[0] == "array_length_cname") {
2601 array_length_cname = eval (nv[1]);
2602 } else if (nv[0] == "array_length_type") {
2603 array_length_type = eval (nv[1]);
2604 } else if (nv[0] == "experimental") {
2605 if (eval (nv[1]) == "1") {
2606 experimental = true;
2612 if (node.name.has_prefix("_") && !unhidden) {
2613 return null;
2616 if (current_type_symbol_set != null) {
2617 current_type_symbol_set.add (node.name);
2620 string field_name = node.name;
2621 if (field_name == "string") {
2622 // avoid conflict with string type
2623 field_name = "str";
2626 var field = new Field (field_name, type, null, current_source_reference);
2627 field.access = SymbolAccessibility.PUBLIC;
2629 if (field_name != node.name) {
2630 field.set_cname (node.name);
2633 if (deprecated) {
2634 field.deprecated = true;
2636 if (deprecated_since != null) {
2637 field.deprecated_since = deprecated_since;
2640 if (replacement != null) {
2641 field.replacement = replacement;
2645 if (experimental) {
2646 field.experimental = true;
2649 if (ctype != null) {
2650 field.set_ctype (ctype);
2653 if (cheader_filename != null) {
2654 field.add_cheader_filename (cheader_filename);
2657 if (array_null_terminated) {
2658 field.array_null_terminated = true;
2661 if (array_length_cname != null || array_length_type != null) {
2662 if (array_length_cname != null) {
2663 field.set_array_length_cname (array_length_cname);
2665 if (array_length_type != null) {
2666 field.array_length_type = array_length_type;
2668 } else {
2669 field.no_array_length = true;
2672 return field;
2675 private string[]? get_attributes (string codenode) {
2676 var attributes = codenode_attributes_map.get (codenode);
2678 if (attributes == null) {
2679 var dot_required = (-1 != codenode.index_of_char ('.'));
2680 var colon_required = (-1 != codenode.index_of_char (':'));
2682 var pattern_specs = codenode_attributes_patterns.get_keys ();
2683 foreach (PatternSpec* pattern in pattern_specs) {
2684 var pspec = codenode_attributes_patterns[pattern];
2686 if ((dot_required && -1 == pspec.index_of_char ('.')) ||
2687 (colon_required && -1 == pspec.index_of_char (':'))) {
2688 continue;
2691 if (pattern->match_string (codenode)) {
2692 return get_attributes (pspec);
2697 if (attributes == null) {
2698 return null;
2701 GLib.SList<string> attr_list = new GLib.SList<string> ();
2702 var attr = new GLib.StringBuilder.sized (attributes.length);
2703 var attributes_len = attributes.length;
2704 unowned string remaining = attributes;
2705 bool quoted = false, escaped = false;
2706 for (int b = 0 ; b < attributes_len ; b++) {
2707 unichar c = remaining.get_char ();
2709 if (escaped) {
2710 escaped = false;
2711 attr.append_unichar (c);
2712 } else {
2713 if (c == '"') {
2714 attr.append_unichar (c);
2715 quoted = !quoted;
2716 } else if (c == '\\') {
2717 escaped = true;
2718 } else if (!quoted && (c == ' ')) {
2719 attr_list.prepend (attr.str);
2720 attr.truncate (0);
2721 } else {
2722 attr.append_unichar (c);
2726 remaining = (string) ((char*) remaining + remaining.index_of_nth_char (1));
2729 if (attr.len > 0) {
2730 attr_list.prepend (attr.str);
2733 var attrs = new string[attr_list.length ()];
2734 unowned GLib.SList<string>? attr_i = attr_list;
2735 for (int a = 0 ; a < attrs.length ; a++, attr_i = attr_i.next) {
2736 attrs[(attrs.length - 1) - a] = attr_i.data;
2739 return attrs;
2742 private string eval (string s) {
2743 return ((s.length >= 2) && s.has_prefix ("\"") && s.has_suffix ("\"")) ? s.substring (1, s.length - 2) : s;
2746 private Signal? parse_signal (IdlNodeSignal sig_node) {
2747 weak IdlNode node = (IdlNode) sig_node;
2749 if (sig_node.deprecated || sig_node.result == null) {
2750 return null;
2753 var sig = new Signal (fix_prop_name (node.name), parse_param (sig_node.result), current_source_reference);
2754 sig.access = SymbolAccessibility.PUBLIC;
2756 var attributes = get_attributes ("%s::%s".printf (current_data_type.get_cname (), sig.name));
2757 if (attributes != null) {
2758 string ns_name = null;
2759 foreach (string attr in attributes) {
2760 var nv = attr.split ("=", 2);
2761 if (nv[0] == "name") {
2762 sig.set_cname (sig.name);
2763 sig.name = eval (nv[1]);
2764 } else if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
2765 sig.has_emitter = true;
2766 } else if (nv[0] == "hidden") {
2767 if (eval (nv[1]) == "1") {
2768 return null;
2770 } else if (nv[0] == "deprecated") {
2771 if (eval (nv[1]) == "1") {
2772 sig.deprecated = true;
2774 } else if (nv[0] == "replacement") {
2775 sig.replacement = eval (nv[1]);
2776 } else if (nv[0] == "deprecated_since") {
2777 sig.deprecated_since = eval (nv[1]);
2778 } else if (nv[0] == "transfer_ownership") {
2779 if (eval (nv[1]) == "1") {
2780 sig.return_type.value_owned = true;
2782 } else if (nv[0] == "namespace_name") {
2783 ns_name = eval (nv[1]);
2784 } else if (nv[0] == "type_name") {
2785 sig.return_type = parse_type_from_string (eval (nv[1]), false);
2786 } else if (nv[0] == "type_arguments") {
2787 parse_type_arguments_from_string (sig.return_type, eval (nv[1]));
2788 } else if (nv[0] == "experimental") {
2789 if (eval (nv[1]) == "1") {
2790 sig.experimental = true;
2794 if (ns_name != null) {
2795 ((UnresolvedType) sig.return_type).unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
2799 sig.is_virtual = true;
2801 bool first = true;
2803 foreach (weak IdlNodeParam param in sig_node.parameters) {
2804 if (first) {
2805 // ignore implicit first signal parameter (sender)
2806 first = false;
2807 continue;
2810 weak IdlNode param_node = (IdlNode) param;
2812 ParameterDirection direction;
2813 var param_type = parse_param (param, out direction);
2814 var p = new Parameter (param_node.name, param_type);
2815 p.direction = direction;
2817 bool hide_param = false;
2818 bool show_param = false;
2819 attributes = get_attributes ("%s::%s.%s".printf (current_data_type.get_cname (), sig.name, param_node.name));
2820 if (attributes != null) {
2821 string ns_name = null;
2822 foreach (string attr in attributes) {
2823 var nv = attr.split ("=", 2);
2824 if (nv[0] == "hidden") {
2825 if (eval (nv[1]) == "1") {
2826 hide_param = true;
2827 } else if (eval (nv[1]) == "0") {
2828 show_param = true;
2830 } else if (nv[0] == "is_array") {
2831 if (eval (nv[1]) == "1") {
2832 param_type = new ArrayType (param_type, 1, param_type.source_reference);
2833 p.variable_type = param_type;
2834 p.direction = ParameterDirection.IN;
2836 } else if (nv[0] == "no_array_length") {
2837 if (eval (nv[1]) == "1") {
2838 p.no_array_length = true;
2840 } else if (nv[0] == "array_length_type") {
2841 p.array_length_type = eval (nv[1]);
2842 } else if (nv[0] == "array_null_terminated") {
2843 if (eval (nv[1]) == "1") {
2844 p.no_array_length = true;
2845 p.array_null_terminated = true;
2847 } else if (nv[0] == "is_out") {
2848 if (eval (nv[1]) == "1") {
2849 p.direction = ParameterDirection.OUT;
2851 } else if (nv[0] == "is_ref") {
2852 if (eval (nv[1]) == "1") {
2853 p.direction = ParameterDirection.REF;
2855 } else if (nv[0] == "nullable") {
2856 if (eval (nv[1]) == "1") {
2857 param_type.nullable = true;
2859 } else if (nv[0] == "transfer_ownership") {
2860 if (eval (nv[1]) == "1") {
2861 param_type.value_owned = true;
2863 } else if (nv[0] == "type_name") {
2864 p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
2865 } else if (nv[0] == "type_arguments") {
2866 parse_type_arguments_from_string (p.variable_type, eval (nv[1]));
2867 } else if (nv[0] == "namespace_name") {
2868 ns_name = eval (nv[1]);
2871 if (ns_name != null) {
2872 ((UnresolvedType) param_type).unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
2876 if (show_param || !hide_param) {
2877 sig.add_parameter (p);
2881 return sig;
2885 // vim:sw=8 noet