gidlparser: Support error types for delegates
[vala-lang.git] / vapigen / valagidlparser.vala
bloba0b775deff341ac888699294f25fd878435025b5
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;
455 bool suppress_throws = false;
456 string? error_types = null;
458 var attributes = get_attributes (node.name);
459 if (attributes != null) {
460 foreach (string attr in attributes) {
461 var nv = attr.split ("=", 2);
462 if (nv[0] == "hidden") {
463 if (eval (nv[1]) == "1") {
464 return null;
466 } else if (nv[0] == "cheader_filename") {
467 cb.add_cheader_filename (eval (nv[1]));
468 } else if (nv[0] == "has_target") {
469 if (eval (nv[1]) == "0") {
470 check_has_target = false;
471 } else if (eval (nv[1]) == "1") {
472 cb.has_target = true;
474 } else if (nv[0] == "transfer_ownership") {
475 if (eval (nv[1]) == "1") {
476 return_type.value_owned = true;
478 } else if (nv[0] == "is_array") {
479 if (eval (nv[1]) == "1") {
480 return_type = new ArrayType (return_type, 1, return_type.source_reference);
481 cb.return_type = return_type;
483 } else if (nv[0] == "throws") {
484 if (eval (nv[1]) == "0") {
485 suppress_throws = true;
487 } else if (nv[0] == "error_types") {
488 error_types = eval (nv[1]);
489 } else if (nv[0] == "array_length_type") {
490 cb.array_length_type = eval (nv[1]);
491 } else if (nv[0] == "type_name") {
492 cb.return_type = return_type = parse_type_from_string (eval (nv[1]), return_type.value_owned);
493 } else if (nv[0] == "deprecated") {
494 if (eval (nv[1]) == "1") {
495 cb.deprecated = true;
497 } else if (nv[0] == "replacement") {
498 cb.replacement = eval (nv[1]);
499 } else if (nv[0] == "deprecated_since") {
500 cb.deprecated_since = eval (nv[1]);
501 } else if (nv[0] == "type_arguments") {
502 parse_type_arguments_from_string (return_type, eval (nv[1]));
503 } else if (nv[0] == "instance_pos") {
504 cb.cinstance_parameter_position = double.parse (eval (nv[1]));
505 } else if (nv[0] == "type_parameters") {
506 foreach (string type_param_name in eval (nv[1]).split (",")) {
507 cb.add_type_parameter (new TypeParameter (type_param_name, current_source_reference));
509 } else if (nv[0] == "experimental") {
510 if (eval (nv[1]) == "1") {
511 cb.experimental = true;
517 uint remaining_params = f_node.parameters.length ();
518 foreach (weak IdlNodeParam param in f_node.parameters) {
519 weak IdlNode param_node = (IdlNode) param;
521 if (check_has_target && remaining_params == 1 && (param_node.name == "user_data" || param_node.name == "data")) {
522 // hide user_data parameter for instance delegates
523 cb.has_target = true;
524 } else {
525 // check for GError parameter
526 if (suppress_throws == false && param_is_exception (param)) {
527 if (error_types == null)
528 cb.add_error_type (parse_type (param.type));
529 remaining_params--;
530 continue;
533 string param_name = param_node.name;
534 if (param_name == "string") {
535 // avoid conflict with string type
536 param_name = "str";
537 } else if (param_name == "self") {
538 // avoid conflict with delegate target
539 param_name = "_self";
542 ParameterDirection direction;
543 var param_type = parse_param (param, out direction);
544 var p = new Parameter (param_name, param_type);
545 p.direction = direction;
547 bool hide_param = false;
548 bool show_param = false;
549 bool array_requested = false;
550 bool out_requested = false;
551 attributes = get_attributes ("%s.%s".printf (node.name, param_node.name));
552 if (attributes != null) {
553 foreach (string attr in attributes) {
554 var nv = attr.split ("=", 2);
555 if (nv[0] == "hidden") {
556 if (eval (nv[1]) == "1") {
557 hide_param = true;
558 } else if (eval (nv[1]) == "0") {
559 show_param = true;
561 } else if (nv[0] == "is_array") {
562 if (eval (nv[1]) == "1") {
563 param_type = new ArrayType (param_type, 1, param_type.source_reference);
564 p.variable_type = param_type;
565 if (!out_requested) {
566 p.direction = ParameterDirection.IN;
568 array_requested = true;
570 } else if (nv[0] == "is_out") {
571 if (eval (nv[1]) == "1") {
572 p.direction = ParameterDirection.OUT;
573 out_requested = true;
574 if (!array_requested && param_type is ArrayType) {
575 var array_type = (ArrayType) param_type;
576 param_type = array_type.element_type;
577 p.variable_type = param_type;
580 } else if (nv[0] == "is_ref") {
581 if (eval (nv[1]) == "1") {
582 p.direction = ParameterDirection.REF;
583 if (!array_requested && param_type is ArrayType) {
584 var array_type = (ArrayType) param_type;
585 param_type = array_type.element_type;
586 p.variable_type = param_type;
589 } else if (nv[0] == "takes_ownership") {
590 if (eval (nv[1]) == "1") {
591 param_type.value_owned = true;
593 } else if (nv[0] == "nullable") {
594 if (eval (nv[1]) == "1") {
595 param_type.nullable = true;
597 } else if (nv[0] == "type_arguments") {
598 parse_type_arguments_from_string (param_type, eval (nv[1]));
599 } else if (nv[0] == "no_array_length") {
600 if (eval (nv[1]) == "1") {
601 p.no_array_length = true;
603 } else if (nv[0] == "array_length_type") {
604 p.array_length_type = eval (nv[1]);
605 } else if (nv[0] == "array_null_terminated") {
606 if (eval (nv[1]) == "1") {
607 p.no_array_length = true;
608 p.array_null_terminated = true;
610 } else if (nv[0] == "type_name") {
611 p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
616 if (show_param || !hide_param) {
617 cb.add_parameter (p);
621 remaining_params--;
624 if (suppress_throws == false && error_types != null) {
625 var type_args = eval (error_types).split (",");
626 foreach (string type_arg in type_args) {
627 cb.add_error_type (parse_type_from_string (type_arg, true));
631 return cb;
634 private bool is_reference_type (string cname) {
635 var st_attributes = get_attributes (cname);
636 if (st_attributes != null) {
637 foreach (string attr in st_attributes) {
638 var nv = attr.split ("=", 2);
639 if (nv[0] == "is_value_type" && eval (nv[1]) == "1") {
640 return false;
644 return true;
647 private void parse_struct (IdlNodeStruct st_node, Symbol container, IdlModule module) {
648 weak IdlNode node = (IdlNode) st_node;
650 if (st_node.deprecated) {
651 return;
654 string name = fix_type_name (node.name, container);
656 if (!is_reference_type (node.name)) {
657 var st = container.scope.lookup (name) as Struct;
658 if (st == null) {
659 st = new Struct (name, current_source_reference);
660 st.access = SymbolAccessibility.PUBLIC;
662 var st_attributes = get_attributes (node.name);
663 if (st_attributes != null) {
664 foreach (string attr in st_attributes) {
665 var nv = attr.split ("=", 2);
666 if (nv[0] == "cheader_filename") {
667 st.add_cheader_filename (eval (nv[1]));
668 } else if (nv[0] == "hidden") {
669 if (eval (nv[1]) == "1") {
670 return;
672 } else if (nv[0] == "base_type") {
673 st.base_type = parse_type_string (eval (nv[1]));
674 } else if (nv[0] == "rank") {
675 st.set_rank (int.parse (eval (nv[1])));
676 } else if (nv[0] == "simple_type") {
677 if (eval (nv[1]) == "1") {
678 st.set_simple_type (true);
680 } else if (nv[0] == "immutable") {
681 if (eval (nv[1]) == "1") {
682 st.is_immutable = true;
684 } else if (nv[0] == "has_type_id") {
685 if (eval (nv[1]) == "0") {
686 st.has_type_id = false;
688 } else if (nv[0] == "type_id") {
689 st.set_type_id (eval (nv[1]));
690 } else if (nv[0] == "has_copy_function") {
691 if (eval (nv[1]) == "0") {
692 st.has_copy_function = false;
694 } else if (nv[0] == "deprecated") {
695 if (eval (nv[1]) == "1") {
696 st.deprecated = true;
698 } else if (nv[0] == "replacement") {
699 st.replacement = eval (nv[1]);
700 } else if (nv[0] == "deprecated_since") {
701 st.deprecated_since = eval (nv[1]);
702 } else if (nv[0] == "has_destroy_function") {
703 if (eval (nv[1]) == "0") {
704 st.has_destroy_function = false;
706 } else if (nv[0] == "experimental") {
707 if (eval (nv[1]) == "1") {
708 st.experimental = true;
714 add_symbol_to_container (container, st);
715 current_source_file.add_node (st);
718 current_data_type = st;
720 foreach (weak IdlNode member in st_node.members) {
721 if (member.type == IdlNodeTypeId.FUNCTION) {
722 var m = parse_function ((IdlNodeFunction) member);
723 if (m != null) {
724 st.add_method (m);
726 } else if (member.type == IdlNodeTypeId.FIELD) {
727 var f = parse_field ((IdlNodeField) member);
728 if (f != null) {
729 st.add_field (f);
734 current_data_type = null;
735 } else {
736 bool ref_function_void = false;
737 string ref_function = null;
738 string unref_function = null;
739 string copy_function = null;
740 string free_function = null;
742 var cl = container.scope.lookup (name) as Class;
743 if (cl == null) {
744 string base_class = null;
746 cl = new Class (name, current_source_reference);
747 cl.access = SymbolAccessibility.PUBLIC;
748 cl.is_compact = true;
750 var cl_attributes = get_attributes (node.name);
751 if (cl_attributes != null) {
752 foreach (string attr in cl_attributes) {
753 var nv = attr.split ("=", 2);
754 if (nv[0] == "cheader_filename") {
755 cl.add_cheader_filename (eval (nv[1]));
756 } else if (nv[0] == "base_class") {
757 base_class = eval (nv[1]);
758 } else if (nv[0] == "hidden") {
759 if (eval (nv[1]) == "1") {
760 return;
762 } else if (nv[0] == "is_immutable") {
763 if (eval (nv[1]) == "1") {
764 cl.is_immutable = true;
766 } else if (nv[0] == "const_cname") {
767 cl.const_cname = eval (nv[1]);
768 } else if (nv[0] == "is_fundamental") {
769 if (eval (nv[1]) == "1") {
770 cl.is_compact = false;
772 } else if (nv[0] == "abstract" && base_class != null) {
773 if (eval (nv[1]) == "1") {
774 cl.is_abstract = true;
776 } else if (nv[0] == "free_function") {
777 free_function = eval (nv[1]);
778 } else if (nv[0] == "ref_function") {
779 ref_function = eval (nv[1]);
780 } else if (nv[0] == "unref_function") {
781 unref_function = eval (nv[1]);
782 } else if (nv[0] == "copy_function") {
783 copy_function = eval (nv[1]);
784 } else if (nv[0] == "ref_function_void") {
785 if (eval (nv[1]) == "1") {
786 ref_function_void = true;
788 } else if (nv[0] == "deprecated") {
789 if (eval (nv[1]) == "1") {
790 cl.deprecated = true;
792 } else if (nv[0] == "replacement") {
793 cl.replacement = eval (nv[1]);
794 } else if (nv[0] == "deprecated_since") {
795 cl.deprecated_since = eval (nv[1]);
796 } else if (nv[0] == "type_parameters") {
797 foreach (string type_param_name in eval (nv[1]).split (",")) {
798 cl.add_type_parameter (new TypeParameter (type_param_name, current_source_reference));
800 } else if (nv[0] == "experimental") {
801 if (eval (nv[1]) == "1") {
802 cl.experimental = true;
808 add_symbol_to_container (container, cl);
809 current_source_file.add_node (cl);
811 if (base_class != null) {
812 var parent = parse_type_string (base_class);
813 cl.add_base_type (parent);
817 current_data_type = cl;
819 foreach (weak IdlNode member in st_node.members) {
820 if (member.type == IdlNodeTypeId.FUNCTION) {
821 if ((ref_function == null) && (member.name == "ref")) {
822 ref_function = ((IdlNodeFunction) member).symbol;
823 ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
824 } else if ((unref_function == null) && (member.name == "unref")) {
825 unref_function = ((IdlNodeFunction) member).symbol;
826 } else if ((free_function == null) && (member.name == "free" || member.name == "destroy")) {
827 free_function = ((IdlNodeFunction) member).symbol;
828 } else {
829 if ((copy_function == null) && (member.name == "copy")) {
830 copy_function = ((IdlNodeFunction) member).symbol;
832 var m = parse_function ((IdlNodeFunction) member);
833 if (m != null) {
834 cl.add_method (m);
837 } else if (member.type == IdlNodeTypeId.FIELD) {
838 var f = parse_field ((IdlNodeField) member);
839 if (f != null) {
840 cl.add_field (f);
845 if (ref_function != null) {
846 cl.set_ref_function (ref_function);
847 cl.ref_function_void = ref_function_void;
849 if (copy_function != null) {
850 cl.set_dup_function (copy_function);
852 if (unref_function != null) {
853 cl.set_unref_function (unref_function);
854 } else if (free_function != null) {
855 cl.set_free_function (free_function);
858 current_data_type = null;
862 private void parse_union (IdlNodeUnion un_node, Symbol container, IdlModule module) {
863 weak IdlNode node = (IdlNode) un_node;
865 if (un_node.deprecated) {
866 return;
869 string name = fix_type_name (node.name, container);
871 if (!is_reference_type (node.name)) {
872 var st = container.scope.lookup (name) as Struct;
873 if (st == null) {
874 st = new Struct (name, current_source_reference);
875 st.access = SymbolAccessibility.PUBLIC;
877 var st_attributes = get_attributes (node.name);
878 if (st_attributes != null) {
879 foreach (string attr in st_attributes) {
880 var nv = attr.split ("=", 2);
881 if (nv[0] == "cheader_filename") {
882 st.add_cheader_filename (eval (nv[1]));
883 } else if (nv[0] == "deprecated") {
884 if (eval (nv[1]) == "1") {
885 st.deprecated = true;
887 } else if (nv[0] == "replacement") {
888 st.replacement = eval (nv[1]);
889 } else if (nv[0] == "deprecated_since") {
890 st.deprecated_since = eval (nv[1]);
891 } else if (nv[0] == "hidden") {
892 if (eval (nv[1]) == "1") {
893 return;
895 } else if (nv[0] == "experimental") {
896 if (eval (nv[1]) == "1") {
897 st.experimental = true;
903 add_symbol_to_container (container, st);
904 current_source_file.add_node (st);
907 current_data_type = st;
909 foreach (weak IdlNode member in un_node.members) {
910 if (member.type == IdlNodeTypeId.FUNCTION) {
911 var m = parse_function ((IdlNodeFunction) member);
912 if (m != null) {
913 st.add_method (m);
915 } else if (member.type == IdlNodeTypeId.FIELD) {
916 var f = parse_field ((IdlNodeField) member);
917 if (f != null) {
918 st.add_field (f);
923 current_data_type = null;
924 } else {
925 var cl = container.scope.lookup (name) as Class;
926 if (cl == null) {
927 cl = new Class (name, current_source_reference);
928 cl.access = SymbolAccessibility.PUBLIC;
929 cl.is_compact = true;
931 var cl_attributes = get_attributes (node.name);
932 if (cl_attributes != null) {
933 foreach (string attr in cl_attributes) {
934 var nv = attr.split ("=", 2);
935 if (nv[0] == "cheader_filename") {
936 cl.add_cheader_filename (eval (nv[1]));
937 } else if (nv[0] == "hidden") {
938 if (eval (nv[1]) == "1") {
939 return;
945 add_symbol_to_container (container, cl);
946 current_source_file.add_node (cl);
949 current_data_type = cl;
951 bool ref_function_void = false;
952 string ref_function = null;
953 string unref_function = null;
954 string copy_function = null;
955 string free_function = null;
957 foreach (weak IdlNode member in un_node.members) {
958 if (member.type == IdlNodeTypeId.FUNCTION) {
959 if (member.name == "ref") {
960 ref_function = ((IdlNodeFunction) member).symbol;
961 ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
962 } else if (member.name == "unref") {
963 unref_function = ((IdlNodeFunction) member).symbol;
964 } else if (member.name == "free" || member.name == "destroy") {
965 free_function = ((IdlNodeFunction) member).symbol;
966 } else {
967 if (member.name == "copy") {
968 copy_function = ((IdlNodeFunction) member).symbol;
970 var m = parse_function ((IdlNodeFunction) member);
971 if (m != null) {
972 cl.add_method (m);
975 } else if (member.type == IdlNodeTypeId.FIELD) {
976 var f = parse_field ((IdlNodeField) member);
977 if (f != null) {
978 cl.add_field (f);
983 if (ref_function != null) {
984 cl.set_ref_function (ref_function);
985 cl.ref_function_void = ref_function_void;
987 if (copy_function != null) {
988 cl.set_dup_function (copy_function);
990 if (unref_function != null) {
991 cl.set_unref_function (unref_function);
992 } else if (free_function != null) {
993 cl.set_free_function (free_function);
996 current_data_type = null;
1000 private void parse_boxed (IdlNodeBoxed boxed_node, Symbol container, IdlModule module) {
1001 weak IdlNode node = (IdlNode) boxed_node;
1003 string name = fix_type_name (node.name, container);
1005 var node_attributes = get_attributes (node.name);
1006 if (node_attributes != null) {
1007 foreach (string attr in node_attributes) {
1008 var nv = attr.split ("=", 2);
1009 if (nv[0] == "hidden") {
1010 return;
1015 if (!is_reference_type (node.name)) {
1016 var st = container.scope.lookup (name) as Struct;
1017 if (st == null) {
1018 st = new Struct (name, current_source_reference);
1019 st.access = SymbolAccessibility.PUBLIC;
1021 var st_attributes = get_attributes (node.name);
1022 if (st_attributes != null) {
1023 foreach (string attr in st_attributes) {
1024 var nv = attr.split ("=", 2);
1025 if (nv[0] == "cheader_filename") {
1026 st.add_cheader_filename (eval (nv[1]));
1027 } else if (nv[0] == "deprecated") {
1028 if (eval (nv[1]) == "1") {
1029 st.deprecated = true;
1031 } else if (nv[0] == "replacement") {
1032 st.replacement = eval (nv[1]);
1033 } else if (nv[0] == "deprecated_since") {
1034 st.deprecated_since = eval (nv[1]);
1035 } else if (nv[0] == "immutable") {
1036 if (eval (nv[1]) == "1") {
1037 st.is_immutable = true;
1039 } else if (nv[0] == "has_copy_function") {
1040 if (eval (nv[1]) == "0") {
1041 st.has_copy_function = false;
1043 } else if (nv[0] == "has_destroy_function") {
1044 if (eval (nv[1]) == "0") {
1045 st.has_destroy_function = false;
1047 } else if (nv[0] == "experimental") {
1048 if (eval (nv[1]) == "1") {
1049 st.experimental = true;
1055 add_symbol_to_container (container, st);
1056 st.set_type_id (st.get_upper_case_cname ("TYPE_"));
1057 current_source_file.add_node (st);
1060 current_data_type = st;
1062 foreach (weak IdlNode member in boxed_node.members) {
1063 if (member.type == IdlNodeTypeId.FUNCTION) {
1064 var m = parse_function ((IdlNodeFunction) member);
1065 if (m != null) {
1066 st.add_method (m);
1068 } else if (member.type == IdlNodeTypeId.FIELD) {
1069 var f = parse_field ((IdlNodeField) member);
1070 if (f != null) {
1071 st.add_field (f);
1076 current_data_type = null;
1077 } else {
1078 bool ref_function_void = false;
1079 string ref_function = null;
1080 string unref_function = null;
1081 string copy_function = null;
1082 string free_function = null;
1084 var cl = container.scope.lookup (name) as Class;
1085 if (cl == null) {
1086 string base_class = null;
1088 cl = new Class (name, current_source_reference);
1089 cl.access = SymbolAccessibility.PUBLIC;
1090 cl.is_compact = true;
1092 var cl_attributes = get_attributes (node.name);
1093 if (cl_attributes != null) {
1094 foreach (string attr in cl_attributes) {
1095 var nv = attr.split ("=", 2);
1096 if (nv[0] == "cheader_filename") {
1097 cl.add_cheader_filename (eval (nv[1]));
1098 } else if (nv[0] == "base_class") {
1099 base_class = eval (nv[1]);
1100 } else if (nv[0] == "is_immutable") {
1101 if (eval (nv[1]) == "1") {
1102 cl.is_immutable = true;
1104 } else if (nv[0] == "deprecated") {
1105 if (eval (nv[1]) == "1") {
1106 cl.deprecated = true;
1108 } else if (nv[0] == "replacement") {
1109 cl.replacement = eval (nv[1]);
1110 } else if (nv[0] == "deprecated_since") {
1111 cl.deprecated_since = eval (nv[1]);
1112 } else if (nv[0] == "const_cname") {
1113 cl.const_cname = eval (nv[1]);
1114 } else if (nv[0] == "free_function") {
1115 free_function = eval (nv[1]);
1116 } else if (nv[0] == "ref_function") {
1117 ref_function = eval (nv[1]);
1118 } else if (nv[0] == "unref_function") {
1119 unref_function = eval (nv[1]);
1120 } else if (nv[0] == "copy_function") {
1121 copy_function = eval (nv[1]);
1122 } else if (nv[0] == "ref_function_void") {
1123 if (eval (nv[1]) == "1") {
1124 ref_function_void = true;
1126 } else if (nv[0] == "experimental") {
1127 if (eval (nv[1]) == "1") {
1128 cl.experimental = true;
1134 add_symbol_to_container (container, cl);
1135 cl.set_type_id (cl.get_upper_case_cname ("TYPE_"));
1136 current_source_file.add_node (cl);
1138 if (base_class != null) {
1139 var parent = parse_type_string (base_class);
1140 cl.add_base_type (parent);
1144 current_data_type = cl;
1146 foreach (weak IdlNode member in boxed_node.members) {
1147 if (member.type == IdlNodeTypeId.FUNCTION) {
1148 if (member.name == "ref") {
1149 ref_function = ((IdlNodeFunction) member).symbol;
1150 ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
1151 } else if (member.name == "unref") {
1152 unref_function = ((IdlNodeFunction) member).symbol;
1153 } else if (member.name == "free" || member.name == "destroy") {
1154 free_function = ((IdlNodeFunction) member).symbol;
1155 } else {
1156 if (member.name == "copy") {
1157 copy_function = ((IdlNodeFunction) member).symbol;
1159 var m = parse_function ((IdlNodeFunction) member);
1160 if (m != null) {
1161 cl.add_method (m);
1164 } else if (member.type == IdlNodeTypeId.FIELD) {
1165 var f = parse_field ((IdlNodeField) member);
1166 if (f != null) {
1167 cl.add_field (f);
1172 if (ref_function != null) {
1173 cl.set_ref_function (ref_function);
1174 cl.ref_function_void = ref_function_void;
1176 if (copy_function != null) {
1177 cl.set_dup_function (copy_function);
1179 if (unref_function != null) {
1180 cl.set_unref_function (unref_function);
1181 } else if (free_function != null) {
1182 cl.set_free_function (free_function);
1185 current_data_type = null;
1189 private void parse_enum (IdlNodeEnum en_node, Symbol container, IdlModule module, bool is_flags) {
1190 weak IdlNode node = (IdlNode) en_node;
1191 string name = fix_type_name (node.name, container);
1192 bool existing = true;
1194 var en = container.scope.lookup (name) as Enum;
1195 if (en == null) {
1196 en = new Enum (name, current_source_reference);
1197 en.access = SymbolAccessibility.PUBLIC;
1198 existing = false;
1199 } else {
1200 // ignore dummy enum values in -custom.vala files
1201 // they exist for syntactical reasons
1202 var dummy = (EnumValue) en.scope.lookup ("__DUMMY__");
1203 if (dummy != null) {
1204 en.get_values ().remove (dummy);
1205 en.scope.remove ("__DUMMY__");
1209 en.has_type_id = (en_node.gtype_name != null && en_node.gtype_name != "");
1211 string common_prefix = null;
1213 foreach (weak IdlNode value in en_node.values) {
1214 var val_attributes = get_attributes (value.name);
1215 bool is_hidden = false;
1216 if (val_attributes != null) {
1217 foreach (string attr in val_attributes) {
1218 var nv = attr.split ("=", 2);
1219 if (nv[0] == "hidden" && eval(nv[1]) == "1") {
1220 is_hidden = true;
1225 if (is_hidden) {
1226 continue;
1229 if (common_prefix == null) {
1230 common_prefix = value.name;
1231 while (common_prefix.length > 0 && !common_prefix.has_suffix ("_")) {
1232 // FIXME: could easily be made faster
1233 common_prefix = common_prefix.substring (0, common_prefix.length - 1);
1235 } else {
1236 while (!value.name.has_prefix (common_prefix)) {
1237 common_prefix = common_prefix.substring (0, common_prefix.length - 1);
1240 while (common_prefix.length > 0 && (!common_prefix.has_suffix ("_") ||
1241 (value.name.get_char (common_prefix.length).isdigit ()) && (value.name.length - common_prefix.length) <= 1)) {
1242 // enum values may not consist solely of digits
1243 common_prefix = common_prefix.substring (0, common_prefix.length - 1);
1247 bool is_errordomain = false;
1249 var cheader_filenames = new ArrayList<string> ();
1251 var en_attributes = get_attributes (node.name);
1252 if (en_attributes != null) {
1253 foreach (string attr in en_attributes) {
1254 var nv = attr.split ("=", 2);
1255 if (nv[0] == "common_prefix") {
1256 common_prefix = eval (nv[1]);
1257 } else if (nv[0] == "cheader_filename") {
1258 cheader_filenames.add (eval (nv[1]));
1259 en.add_cheader_filename (eval (nv[1]));
1260 } else if (nv[0] == "hidden") {
1261 if (eval (nv[1]) == "1") {
1262 return;
1264 } else if (nv[0] == "deprecated") {
1265 if (eval (nv[1]) == "1") {
1266 en.deprecated = true;
1268 } else if (nv[0] == "replacement") {
1269 en.replacement = eval (nv[1]);
1270 } else if (nv[0] == "deprecated_since") {
1271 en.deprecated_since = eval (nv[1]);
1272 } else if (nv[0] == "rename_to") {
1273 en.name = eval (nv[1]);
1274 } else if (nv[0] == "errordomain") {
1275 if (eval (nv[1]) == "1") {
1276 is_errordomain = true;
1278 } else if (nv[0] == "to_string") {
1279 var return_type = new UnresolvedType ();
1280 return_type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1281 return_type.value_owned = false;
1282 var m = new Method ("to_string", return_type, current_source_reference);
1283 m.access = SymbolAccessibility.PUBLIC;
1284 m.set_cname (eval(nv[1]));
1285 en.add_method (m);
1286 } else if (nv[0] == "experimental") {
1287 if (eval (nv[1]) == "1") {
1288 en.experimental = true;
1294 en.set_cprefix (common_prefix);
1296 foreach (weak IdlNode value2 in en_node.values) {
1297 var val_attributes = get_attributes (value2.name);
1298 bool is_hidden = false;
1299 if (val_attributes != null) {
1300 foreach (string attr in val_attributes) {
1301 var nv = attr.split ("=", 2);
1302 if (nv[0] == "hidden" && eval(nv[1]) == "1") {
1303 is_hidden = true;
1308 if (!is_hidden) {
1309 var ev = new EnumValue (value2.name.substring (common_prefix.length), null);
1310 en.add_value (ev);
1314 if (is_errordomain) {
1315 var ed = new ErrorDomain (en.name, current_source_reference);
1316 ed.access = SymbolAccessibility.PUBLIC;
1317 ed.set_cprefix (common_prefix);
1319 foreach (string filename in cheader_filenames) {
1320 ed.add_cheader_filename (filename);
1323 foreach (EnumValue ev in en.get_values ()) {
1324 ed.add_code (new ErrorCode (ev.name));
1327 current_source_file.add_node (ed);
1328 if (!existing) {
1329 add_symbol_to_container (container, ed);
1331 } else {
1332 en.is_flags = is_flags;
1333 current_source_file.add_node (en);
1334 if (!existing) {
1335 add_symbol_to_container (container, en);
1340 private void parse_object (IdlNodeInterface node, Symbol container, IdlModule module) {
1341 string name = fix_type_name (((IdlNode) node).name, container);
1343 string base_class = null;
1345 var cl = container.scope.lookup (name) as Class;
1346 if (cl == null) {
1347 cl = new Class (name, current_source_reference);
1348 cl.access = SymbolAccessibility.PUBLIC;
1350 var attributes = get_attributes (node.gtype_name);
1351 if (attributes != null) {
1352 foreach (string attr in attributes) {
1353 var nv = attr.split ("=", 2);
1354 if (nv[0] == "cheader_filename") {
1355 cl.add_cheader_filename (eval (nv[1]));
1356 } else if (nv[0] == "base_class") {
1357 base_class = eval (nv[1]);
1358 } else if (nv[0] == "hidden") {
1359 if (eval (nv[1]) == "1") {
1360 return;
1362 } else if (nv[0] == "type_check_function") {
1363 cl.type_check_function = eval (nv[1]);
1364 } else if (nv[0] == "deprecated") {
1365 if (eval (nv[1]) == "1") {
1366 cl.deprecated = true;
1368 } else if (nv[0] == "replacement") {
1369 cl.replacement = eval (nv[1]);
1370 } else if (nv[0] == "deprecated_since") {
1371 cl.deprecated_since = eval (nv[1]);
1372 } else if (nv[0] == "type_id") {
1373 cl.set_type_id (eval (nv[1]));
1374 } else if (nv[0] == "abstract") {
1375 if (eval (nv[1]) == "1") {
1376 cl.is_abstract = true;
1378 } else if (nv[0] == "experimental") {
1379 if (eval (nv[1]) == "1") {
1380 cl.experimental = true;
1386 add_symbol_to_container (container, cl);
1387 current_source_file.add_node (cl);
1390 if (base_class != null) {
1391 var parent = parse_type_string (base_class);
1392 cl.add_base_type (parent);
1393 } else if (node.parent != null) {
1394 var parent = parse_type_string (node.parent);
1395 cl.add_base_type (parent);
1396 } else {
1397 var gobject_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Object");
1398 cl.add_base_type (new UnresolvedType.from_symbol (gobject_symbol));
1401 foreach (string iface_name in node.interfaces) {
1402 bool skip_iface = false;
1404 var attributes = get_attributes (iface_name);
1405 if (attributes != null) {
1406 foreach (string attr in attributes) {
1407 var nv = attr.split ("=", 2);
1408 if (nv[0] == "hidden") {
1409 if (eval (nv[1]) == "1") {
1410 skip_iface = true;
1416 if (skip_iface) {
1417 continue;
1420 var iface = parse_type_string (iface_name);
1421 cl.add_base_type (iface);
1424 current_data_type = cl;
1426 current_type_symbol_set = new HashSet<string> (str_hash, str_equal);
1427 var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
1428 var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
1430 foreach (weak IdlNode member in node.members) {
1431 if (member.type == IdlNodeTypeId.FUNCTION) {
1432 current_type_func_map.set (member.name, (IdlNodeFunction) member);
1434 if (member.type == IdlNodeTypeId.VFUNC) {
1435 current_type_vfunc_map.set (member.name, "1");
1439 foreach (weak IdlNode member in node.members) {
1440 if (member.type == IdlNodeTypeId.FUNCTION) {
1441 // Ignore if vfunc (handled below)
1442 if (!current_type_vfunc_map.contains (member.name)) {
1443 var m = parse_function ((IdlNodeFunction) member);
1444 if (m != null) {
1445 cl.add_method (m);
1448 } else if (member.type == IdlNodeTypeId.VFUNC) {
1449 var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name));
1450 if (m != null) {
1451 cl.add_method (m);
1453 } else if (member.type == IdlNodeTypeId.PROPERTY) {
1454 var prop = parse_property ((IdlNodeProperty) member);
1455 if (prop != null) {
1456 cl.add_property (prop);
1458 } else if (member.type == IdlNodeTypeId.SIGNAL) {
1459 var sig = parse_signal ((IdlNodeSignal) member);
1460 if (sig != null) {
1461 cl.add_signal (sig);
1466 foreach (weak IdlNode member in node.members) {
1467 if (member.type == IdlNodeTypeId.FIELD) {
1468 if (!current_type_symbol_set.contains (member.name)) {
1469 var f = parse_field ((IdlNodeField) member);
1470 if (f != null) {
1471 cl.add_field (f);
1477 foreach (Property prop in cl.get_properties ()) {
1478 var getter = "get_%s".printf (prop.name);
1480 if (prop.get_accessor != null && !current_type_symbol_set.contains (getter)) {
1481 prop.no_accessor_method = true;
1484 var setter = "set_%s".printf (prop.name);
1486 if (prop.set_accessor != null && prop.set_accessor.writable
1487 && !current_type_symbol_set.contains (setter)) {
1488 prop.no_accessor_method = true;
1491 if (prop.no_accessor_method && prop.get_accessor != null) {
1492 prop.get_accessor.value_type.value_owned = true;
1496 handle_async_methods (cl);
1498 if (cl.default_construction_method == null) {
1499 // always provide constructor in generated bindings
1500 // to indicate that implicit Object () chainup is allowed
1501 var cm = new CreationMethod (null, null, cl.source_reference);
1502 cm.has_construct_function = false;
1503 cm.access = SymbolAccessibility.PROTECTED;
1504 cl.add_method (cm);
1507 current_data_type = null;
1508 current_type_symbol_set = null;
1511 private void parse_interface (IdlNodeInterface node, Symbol container, IdlModule module) {
1512 string name = fix_type_name (node.gtype_name, container);
1514 var iface = container.scope.lookup (name) as Interface;
1515 if (iface == null) {
1516 iface = new Interface (name, current_source_reference);
1517 iface.access = SymbolAccessibility.PUBLIC;
1519 var attributes = get_attributes (node.gtype_name);
1520 if (attributes != null) {
1521 foreach (string attr in attributes) {
1522 var nv = attr.split ("=", 2);
1523 if (nv[0] == "cheader_filename") {
1524 iface.add_cheader_filename (eval (nv[1]));
1525 } else if (nv[0] == "type_cname") {
1526 iface.set_type_cname (eval (nv[1]));
1527 } else if (nv[0] == "lower_case_csuffix") {
1528 iface.set_lower_case_csuffix (eval (nv[1]));
1533 foreach (string prereq_name in node.prerequisites) {
1534 var prereq = parse_type_string (prereq_name);
1535 iface.add_prerequisite (prereq);
1538 add_symbol_to_container (container, iface);
1539 current_source_file.add_node (iface);
1542 current_data_type = iface;
1544 var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
1545 var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
1547 foreach (weak IdlNode member in node.members) {
1548 if (member.type == IdlNodeTypeId.FUNCTION) {
1549 current_type_func_map.set (member.name, (IdlNodeFunction) member);
1551 if (member.type == IdlNodeTypeId.VFUNC) {
1552 current_type_vfunc_map.set (member.name, "1");
1556 foreach (weak IdlNode member in node.members) {
1557 if (member.type == IdlNodeTypeId.FUNCTION) {
1558 // Ignore if vfunc (handled below)
1559 if (!current_type_vfunc_map.contains (member.name)) {
1560 var m = parse_function ((IdlNodeFunction) member, true);
1561 if (m != null) {
1562 iface.add_method (m);
1565 } else if (member.type == IdlNodeTypeId.VFUNC) {
1566 var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name), true);
1567 if (m != null) {
1568 iface.add_method (m);
1570 } else if (member.type == IdlNodeTypeId.PROPERTY) {
1571 var prop = parse_property ((IdlNodeProperty) member);
1572 if (prop != null) {
1573 iface.add_property (prop);
1575 } else if (member.type == IdlNodeTypeId.SIGNAL) {
1576 var sig = parse_signal ((IdlNodeSignal) member);
1577 if (sig != null) {
1578 iface.add_signal (sig);
1579 sig.is_virtual = false;
1584 handle_async_methods (iface);
1586 current_data_type = null;
1589 void handle_async_methods (ObjectTypeSymbol type_symbol) {
1590 Set<Method> finish_methods = new HashSet<Method> ();
1591 var methods = type_symbol.get_methods ();
1593 foreach (Method m in methods) {
1594 if (m.coroutine) {
1595 string finish_method_base;
1596 if (m.name.has_suffix ("_async")) {
1597 finish_method_base = m.name.substring (0, m.name.length - "_async".length);
1598 } else {
1599 finish_method_base = m.name;
1601 var finish_method = type_symbol.scope.lookup (finish_method_base + "_finish") as Method;
1603 // check if the method is using non-standard finish method name
1604 if (finish_method == null) {
1605 var method_cname = m.get_finish_cname ();
1606 foreach (Method method in type_symbol.get_methods ()) {
1607 if (method.get_cname () == method_cname) {
1608 finish_method = method;
1609 break;
1614 if (finish_method != null) {
1615 m.return_type = finish_method.return_type.copy ();
1616 m.no_array_length = finish_method.no_array_length;
1617 m.array_null_terminated = finish_method.array_null_terminated;
1618 foreach (var param in finish_method.get_parameters ()) {
1619 if (param.direction == ParameterDirection.OUT) {
1620 var async_param = param.copy ();
1621 if (m.scope.lookup (param.name) != null) {
1622 // parameter name conflict
1623 async_param.name += "_out";
1625 m.add_parameter (async_param);
1628 foreach (DataType error_type in finish_method.get_error_types ()) {
1629 m.add_error_type (error_type.copy ());
1631 finish_methods.add (finish_method);
1636 foreach (Method m in finish_methods)
1638 type_symbol.scope.remove (m.name);
1639 methods.remove (m);
1643 private DataType? parse_type (IdlNodeType type_node, out ParameterDirection direction = null) {
1644 ParameterDirection dir = ParameterDirection.IN;
1646 var type = new UnresolvedType ();
1647 if (type_node.tag == TypeTag.VOID) {
1648 if (type_node.is_pointer) {
1649 return new PointerType (new VoidType ());
1650 } else {
1651 return new VoidType ();
1653 } else if (type_node.tag == TypeTag.BOOLEAN) {
1654 type.unresolved_symbol = new UnresolvedSymbol (null, "bool");
1655 } else if (type_node.tag == TypeTag.INT8) {
1656 type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1657 } else if (type_node.tag == TypeTag.UINT8) {
1658 type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1659 } else if (type_node.tag == TypeTag.INT16) {
1660 type.unresolved_symbol = new UnresolvedSymbol (null, "int16");
1661 } else if (type_node.tag == TypeTag.UINT16) {
1662 type.unresolved_symbol = new UnresolvedSymbol (null, "uint16");
1663 } else if (type_node.tag == TypeTag.INT32) {
1664 type.unresolved_symbol = new UnresolvedSymbol (null, "int32");
1665 } else if (type_node.tag == TypeTag.UINT32) {
1666 type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
1667 } else if (type_node.tag == TypeTag.INT64) {
1668 type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1669 } else if (type_node.tag == TypeTag.UINT64) {
1670 type.unresolved_symbol = new UnresolvedSymbol (null, "uint64");
1671 } else if (type_node.tag == TypeTag.INT) {
1672 type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1673 } else if (type_node.tag == TypeTag.UINT) {
1674 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1675 } else if (type_node.tag == TypeTag.LONG) {
1676 type.unresolved_symbol = new UnresolvedSymbol (null, "long");
1677 } else if (type_node.tag == TypeTag.ULONG) {
1678 type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1679 } else if (type_node.tag == TypeTag.SSIZE) {
1680 type.unresolved_symbol = new UnresolvedSymbol (null, "ssize_t");
1681 } else if (type_node.tag == TypeTag.SIZE) {
1682 type.unresolved_symbol = new UnresolvedSymbol (null, "size_t");
1683 } else if (type_node.tag == TypeTag.FLOAT) {
1684 type.unresolved_symbol = new UnresolvedSymbol (null, "float");
1685 } else if (type_node.tag == TypeTag.DOUBLE) {
1686 type.unresolved_symbol = new UnresolvedSymbol (null, "double");
1687 } else if (type_node.tag == TypeTag.UTF8) {
1688 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1689 } else if (type_node.tag == TypeTag.FILENAME) {
1690 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1691 } else if (type_node.tag == TypeTag.ARRAY) {
1692 var element_type = parse_type (type_node.parameter_type1);
1693 type = element_type as UnresolvedType;
1694 if (type == null) {
1695 return element_type;
1697 return new ArrayType (element_type, 1, element_type.source_reference);
1698 } else if (type_node.tag == TypeTag.LIST) {
1699 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "List");
1700 } else if (type_node.tag == TypeTag.SLIST) {
1701 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "SList");
1702 } else if (type_node.tag == TypeTag.HASH) {
1703 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "HashTable");
1704 } else if (type_node.tag == TypeTag.ERROR) {
1705 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Error");
1706 } else if (type_node.is_interface) {
1707 var n = type_node.@interface;
1709 if (n == "") {
1710 return null;
1713 if (n.has_prefix ("const-")) {
1714 n = n.substring ("const-".length);
1717 if (type_node.is_pointer &&
1718 (n == "gchar" || n == "char")) {
1719 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1720 if (type_node.unparsed.has_suffix ("**")) {
1721 dir = ParameterDirection.OUT;
1723 } else if (n == "gunichar") {
1724 type.unresolved_symbol = new UnresolvedSymbol (null, "unichar");
1725 } else if (n == "gchar") {
1726 type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1727 } else if (n == "guchar" || n == "guint8") {
1728 type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1729 if (type_node.is_pointer) {
1730 return new ArrayType (type, 1, type.source_reference);
1732 } else if (n == "gushort") {
1733 type.unresolved_symbol = new UnresolvedSymbol (null, "ushort");
1734 } else if (n == "gshort") {
1735 type.unresolved_symbol = new UnresolvedSymbol (null, "short");
1736 } else if (n == "gconstpointer" || n == "void") {
1737 return new PointerType (new VoidType ());
1738 } else if (n == "goffset" || n == "off_t") {
1739 type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1740 } else if (n == "value_array") {
1741 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "ValueArray");
1742 } else if (n == "time_t") {
1743 type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1744 } else if (n == "socklen_t") {
1745 type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
1746 } else if (n == "mode_t") {
1747 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1748 } else if (n == "gint" || n == "pid_t") {
1749 type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1750 } else if (n == "unsigned" || n == "unsigned-int") {
1751 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1752 } else if (n == "FILE") {
1753 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "FileStream");
1754 } else if (n == "struct") {
1755 return new PointerType (new VoidType ());
1756 } else if (n == "iconv_t") {
1757 return new PointerType (new VoidType ());
1758 } else if (n == "GType") {
1759 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Type");
1760 if (type_node.is_pointer) {
1761 return new ArrayType (type, 1, type.source_reference);
1763 } else if (n == "GStrv") {
1764 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1765 return new ArrayType (type, 1, type.source_reference);
1766 } else {
1767 var named_type = parse_type_string (n);
1768 type = named_type as UnresolvedType;
1769 if (type == null) {
1770 return named_type;
1772 if (is_simple_type (n)) {
1773 if (type_node.is_pointer) {
1774 dir = ParameterDirection.OUT;
1776 } else if (type_node.unparsed.has_suffix ("**")) {
1777 dir = ParameterDirection.OUT;
1780 } else {
1781 stdout.printf ("%d\n", type_node.tag);
1783 if (&direction != null) {
1784 direction = dir;
1786 return type;
1789 private bool is_simple_type (string type_name) {
1790 var st = cname_type_map[type_name] as Struct;
1791 if (st != null && st.is_simple_type ()) {
1792 return true;
1795 return false;
1798 private DataType parse_type_string (string n) {
1799 if (n == "va_list") {
1800 // unsupported
1801 return new PointerType (new VoidType ());
1804 var type = new UnresolvedType ();
1806 var dt = cname_type_map[n];
1807 if (dt != null) {
1808 UnresolvedSymbol parent_symbol = null;
1809 if (dt.parent_symbol.name != null) {
1810 parent_symbol = new UnresolvedSymbol (null, dt.parent_symbol.name);
1812 type.unresolved_symbol = new UnresolvedSymbol (parent_symbol, dt.name);
1813 return type;
1816 var type_attributes = get_attributes (n);
1818 string ns_name = null;
1820 if (null != type_attributes) {
1821 foreach (string attr in type_attributes) {
1822 var nv = attr.split ("=", 2);
1824 if (nv[0] == "cprefix") {
1825 type.unresolved_symbol = new UnresolvedSymbol (null, n.substring (eval (nv[1]).length));
1826 } else if (nv[0] == "name") {
1827 type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1828 } else if (nv[0] == "namespace") {
1829 ns_name = eval (nv[1]);
1830 } else if (nv[0] == "rename_to") {
1831 type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1836 if (type.unresolved_symbol != null) {
1837 if (type.unresolved_symbol.name == "pointer") {
1838 return new PointerType (new VoidType ());
1840 if (ns_name != null) {
1841 type.unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
1843 return type;
1846 if (n.has_prefix (current_namespace.name)) {
1847 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, current_namespace.name), n.substring (current_namespace.name.length));
1848 } else if (n.has_prefix ("G")) {
1849 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), n.substring (1));
1850 } else {
1851 var name_parts = n.split (".", 2);
1852 if (name_parts[1] == null) {
1853 type.unresolved_symbol = new UnresolvedSymbol (null, name_parts[0]);
1854 } else {
1855 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, name_parts[0]), name_parts[1]);
1859 return type;
1862 private DataType? parse_param (IdlNodeParam param, out ParameterDirection direction = null) {
1863 var type = parse_type (param.type, out direction);
1865 // disable for now as null_ok not yet correctly set
1866 // type.non_null = !param.null_ok;
1868 return type;
1871 private UnresolvedSymbol? parse_symbol_from_string (string symbol_string, SourceReference? source_reference = null) {
1872 UnresolvedSymbol? sym = null;
1873 foreach (unowned string s in symbol_string.split (".")) {
1874 sym = new UnresolvedSymbol (sym, s, source_reference);
1876 if (sym == null) {
1877 Report.error (source_reference, "a symbol must be specified");
1879 return sym;
1882 private bool parse_type_arguments_from_string (DataType parent_type, string type_arguments, SourceReference? source_reference = null) {
1883 int type_arguments_length = (int) type_arguments.length;
1884 GLib.StringBuilder current = new GLib.StringBuilder.sized (type_arguments_length);
1886 int depth = 0;
1887 for (var c = 0 ; c < type_arguments_length ; c++) {
1888 if (type_arguments[c] == '<' || type_arguments[c] == '[') {
1889 depth++;
1890 current.append_unichar (type_arguments[c]);
1891 } else if (type_arguments[c] == '>' || type_arguments[c] == ']') {
1892 depth--;
1893 current.append_unichar (type_arguments[c]);
1894 } else if (type_arguments[c] == ',') {
1895 if (depth == 0) {
1896 var dt = parse_type_from_string (current.str, true, source_reference);
1897 if (dt == null) {
1898 return false;
1900 parent_type.add_type_argument (dt);
1901 current.truncate ();
1902 } else {
1903 current.append_unichar (type_arguments[c]);
1905 } else {
1906 current.append_unichar (type_arguments[c]);
1910 var dt = parse_type_from_string (current.str, true, source_reference);
1911 if (dt == null) {
1912 return false;
1914 parent_type.add_type_argument (dt);
1916 return true;
1919 private DataType? parse_type_from_string (string type_string, bool owned_by_default, SourceReference? source_reference = null) {
1920 if (type_from_string_regex == null) {
1921 try {
1922 type_from_string_regex = new GLib.Regex ("^(?:(owned|unowned|weak) +)?([0-9a-zA-Z_\\.]+)(?:<(.+)>)?(\\*+)?(\\[(,*)?\\])?(\\?)?$", GLib.RegexCompileFlags.ANCHORED | GLib.RegexCompileFlags.DOLLAR_ENDONLY | GLib.RegexCompileFlags.OPTIMIZE);
1923 } catch (GLib.RegexError e) {
1924 GLib.error ("Unable to compile regex: %s", e.message);
1928 GLib.MatchInfo match;
1929 if (!type_from_string_regex.match (type_string, 0, out match)) {
1930 Report.error (source_reference, "unable to parse type");
1931 return null;
1934 DataType? type = null;
1936 var ownership_data = match.fetch (1);
1937 var type_name = match.fetch (2);
1938 var type_arguments_data = match.fetch (3);
1939 var pointers_data = match.fetch (4);
1940 var array_data = match.fetch (5);
1941 var array_dimension_data = match.fetch (6);
1942 var nullable_data = match.fetch (7);
1944 var nullable = nullable_data != null && nullable_data.length > 0;
1946 if (ownership_data == null && type_name == "void") {
1947 if (array_data == null && !nullable) {
1948 type = new VoidType (source_reference);
1949 if (pointers_data != null) {
1950 for (int i=0; i < pointers_data.length; i++) {
1951 type = new PointerType (type);
1954 return type;
1955 } else {
1956 Report.error (source_reference, "invalid void type");
1957 return null;
1961 bool value_owned = owned_by_default;
1963 if (ownership_data == "owned") {
1964 value_owned = true;
1965 } else if (ownership_data == "unowned") {
1966 value_owned = false;
1969 var sym = parse_symbol_from_string (type_name, source_reference);
1970 if (sym == null) {
1971 return null;
1973 type = new UnresolvedType.from_symbol (sym, source_reference);
1975 if (type_arguments_data != null && type_arguments_data.length > 0) {
1976 if (!parse_type_arguments_from_string (type, type_arguments_data, source_reference)) {
1977 return null;
1981 if (pointers_data != null) {
1982 for (int i=0; i < pointers_data.length; i++) {
1983 type = new PointerType (type);
1987 if (array_data != null && array_data.length > 0) {
1988 type = new ArrayType (type, array_dimension_data.length + 1, source_reference);
1991 type.nullable = nullable;
1992 type.value_owned = value_owned;
1993 return type;
1996 private Method? create_method (string name, string symbol, IdlNodeParam? res, GLib.List<IdlNodeParam>? parameters, bool is_constructor, bool is_interface) {
1997 DataType return_type = null;
1998 if (res != null) {
1999 return_type = parse_param (res);
2002 Method m;
2003 if (!is_interface && (is_constructor || name.has_prefix ("new"))) {
2004 m = new CreationMethod (null, name, current_source_reference);
2005 m.has_construct_function = false;
2006 if (m.name == "new") {
2007 m.name = null;
2008 } else if (m.name.has_prefix ("new_")) {
2009 m.name = m.name.substring ("new_".length);
2011 // For classes, check whether a creation method return type equals to the
2012 // type of the class created. If the types do not match (e.g. in most
2013 // gtk widgets) add an attribute to the creation method indicating the used
2014 // return type.
2015 if (current_data_type is Class && res != null) {
2016 if ("%s*".printf (current_data_type.get_cname()) != res.type.unparsed) {
2017 ((CreationMethod)m).custom_return_type_cname = res.type.unparsed;
2020 } else {
2021 m = new Method (name, return_type, current_source_reference);
2023 m.access = SymbolAccessibility.PUBLIC;
2025 if (current_type_symbol_set != null) {
2026 current_type_symbol_set.add (name);
2029 if (current_data_type != null) {
2030 var sig_attributes = get_attributes ("%s::%s".printf (current_data_type.get_cname (), name));
2031 if (sig_attributes != null) {
2032 foreach (string attr in sig_attributes) {
2033 var nv = attr.split ("=", 2);
2034 if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
2035 return null;
2041 bool add_ellipsis = false;
2042 bool suppress_throws = false;
2043 string? error_types = null;
2045 var attributes = get_attributes (symbol);
2046 if (attributes != null) {
2047 foreach (string attr in attributes) {
2048 var nv = attr.split ("=", 2);
2049 if (nv[0] == "name") {
2050 m.set_cname (m.name);
2051 m.name = eval (nv[1]);
2052 } else if (nv[0] == "hidden") {
2053 if (eval (nv[1]) == "1") {
2054 return null;
2056 } else if (nv[0] == "ellipsis") {
2057 if (eval (nv[1]) == "1") {
2058 add_ellipsis = true;
2060 } else if (nv[0] == "printf_format") {
2061 if (eval (nv[1]) == "1") {
2062 m.printf_format = true;
2064 } else if (nv[0] == "transfer_ownership") {
2065 if (eval (nv[1]) == "1") {
2066 return_type.value_owned = true;
2068 } else if (nv[0] == "nullable") {
2069 if (eval (nv[1]) == "1") {
2070 return_type.nullable = true;
2072 } else if (nv[0] == "sentinel") {
2073 m.sentinel = eval (nv[1]);
2074 } else if (nv[0] == "is_array") {
2075 if (eval (nv[1]) == "1") {
2076 return_type = new ArrayType (return_type, 1, return_type.source_reference);
2077 m.return_type = return_type;
2079 } else if (nv[0] == "throws") {
2080 if (eval (nv[1]) == "0") {
2081 suppress_throws = true;
2083 } else if (nv[0] == "error_types") {
2084 error_types = eval (nv[1]);
2085 } else if (nv[0] == "no_array_length") {
2086 if (eval (nv[1]) == "1") {
2087 m.no_array_length = true;
2089 } else if (nv[0] == "array_null_terminated") {
2090 if (eval (nv[1]) == "1") {
2091 m.no_array_length = true;
2092 m.array_null_terminated = true;
2094 } else if (nv[0] == "array_length_type") {
2095 m.array_length_type = eval (nv[1]);
2096 } else if (nv[0] == "type_name") {
2097 m.return_type = return_type = parse_type_from_string (eval (nv[1]), return_type.value_owned);
2098 } else if (nv[0] == "type_arguments") {
2099 parse_type_arguments_from_string (return_type, eval (nv[1]));
2100 } else if (nv[0] == "deprecated") {
2101 if (eval (nv[1]) == "1") {
2102 m.deprecated = true;
2104 } else if (nv[0] == "replacement") {
2105 m.replacement = eval (nv[1]);
2106 } else if (nv[0] == "deprecated_since") {
2107 m.deprecated_since = eval (nv[1]);
2108 } else if (nv[0] == "cheader_filename") {
2109 m.add_cheader_filename (eval (nv[1]));
2110 } else if (nv[0] == "abstract") {
2111 if (eval (nv[1]) == "1") {
2112 m.is_abstract = true;
2114 } else if (nv[0] == "virtual") {
2115 if (eval (nv[1]) == "1") {
2116 m.is_virtual = true;
2118 } else if (nv[0] == "vfunc_name") {
2119 m.vfunc_name = eval (nv[1]);
2120 } else if (nv[0] == "finish_name") {
2121 m.set_finish_cname (eval (nv[1]));
2122 } else if (nv[0] == "async") {
2123 if (eval (nv[1]) == "1") {
2124 // force async function, even if it doesn't end in _async
2125 m.coroutine = true;
2127 } else if (nv[0] == "parent") {
2128 Symbol container = get_container_from_name (eval (nv[1]));
2129 var prefix = container.get_lower_case_cprefix ();
2130 if (symbol.has_prefix (prefix)) {
2131 m.set_cname (m.name);
2132 m.name = symbol.substring (prefix.length);
2134 } else if (nv[0] == "experimental") {
2135 if (eval (nv[1]) == "1") {
2136 m.experimental = true;
2142 m.set_cname (symbol);
2144 bool first = true;
2145 Parameter last_param = null;
2146 DataType last_param_type = null;
2147 foreach (weak IdlNodeParam param in parameters) {
2148 weak IdlNode param_node = (IdlNode) param;
2150 if (first) {
2151 first = false;
2152 if (!(m is CreationMethod) &&
2153 current_data_type != null &&
2154 param.type.is_interface &&
2155 (param_node.name == "self" ||
2156 param.type.@interface.has_suffix (current_data_type.get_cname ()))) {
2157 // instance method
2158 continue;
2159 } else if (!(m is CreationMethod) &&
2160 current_data_type != null &&
2161 param.type.is_interface &&
2162 (param_node.name == "klass" ||
2163 param.type.@interface.has_suffix ("%sClass".printf(current_data_type.get_cname ())))) {
2164 // class method
2165 m.binding = MemberBinding.CLASS;
2166 if (m.name.has_prefix ("class_")) {
2167 m.name = m.name.substring ("class_".length, m.name.length - "class_".length);
2169 continue;
2170 } else {
2171 // static method
2172 m.binding = MemberBinding.STATIC;
2176 if (param.type.@interface == "GAsyncReadyCallback" && (symbol.has_suffix ("_async") || m.coroutine)) {
2177 // async method
2178 m.coroutine = true;
2179 continue;
2182 // check for GError parameter
2183 if (suppress_throws == false && param_is_exception (param)) {
2184 if (error_types == null)
2185 m.add_error_type (parse_type (param.type));
2186 continue;
2189 string param_name = param_node.name;
2190 if (param_name == "result") {
2191 // avoid conflict with generated result variable
2192 param_name = "_result";
2193 } else if (param_name == "string") {
2194 // avoid conflict with string type
2195 param_name = "str";
2197 ParameterDirection direction;
2198 var param_type = parse_param (param, out direction);
2199 var p = new Parameter (param_name, param_type);
2200 p.direction = direction;
2202 bool hide_param = false;
2203 bool show_param = false;
2204 bool set_array_length_pos = false;
2205 double array_length_pos = 0;
2206 bool set_delegate_target_pos = false;
2207 double delegate_target_pos = 0;
2208 bool array_requested = false;
2209 bool out_requested = false;
2210 attributes = get_attributes ("%s.%s".printf (symbol, param_node.name));
2211 if (attributes != null) {
2212 foreach (string attr in attributes) {
2213 var nv = attr.split ("=", 2);
2214 if (nv[0] == "is_array") {
2215 if (eval (nv[1]) == "1") {
2216 param_type = new ArrayType (param_type, 1, param_type.source_reference);
2217 p.variable_type = param_type;
2218 if (!out_requested) {
2219 p.direction = ParameterDirection.IN;
2221 array_requested = true;
2223 } else if (nv[0] == "is_out") {
2224 if (eval (nv[1]) == "1") {
2225 p.direction = ParameterDirection.OUT;
2226 out_requested = true;
2227 if (!array_requested && param_type is ArrayType) {
2228 var array_type = (ArrayType) param_type;
2229 param_type = array_type.element_type;
2230 p.variable_type = param_type;
2233 } else if (nv[0] == "is_ref") {
2234 if (eval (nv[1]) == "1") {
2235 p.direction = ParameterDirection.REF;
2236 if (!array_requested && param_type is ArrayType) {
2237 var array_type = (ArrayType) param_type;
2238 param_type = array_type.element_type;
2239 p.variable_type = param_type;
2242 } else if (nv[0] == "nullable") {
2243 if (eval (nv[1]) == "1") {
2244 param_type.nullable = true;
2246 } else if (nv[0] == "transfer_ownership") {
2247 if (eval (nv[1]) == "1") {
2248 param_type.value_owned = true;
2250 } else if (nv[0] == "takes_ownership") {
2251 if (eval (nv[1]) == "1") {
2252 param_type.value_owned = true;
2254 } else if (nv[0] == "value_owned") {
2255 if (eval (nv[1]) == "0") {
2256 param_type.value_owned = false;
2257 } else if (eval (nv[1]) == "1") {
2258 param_type.value_owned = true;
2260 } else if (nv[0] == "hidden") {
2261 if (eval (nv[1]) == "1") {
2262 hide_param = true;
2263 } else if (eval (nv[1]) == "0") {
2264 show_param = true;
2266 } else if (nv[0] == "no_array_length") {
2267 if (eval (nv[1]) == "1") {
2268 p.no_array_length = true;
2270 } else if (nv[0] == "array_length_type") {
2271 p.array_length_type = eval (nv[1]);
2272 } else if (nv[0] == "array_null_terminated") {
2273 if (eval (nv[1]) == "1") {
2274 p.no_array_length = true;
2275 p.array_null_terminated = true;
2277 } else if (nv[0] == "array_length_pos") {
2278 set_array_length_pos = true;
2279 array_length_pos = double.parse (eval (nv[1]));
2280 } else if (nv[0] == "delegate_target_pos") {
2281 set_delegate_target_pos = true;
2282 delegate_target_pos = double.parse (eval (nv[1]));
2283 } else if (nv[0] == "type_name") {
2284 p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
2285 } else if (nv[0] == "ctype") {
2286 p.ctype = eval (nv[1]);
2287 } else if (nv[0] == "type_arguments") {
2288 parse_type_arguments_from_string (param_type, eval (nv[1]));
2289 } else if (nv[0] == "default_value") {
2290 var val = eval (nv[1]);
2291 if (val == "null") {
2292 p.initializer = new NullLiteral (param_type.source_reference);
2293 } else if (val == "true") {
2294 p.initializer = new BooleanLiteral (true, param_type.source_reference);
2295 } else if (val == "false") {
2296 p.initializer = new BooleanLiteral (false, param_type.source_reference);
2297 } else if (val == "") {
2298 p.initializer = new StringLiteral ("\"\"", param_type.source_reference);
2299 } else {
2300 if (int64.try_parse (val)) {
2301 p.initializer = new IntegerLiteral (val, param_type.source_reference);
2302 } else {
2303 if (double.try_parse (val)) {
2304 p.initializer = new RealLiteral (val, param_type.source_reference);
2305 } else {
2306 if (val.has_prefix ("\"") && val.has_suffix ("\"")) {
2307 p.initializer = new StringLiteral (val, param_type.source_reference);
2308 } else {
2309 foreach (var member in val.split (".")) {
2310 p.initializer = new MemberAccess (p.initializer, member, param_type.source_reference);
2320 if (last_param != null && p.name == "n_" + last_param.name) {
2321 if (!(last_param_type is ArrayType)) {
2322 // last_param is array, p is array length
2323 last_param_type = new ArrayType (last_param_type, 1, last_param_type.source_reference);
2324 last_param.variable_type = last_param_type;
2325 last_param.direction = ParameterDirection.IN;
2328 // hide array length param
2329 hide_param = true;
2330 } else if (last_param != null && p.name == "user_data") {
2331 // last_param is delegate
2333 // hide deleate target param
2334 hide_param = true;
2337 if (show_param || !hide_param) {
2338 m.add_parameter (p);
2339 if (set_array_length_pos) {
2340 p.carray_length_parameter_position = array_length_pos;
2342 if (set_delegate_target_pos) {
2343 p.cdelegate_target_parameter_position = delegate_target_pos;
2347 last_param = p;
2348 last_param_type = param_type;
2351 if (suppress_throws == false && error_types != null) {
2352 var type_args = eval (error_types).split (",");
2353 foreach (string type_arg in type_args) {
2354 m.add_error_type (parse_type_from_string (type_arg, true));
2358 if (first) {
2359 // no parameters => static method
2360 m.binding = MemberBinding.STATIC;
2363 if (last_param != null && last_param.name.has_prefix ("first_")) {
2364 last_param.ellipsis = true;
2365 } else if (add_ellipsis) {
2366 m.add_parameter (new Parameter.with_ellipsis ());
2369 return m;
2372 private bool param_is_exception (IdlNodeParam param) {
2373 if (!param.type.is_error) {
2374 return false;
2376 var s = param.type.unparsed.chomp ();
2377 if (s.has_suffix ("**")) {
2378 return true;
2380 return false;
2383 private Method? parse_function (IdlNodeFunction f, bool is_interface = false) {
2384 weak IdlNode node = (IdlNode) f;
2386 if (f.deprecated) {
2387 return null;
2390 return create_method (node.name, f.symbol, f.result, f.parameters, f.is_constructor, is_interface);
2393 private Method parse_virtual (IdlNodeVFunc v, IdlNodeFunction? func, bool is_interface = false) {
2394 weak IdlNode node = (IdlNode) v;
2395 string symbol = "%s%s".printf (current_data_type.get_lower_case_cprefix(), node.name);
2397 if (func != null) {
2398 symbol = func.symbol;
2401 Method m = create_method (node.name, symbol, v.result, func != null ? func.parameters : v.parameters, false, is_interface);
2402 if (m != null) {
2403 m.binding = MemberBinding.INSTANCE;
2404 m.is_virtual = !(m.is_abstract || is_interface);
2405 m.is_abstract = m.is_abstract || is_interface;
2407 var attributes = get_attributes (symbol);
2408 if (attributes != null) {
2409 foreach (string attr in attributes) {
2410 var nv = attr.split ("=", 2);
2411 if (nv[0] == "virtual") {
2412 if (eval (nv[1]) == "0") {
2413 m.is_virtual = false;
2414 m.is_abstract = false;
2415 } else {
2416 m.is_virtual = true;
2417 m.is_abstract = false;
2423 if (func == null) {
2424 m.attributes.append (new Attribute ("NoWrapper", null));
2428 return m;
2431 private string fix_prop_name (string name) {
2432 var str = new StringBuilder ();
2434 string i = name;
2436 while (i.length > 0) {
2437 unichar c = i.get_char ();
2438 if (c == '-') {
2439 str.append_c ('_');
2440 } else {
2441 str.append_unichar (c);
2444 i = i.next_char ();
2447 return str.str;
2450 private Property? parse_property (IdlNodeProperty prop_node) {
2451 weak IdlNode node = (IdlNode) prop_node;
2453 if (prop_node.deprecated) {
2454 return null;
2457 if (!prop_node.readable && !prop_node.writable) {
2458 // buggy GIDL definition
2459 prop_node.readable = true;
2460 prop_node.writable = true;
2463 var prop = new Property (fix_prop_name (node.name), parse_type (prop_node.type), null, null, current_source_reference);
2464 prop.access = SymbolAccessibility.PUBLIC;
2465 prop.interface_only = true;
2467 if (prop_node.type.is_interface && prop_node.type.interface == "GStrv") {
2468 prop.no_array_length = true;
2469 prop.array_null_terminated = true;
2472 if (prop_node.readable) {
2473 prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, null);
2475 if (prop_node.writable) {
2476 prop.set_accessor = new PropertyAccessor (false, false, false, prop.property_type.copy (), null, null);
2477 if (prop_node.construct_only) {
2478 prop.set_accessor.construction = true;
2479 } else {
2480 prop.set_accessor.writable = true;
2481 prop.set_accessor.construction = prop_node.@construct;
2485 var attributes = get_attributes ("%s:%s".printf (current_data_type.get_cname (), node.name));
2486 if (attributes != null) {
2487 foreach (string attr in attributes) {
2488 var nv = attr.split ("=", 2);
2489 if (nv[0] == "hidden") {
2490 if (eval (nv[1]) == "1") {
2491 return null;
2493 } else if (nv[0] == "type_arguments") {
2494 parse_type_arguments_from_string (prop.property_type, eval (nv[1]));
2495 } else if (nv[0] == "deprecated") {
2496 if (eval (nv[1]) == "1") {
2497 prop.deprecated = true;
2499 } else if (nv[0] == "replacement") {
2500 prop.replacement = eval (nv[1]);
2501 } else if (nv[0] == "deprecated_since") {
2502 prop.deprecated_since = eval (nv[1]);
2503 } else if (nv[0] == "accessor_method") {
2504 if (eval (nv[1]) == "0") {
2505 prop.no_accessor_method = true;
2507 } else if (nv[0] == "owned_get") {
2508 if (eval (nv[1]) == "1") {
2509 prop.get_accessor.value_type.value_owned = true;
2511 } else if (nv[0] == "type_name") {
2512 prop.property_type = parse_type_from_string (eval (nv[1]), false);
2513 } else if (nv[0] == "experimental") {
2514 if (eval (nv[1]) == "1") {
2515 prop.experimental = true;
2521 if (current_type_symbol_set != null) {
2522 current_type_symbol_set.add (prop.name);
2525 return prop;
2528 private Constant? parse_constant (IdlNodeConstant const_node) {
2529 weak IdlNode node = (IdlNode) const_node;
2531 var type = parse_type (const_node.type);
2532 if (type == null) {
2533 return null;
2536 var c = new Constant (node.name, type, null, current_source_reference);
2537 c.external = true;
2539 string[] attributes = get_attributes (node.name);
2540 if (attributes != null) {
2541 foreach (string attr in attributes) {
2542 var nv = attr.split ("=", 2);
2543 if (nv[0] == "cheader_filename") {
2544 c.add_cheader_filename (eval (nv[1]));
2545 } else if (nv[0] == "deprecated") {
2546 if (eval (nv[1]) == "1") {
2547 c.deprecated = true;
2549 } else if (nv[0] == "replacement") {
2550 c.replacement = eval (nv[1]);
2551 } else if (nv[0] == "deprecated_since") {
2552 c.deprecated_since = eval (nv[1]);
2553 } else if (nv[0] == "hidden") {
2554 if (eval (nv[1]) == "1") {
2555 return null;
2557 } else if (nv[0] == "experimental") {
2558 if (eval (nv[1]) == "1") {
2559 c.experimental = true;
2565 c.access = SymbolAccessibility.PUBLIC;
2567 return c;
2570 private Field? parse_field (IdlNodeField field_node) {
2571 weak IdlNode node = (IdlNode) field_node;
2572 bool unhidden = false;
2574 var type = parse_type (field_node.type);
2575 if (type == null) {
2576 return null;
2579 string cheader_filename = null;
2580 string ctype = null;
2581 string array_length_cname = null;
2582 string array_length_type = null;
2583 bool array_null_terminated = false;
2584 bool deprecated = false;
2585 string deprecated_since = null;
2586 string replacement = null;
2587 bool experimental = false;
2589 var attributes = get_attributes ("%s.%s".printf (current_data_type.get_cname (), node.name));
2590 if (attributes != null) {
2591 foreach (string attr in attributes) {
2592 var nv = attr.split ("=", 2);
2593 if (nv[0] == "hidden") {
2594 if (eval (nv[1]) == "1") {
2595 return null;
2596 } else {
2597 unhidden = true;
2599 } else if (nv[0] == "is_array") {
2600 if (eval (nv[1]) == "1") {
2601 type = new ArrayType (type, 1, type.source_reference);
2603 } else if (nv[0] == "weak") {
2604 if (eval (nv[1]) == "0") {
2605 type.value_owned = true;
2607 } else if (nv[0] == "value_owned") {
2608 if (eval (nv[1]) == "0") {
2609 type.value_owned = false;
2610 } else if (eval (nv[1]) == "1") {
2611 type.value_owned = true;
2613 } else if (nv[0] == "type_name") {
2614 type = parse_type_from_string (eval (nv[1]), true);
2615 } else if (nv[0] == "type_arguments") {
2616 parse_type_arguments_from_string (type, eval (nv[1]));
2617 } else if (nv[0] == "deprecated") {
2618 if (eval (nv[1]) == "1") {
2619 deprecated = true;
2621 } else if (nv[0] == "replacement") {
2622 replacement = eval (nv[1]);
2623 } else if (nv[0] == "deprecated_since") {
2624 deprecated_since = eval (nv[1]);
2625 } else if (nv[0] == "cheader_filename") {
2626 cheader_filename = eval (nv[1]);
2627 } else if (nv[0] == "ctype") {
2628 ctype = eval (nv[1]);
2629 } else if (nv[0] == "array_null_terminated") {
2630 if (eval (nv[1]) == "1") {
2631 array_null_terminated = true;
2633 } else if (nv[0] == "array_length_cname") {
2634 array_length_cname = eval (nv[1]);
2635 } else if (nv[0] == "array_length_type") {
2636 array_length_type = eval (nv[1]);
2637 } else if (nv[0] == "experimental") {
2638 if (eval (nv[1]) == "1") {
2639 experimental = true;
2645 if (node.name.has_prefix("_") && !unhidden) {
2646 return null;
2649 if (current_type_symbol_set != null) {
2650 current_type_symbol_set.add (node.name);
2653 string field_name = node.name;
2654 if (field_name == "string") {
2655 // avoid conflict with string type
2656 field_name = "str";
2659 var field = new Field (field_name, type, null, current_source_reference);
2660 field.access = SymbolAccessibility.PUBLIC;
2662 if (field_name != node.name) {
2663 field.set_cname (node.name);
2666 if (deprecated) {
2667 field.deprecated = true;
2669 if (deprecated_since != null) {
2670 field.deprecated_since = deprecated_since;
2673 if (replacement != null) {
2674 field.replacement = replacement;
2678 if (experimental) {
2679 field.experimental = true;
2682 if (ctype != null) {
2683 field.set_ctype (ctype);
2686 if (cheader_filename != null) {
2687 field.add_cheader_filename (cheader_filename);
2690 if (array_null_terminated) {
2691 field.array_null_terminated = true;
2694 if (array_length_cname != null || array_length_type != null) {
2695 if (array_length_cname != null) {
2696 field.set_array_length_cname (array_length_cname);
2698 if (array_length_type != null) {
2699 field.array_length_type = array_length_type;
2701 } else {
2702 field.no_array_length = true;
2705 return field;
2708 private string[]? get_attributes (string codenode) {
2709 var attributes = codenode_attributes_map.get (codenode);
2711 if (attributes == null) {
2712 var dot_required = (-1 != codenode.index_of_char ('.'));
2713 var colon_required = (-1 != codenode.index_of_char (':'));
2715 var pattern_specs = codenode_attributes_patterns.get_keys ();
2716 foreach (PatternSpec* pattern in pattern_specs) {
2717 var pspec = codenode_attributes_patterns[pattern];
2719 if ((dot_required && -1 == pspec.index_of_char ('.')) ||
2720 (colon_required && -1 == pspec.index_of_char (':'))) {
2721 continue;
2724 if (pattern->match_string (codenode)) {
2725 return get_attributes (pspec);
2730 if (attributes == null) {
2731 return null;
2734 GLib.SList<string> attr_list = new GLib.SList<string> ();
2735 var attr = new GLib.StringBuilder.sized (attributes.length);
2736 var attributes_len = attributes.length;
2737 unowned string remaining = attributes;
2738 bool quoted = false, escaped = false;
2739 for (int b = 0 ; b < attributes_len ; b++) {
2740 unichar c = remaining.get_char ();
2742 if (escaped) {
2743 escaped = false;
2744 attr.append_unichar (c);
2745 } else {
2746 if (c == '"') {
2747 attr.append_unichar (c);
2748 quoted = !quoted;
2749 } else if (c == '\\') {
2750 escaped = true;
2751 } else if (!quoted && (c == ' ')) {
2752 attr_list.prepend (attr.str);
2753 attr.truncate (0);
2754 } else {
2755 attr.append_unichar (c);
2759 remaining = (string) ((char*) remaining + remaining.index_of_nth_char (1));
2762 if (attr.len > 0) {
2763 attr_list.prepend (attr.str);
2766 var attrs = new string[attr_list.length ()];
2767 unowned GLib.SList<string>? attr_i = attr_list;
2768 for (int a = 0 ; a < attrs.length ; a++, attr_i = attr_i.next) {
2769 attrs[(attrs.length - 1) - a] = attr_i.data;
2772 return attrs;
2775 private string eval (string s) {
2776 return ((s.length >= 2) && s.has_prefix ("\"") && s.has_suffix ("\"")) ? s.substring (1, s.length - 2) : s;
2779 private Signal? parse_signal (IdlNodeSignal sig_node) {
2780 weak IdlNode node = (IdlNode) sig_node;
2782 if (sig_node.deprecated || sig_node.result == null) {
2783 return null;
2786 var sig = new Signal (fix_prop_name (node.name), parse_param (sig_node.result), current_source_reference);
2787 sig.access = SymbolAccessibility.PUBLIC;
2789 var attributes = get_attributes ("%s::%s".printf (current_data_type.get_cname (), sig.name));
2790 if (attributes != null) {
2791 string ns_name = null;
2792 foreach (string attr in attributes) {
2793 var nv = attr.split ("=", 2);
2794 if (nv[0] == "name") {
2795 sig.set_cname (sig.name);
2796 sig.name = eval (nv[1]);
2797 } else if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
2798 sig.has_emitter = true;
2799 } else if (nv[0] == "hidden") {
2800 if (eval (nv[1]) == "1") {
2801 return null;
2803 } else if (nv[0] == "deprecated") {
2804 if (eval (nv[1]) == "1") {
2805 sig.deprecated = true;
2807 } else if (nv[0] == "replacement") {
2808 sig.replacement = eval (nv[1]);
2809 } else if (nv[0] == "deprecated_since") {
2810 sig.deprecated_since = eval (nv[1]);
2811 } else if (nv[0] == "transfer_ownership") {
2812 if (eval (nv[1]) == "1") {
2813 sig.return_type.value_owned = true;
2815 } else if (nv[0] == "namespace_name") {
2816 ns_name = eval (nv[1]);
2817 } else if (nv[0] == "type_name") {
2818 sig.return_type = parse_type_from_string (eval (nv[1]), false);
2819 } else if (nv[0] == "type_arguments") {
2820 parse_type_arguments_from_string (sig.return_type, eval (nv[1]));
2821 } else if (nv[0] == "experimental") {
2822 if (eval (nv[1]) == "1") {
2823 sig.experimental = true;
2827 if (ns_name != null) {
2828 ((UnresolvedType) sig.return_type).unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
2832 sig.is_virtual = true;
2834 bool first = true;
2836 foreach (weak IdlNodeParam param in sig_node.parameters) {
2837 if (first) {
2838 // ignore implicit first signal parameter (sender)
2839 first = false;
2840 continue;
2843 weak IdlNode param_node = (IdlNode) param;
2845 ParameterDirection direction;
2846 var param_type = parse_param (param, out direction);
2847 var p = new Parameter (param_node.name, param_type);
2848 p.direction = direction;
2850 bool hide_param = false;
2851 bool show_param = false;
2852 attributes = get_attributes ("%s::%s.%s".printf (current_data_type.get_cname (), sig.name, param_node.name));
2853 if (attributes != null) {
2854 string ns_name = null;
2855 foreach (string attr in attributes) {
2856 var nv = attr.split ("=", 2);
2857 if (nv[0] == "hidden") {
2858 if (eval (nv[1]) == "1") {
2859 hide_param = true;
2860 } else if (eval (nv[1]) == "0") {
2861 show_param = true;
2863 } else if (nv[0] == "is_array") {
2864 if (eval (nv[1]) == "1") {
2865 param_type = new ArrayType (param_type, 1, param_type.source_reference);
2866 p.variable_type = param_type;
2867 p.direction = ParameterDirection.IN;
2869 } else if (nv[0] == "no_array_length") {
2870 if (eval (nv[1]) == "1") {
2871 p.no_array_length = true;
2873 } else if (nv[0] == "array_length_type") {
2874 p.array_length_type = eval (nv[1]);
2875 } else if (nv[0] == "array_null_terminated") {
2876 if (eval (nv[1]) == "1") {
2877 p.no_array_length = true;
2878 p.array_null_terminated = true;
2880 } else if (nv[0] == "is_out") {
2881 if (eval (nv[1]) == "1") {
2882 p.direction = ParameterDirection.OUT;
2884 } else if (nv[0] == "is_ref") {
2885 if (eval (nv[1]) == "1") {
2886 p.direction = ParameterDirection.REF;
2888 } else if (nv[0] == "nullable") {
2889 if (eval (nv[1]) == "1") {
2890 param_type.nullable = true;
2892 } else if (nv[0] == "transfer_ownership") {
2893 if (eval (nv[1]) == "1") {
2894 param_type.value_owned = true;
2896 } else if (nv[0] == "type_name") {
2897 p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
2898 } else if (nv[0] == "type_arguments") {
2899 parse_type_arguments_from_string (p.variable_type, eval (nv[1]));
2900 } else if (nv[0] == "namespace_name") {
2901 ns_name = eval (nv[1]);
2904 if (ns_name != null) {
2905 ((UnresolvedType) param_type).unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
2909 if (show_param || !hide_param) {
2910 sig.add_parameter (p);
2914 return sig;
2918 // vim:sw=8 noet