Use gdestroynotify_type in codegen instead of looking it up everytime.
[vala-lang.git] / vapigen / valagidlparser.vala
blob46d0747e96102fc40c4f0063c106e2efaa60fb2f
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.ndup (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 (null != tokens[0].chr (-1, '*')) {
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.offset (container.name.length);
168 } else if (container.name == "GLib" && type_name.has_prefix ("G")) {
169 return type_name.offset (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.offset (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.offset (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 = eval (nv[1]).to_double ();
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));
496 uint remaining_params = f_node.parameters.length ();
497 foreach (weak IdlNodeParam param in f_node.parameters) {
498 weak IdlNode param_node = (IdlNode) param;
500 if (check_has_target && remaining_params == 1 && (param_node.name == "user_data" || param_node.name == "data")) {
501 // hide user_data parameter for instance delegates
502 cb.has_target = true;
503 } else {
504 string param_name = param_node.name;
505 if (param_name == "string") {
506 // avoid conflict with string type
507 param_name = "str";
508 } else if (param_name == "self") {
509 // avoid conflict with delegate target
510 param_name = "_self";
513 ParameterDirection direction;
514 var param_type = parse_param (param, out direction);
515 var p = new Parameter (param_name, param_type);
516 p.direction = direction;
518 bool hide_param = false;
519 bool show_param = false;
520 bool array_requested = false;
521 bool out_requested = false;
522 attributes = get_attributes ("%s.%s".printf (node.name, param_node.name));
523 if (attributes != null) {
524 foreach (string attr in attributes) {
525 var nv = attr.split ("=", 2);
526 if (nv[0] == "hidden") {
527 if (eval (nv[1]) == "1") {
528 hide_param = true;
529 } else if (eval (nv[1]) == "0") {
530 show_param = true;
532 } else if (nv[0] == "is_array") {
533 if (eval (nv[1]) == "1") {
534 param_type = new ArrayType (param_type, 1, param_type.source_reference);
535 p.variable_type = param_type;
536 if (!out_requested) {
537 p.direction = ParameterDirection.IN;
539 array_requested = true;
541 } else if (nv[0] == "is_out") {
542 if (eval (nv[1]) == "1") {
543 p.direction = ParameterDirection.OUT;
544 out_requested = true;
545 if (!array_requested && param_type is ArrayType) {
546 var array_type = (ArrayType) param_type;
547 param_type = array_type.element_type;
548 p.variable_type = param_type;
551 } else if (nv[0] == "is_ref") {
552 if (eval (nv[1]) == "1") {
553 p.direction = ParameterDirection.REF;
554 if (!array_requested && param_type is ArrayType) {
555 var array_type = (ArrayType) param_type;
556 param_type = array_type.element_type;
557 p.variable_type = param_type;
560 } else if (nv[0] == "takes_ownership") {
561 if (eval (nv[1]) == "1") {
562 param_type.value_owned = true;
564 } else if (nv[0] == "nullable") {
565 if (eval (nv[1]) == "1") {
566 param_type.nullable = true;
568 } else if (nv[0] == "type_arguments") {
569 parse_type_arguments_from_string (param_type, eval (nv[1]));
570 } else if (nv[0] == "no_array_length") {
571 if (eval (nv[1]) == "1") {
572 p.no_array_length = true;
574 } else if (nv[0] == "type_name") {
575 p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
580 if (show_param || !hide_param) {
581 cb.add_parameter (p);
585 remaining_params--;
588 return cb;
591 private bool is_reference_type (string cname) {
592 var st_attributes = get_attributes (cname);
593 if (st_attributes != null) {
594 foreach (string attr in st_attributes) {
595 var nv = attr.split ("=", 2);
596 if (nv[0] == "is_value_type" && eval (nv[1]) == "1") {
597 return false;
601 return true;
604 private void parse_struct (IdlNodeStruct st_node, Symbol container, IdlModule module) {
605 weak IdlNode node = (IdlNode) st_node;
607 if (st_node.deprecated) {
608 return;
611 string name = fix_type_name (node.name, container);
613 if (!is_reference_type (node.name)) {
614 var st = container.scope.lookup (name) as Struct;
615 if (st == null) {
616 st = new Struct (name, current_source_reference);
617 st.access = SymbolAccessibility.PUBLIC;
619 var st_attributes = get_attributes (node.name);
620 if (st_attributes != null) {
621 foreach (string attr in st_attributes) {
622 var nv = attr.split ("=", 2);
623 if (nv[0] == "cheader_filename") {
624 st.add_cheader_filename (eval (nv[1]));
625 } else if (nv[0] == "hidden") {
626 if (eval (nv[1]) == "1") {
627 return;
629 } else if (nv[0] == "base_type") {
630 st.base_type = parse_type_string (eval (nv[1]));
631 } else if (nv[0] == "rank") {
632 st.set_rank (eval (nv[1]).to_int ());
633 } else if (nv[0] == "simple_type") {
634 if (eval (nv[1]) == "1") {
635 st.set_simple_type (true);
637 } else if (nv[0] == "immutable") {
638 if (eval (nv[1]) == "1") {
639 st.is_immutable = true;
641 } else if (nv[0] == "has_type_id") {
642 if (eval (nv[1]) == "0") {
643 st.has_type_id = false;
645 } else if (nv[0] == "type_id") {
646 st.set_type_id (eval (nv[1]));
647 } else if (nv[0] == "has_copy_function") {
648 if (eval (nv[1]) == "0") {
649 st.has_copy_function = false;
651 } else if (nv[0] == "deprecated") {
652 if (eval (nv[1]) == "1") {
653 st.deprecated = true;
655 } else if (nv[0] == "replacement") {
656 st.replacement = eval (nv[1]);
657 } else if (nv[0] == "deprecated_since") {
658 st.deprecated_since = eval (nv[1]);
659 } else if (nv[0] == "has_destroy_function") {
660 if (eval (nv[1]) == "0") {
661 st.has_destroy_function = false;
667 add_symbol_to_container (container, st);
668 current_source_file.add_node (st);
671 current_data_type = st;
673 foreach (weak IdlNode member in st_node.members) {
674 if (member.type == IdlNodeTypeId.FUNCTION) {
675 var m = parse_function ((IdlNodeFunction) member);
676 if (m != null) {
677 st.add_method (m);
679 } else if (member.type == IdlNodeTypeId.FIELD) {
680 var f = parse_field ((IdlNodeField) member);
681 if (f != null) {
682 st.add_field (f);
687 current_data_type = null;
688 } else {
689 bool ref_function_void = false;
690 string ref_function = null;
691 string unref_function = null;
692 string copy_function = null;
693 string free_function = null;
695 var cl = container.scope.lookup (name) as Class;
696 if (cl == null) {
697 string base_class = null;
699 cl = new Class (name, current_source_reference);
700 cl.access = SymbolAccessibility.PUBLIC;
701 cl.is_compact = true;
703 var cl_attributes = get_attributes (node.name);
704 if (cl_attributes != null) {
705 foreach (string attr in cl_attributes) {
706 var nv = attr.split ("=", 2);
707 if (nv[0] == "cheader_filename") {
708 cl.add_cheader_filename (eval (nv[1]));
709 } else if (nv[0] == "base_class") {
710 base_class = eval (nv[1]);
711 } else if (nv[0] == "hidden") {
712 if (eval (nv[1]) == "1") {
713 return;
715 } else if (nv[0] == "is_immutable") {
716 if (eval (nv[1]) == "1") {
717 cl.is_immutable = true;
719 } else if (nv[0] == "const_cname") {
720 cl.const_cname = eval (nv[1]);
721 } else if (nv[0] == "is_fundamental") {
722 if (eval (nv[1]) == "1") {
723 cl.is_compact = false;
725 } else if (nv[0] == "abstract" && base_class != null) {
726 if (eval (nv[1]) == "1") {
727 cl.is_abstract = true;
729 } else if (nv[0] == "free_function") {
730 free_function = eval (nv[1]);
731 } else if (nv[0] == "ref_function") {
732 ref_function = eval (nv[1]);
733 } else if (nv[0] == "unref_function") {
734 unref_function = eval (nv[1]);
735 } else if (nv[0] == "copy_function") {
736 copy_function = eval (nv[1]);
737 } else if (nv[0] == "ref_function_void") {
738 if (eval (nv[1]) == "1") {
739 ref_function_void = true;
741 } else if (nv[0] == "deprecated") {
742 if (eval (nv[1]) == "1") {
743 cl.deprecated = true;
745 } else if (nv[0] == "replacement") {
746 cl.replacement = eval (nv[1]);
747 } else if (nv[0] == "deprecated_since") {
748 cl.deprecated_since = eval (nv[1]);
749 } else if (nv[0] == "type_parameters") {
750 foreach (string type_param_name in eval (nv[1]).split (",")) {
751 cl.add_type_parameter (new TypeParameter (type_param_name, current_source_reference));
757 add_symbol_to_container (container, cl);
758 current_source_file.add_node (cl);
760 if (base_class != null) {
761 var parent = parse_type_string (base_class);
762 cl.add_base_type (parent);
766 current_data_type = cl;
768 foreach (weak IdlNode member in st_node.members) {
769 if (member.type == IdlNodeTypeId.FUNCTION) {
770 if ((ref_function == null) && (member.name == "ref")) {
771 ref_function = ((IdlNodeFunction) member).symbol;
772 ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
773 } else if ((unref_function == null) && (member.name == "unref")) {
774 unref_function = ((IdlNodeFunction) member).symbol;
775 } else if ((free_function == null) && (member.name == "free" || member.name == "destroy")) {
776 free_function = ((IdlNodeFunction) member).symbol;
777 } else {
778 if ((copy_function == null) && (member.name == "copy")) {
779 copy_function = ((IdlNodeFunction) member).symbol;
781 var m = parse_function ((IdlNodeFunction) member);
782 if (m != null) {
783 cl.add_method (m);
786 } else if (member.type == IdlNodeTypeId.FIELD) {
787 var f = parse_field ((IdlNodeField) member);
788 if (f != null) {
789 cl.add_field (f);
794 if (ref_function != null) {
795 cl.set_ref_function (ref_function);
796 cl.ref_function_void = ref_function_void;
798 if (copy_function != null) {
799 cl.set_dup_function (copy_function);
801 if (unref_function != null) {
802 cl.set_unref_function (unref_function);
803 } else if (free_function != null) {
804 cl.set_free_function (free_function);
807 current_data_type = null;
811 private void parse_union (IdlNodeUnion un_node, Symbol container, IdlModule module) {
812 weak IdlNode node = (IdlNode) un_node;
814 if (un_node.deprecated) {
815 return;
818 string name = fix_type_name (node.name, container);
820 if (!is_reference_type (node.name)) {
821 var st = container.scope.lookup (name) as Struct;
822 if (st == null) {
823 st = new Struct (name, current_source_reference);
824 st.access = SymbolAccessibility.PUBLIC;
826 var st_attributes = get_attributes (node.name);
827 if (st_attributes != null) {
828 foreach (string attr in st_attributes) {
829 var nv = attr.split ("=", 2);
830 if (nv[0] == "cheader_filename") {
831 st.add_cheader_filename (eval (nv[1]));
832 } else if (nv[0] == "deprecated") {
833 if (eval (nv[1]) == "1") {
834 st.deprecated = true;
836 } else if (nv[0] == "replacement") {
837 st.replacement = eval (nv[1]);
838 } else if (nv[0] == "deprecated_since") {
839 st.deprecated_since = eval (nv[1]);
840 } else if (nv[0] == "hidden") {
841 if (eval (nv[1]) == "1") {
842 return;
848 add_symbol_to_container (container, st);
849 current_source_file.add_node (st);
852 current_data_type = st;
854 foreach (weak IdlNode member in un_node.members) {
855 if (member.type == IdlNodeTypeId.FUNCTION) {
856 var m = parse_function ((IdlNodeFunction) member);
857 if (m != null) {
858 st.add_method (m);
860 } else if (member.type == IdlNodeTypeId.FIELD) {
861 var f = parse_field ((IdlNodeField) member);
862 if (f != null) {
863 st.add_field (f);
868 current_data_type = null;
869 } else {
870 var cl = container.scope.lookup (name) as Class;
871 if (cl == null) {
872 cl = new Class (name, current_source_reference);
873 cl.access = SymbolAccessibility.PUBLIC;
874 cl.is_compact = true;
876 var cl_attributes = get_attributes (node.name);
877 if (cl_attributes != null) {
878 foreach (string attr in cl_attributes) {
879 var nv = attr.split ("=", 2);
880 if (nv[0] == "cheader_filename") {
881 cl.add_cheader_filename (eval (nv[1]));
882 } else if (nv[0] == "hidden") {
883 if (eval (nv[1]) == "1") {
884 return;
890 add_symbol_to_container (container, cl);
891 current_source_file.add_node (cl);
894 current_data_type = cl;
896 bool ref_function_void = false;
897 string ref_function = null;
898 string unref_function = null;
899 string copy_function = null;
900 string free_function = null;
902 foreach (weak IdlNode member in un_node.members) {
903 if (member.type == IdlNodeTypeId.FUNCTION) {
904 if (member.name == "ref") {
905 ref_function = ((IdlNodeFunction) member).symbol;
906 ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
907 } else if (member.name == "unref") {
908 unref_function = ((IdlNodeFunction) member).symbol;
909 } else if (member.name == "free" || member.name == "destroy") {
910 free_function = ((IdlNodeFunction) member).symbol;
911 } else {
912 if (member.name == "copy") {
913 copy_function = ((IdlNodeFunction) member).symbol;
915 var m = parse_function ((IdlNodeFunction) member);
916 if (m != null) {
917 cl.add_method (m);
920 } else if (member.type == IdlNodeTypeId.FIELD) {
921 var f = parse_field ((IdlNodeField) member);
922 if (f != null) {
923 cl.add_field (f);
928 if (ref_function != null) {
929 cl.set_ref_function (ref_function);
930 cl.ref_function_void = ref_function_void;
932 if (copy_function != null) {
933 cl.set_dup_function (copy_function);
935 if (unref_function != null) {
936 cl.set_unref_function (unref_function);
937 } else if (free_function != null) {
938 cl.set_free_function (free_function);
941 current_data_type = null;
945 private void parse_boxed (IdlNodeBoxed boxed_node, Symbol container, IdlModule module) {
946 weak IdlNode node = (IdlNode) boxed_node;
948 string name = fix_type_name (node.name, container);
950 var node_attributes = get_attributes (node.name);
951 if (node_attributes != null) {
952 foreach (string attr in node_attributes) {
953 var nv = attr.split ("=", 2);
954 if (nv[0] == "hidden") {
955 return;
960 if (!is_reference_type (node.name)) {
961 var st = container.scope.lookup (name) as Struct;
962 if (st == null) {
963 st = new Struct (name, current_source_reference);
964 st.access = SymbolAccessibility.PUBLIC;
966 var st_attributes = get_attributes (node.name);
967 if (st_attributes != null) {
968 foreach (string attr in st_attributes) {
969 var nv = attr.split ("=", 2);
970 if (nv[0] == "cheader_filename") {
971 st.add_cheader_filename (eval (nv[1]));
972 } else if (nv[0] == "deprecated") {
973 if (eval (nv[1]) == "1") {
974 st.deprecated = true;
976 } else if (nv[0] == "replacement") {
977 st.replacement = eval (nv[1]);
978 } else if (nv[0] == "deprecated_since") {
979 st.deprecated_since = eval (nv[1]);
980 } else if (nv[0] == "immutable") {
981 if (eval (nv[1]) == "1") {
982 st.is_immutable = true;
984 } else if (nv[0] == "has_copy_function") {
985 if (eval (nv[1]) == "0") {
986 st.has_copy_function = false;
988 } else if (nv[0] == "has_destroy_function") {
989 if (eval (nv[1]) == "0") {
990 st.has_destroy_function = false;
996 add_symbol_to_container (container, st);
997 st.set_type_id (st.get_upper_case_cname ("TYPE_"));
998 current_source_file.add_node (st);
1001 current_data_type = st;
1003 foreach (weak IdlNode member in boxed_node.members) {
1004 if (member.type == IdlNodeTypeId.FUNCTION) {
1005 var m = parse_function ((IdlNodeFunction) member);
1006 if (m != null) {
1007 st.add_method (m);
1009 } else if (member.type == IdlNodeTypeId.FIELD) {
1010 var f = parse_field ((IdlNodeField) member);
1011 if (f != null) {
1012 st.add_field (f);
1017 current_data_type = null;
1018 } else {
1019 bool ref_function_void = false;
1020 string ref_function = null;
1021 string unref_function = null;
1022 string copy_function = null;
1023 string free_function = null;
1025 var cl = container.scope.lookup (name) as Class;
1026 if (cl == null) {
1027 string base_class = null;
1029 cl = new Class (name, current_source_reference);
1030 cl.access = SymbolAccessibility.PUBLIC;
1031 cl.is_compact = true;
1033 var cl_attributes = get_attributes (node.name);
1034 if (cl_attributes != null) {
1035 foreach (string attr in cl_attributes) {
1036 var nv = attr.split ("=", 2);
1037 if (nv[0] == "cheader_filename") {
1038 cl.add_cheader_filename (eval (nv[1]));
1039 } else if (nv[0] == "base_class") {
1040 base_class = eval (nv[1]);
1041 } else if (nv[0] == "is_immutable") {
1042 if (eval (nv[1]) == "1") {
1043 cl.is_immutable = true;
1045 } else if (nv[0] == "deprecated") {
1046 if (eval (nv[1]) == "1") {
1047 cl.deprecated = true;
1049 } else if (nv[0] == "replacement") {
1050 cl.replacement = eval (nv[1]);
1051 } else if (nv[0] == "deprecated_since") {
1052 cl.deprecated_since = eval (nv[1]);
1053 } else if (nv[0] == "const_cname") {
1054 cl.const_cname = eval (nv[1]);
1055 } else if (nv[0] == "free_function") {
1056 free_function = eval (nv[1]);
1057 } else if (nv[0] == "ref_function") {
1058 ref_function = eval (nv[1]);
1059 } else if (nv[0] == "unref_function") {
1060 unref_function = eval (nv[1]);
1061 } else if (nv[0] == "copy_function") {
1062 copy_function = eval (nv[1]);
1063 } else if (nv[0] == "ref_function_void") {
1064 if (eval (nv[1]) == "1") {
1065 ref_function_void = true;
1071 add_symbol_to_container (container, cl);
1072 cl.set_type_id (cl.get_upper_case_cname ("TYPE_"));
1073 current_source_file.add_node (cl);
1075 if (base_class != null) {
1076 var parent = parse_type_string (base_class);
1077 cl.add_base_type (parent);
1081 current_data_type = cl;
1083 foreach (weak IdlNode member in boxed_node.members) {
1084 if (member.type == IdlNodeTypeId.FUNCTION) {
1085 if (member.name == "ref") {
1086 ref_function = ((IdlNodeFunction) member).symbol;
1087 ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
1088 } else if (member.name == "unref") {
1089 unref_function = ((IdlNodeFunction) member).symbol;
1090 } else if (member.name == "free" || member.name == "destroy") {
1091 free_function = ((IdlNodeFunction) member).symbol;
1092 } else {
1093 if (member.name == "copy") {
1094 copy_function = ((IdlNodeFunction) member).symbol;
1096 var m = parse_function ((IdlNodeFunction) member);
1097 if (m != null) {
1098 cl.add_method (m);
1101 } else if (member.type == IdlNodeTypeId.FIELD) {
1102 var f = parse_field ((IdlNodeField) member);
1103 if (f != null) {
1104 cl.add_field (f);
1109 if (ref_function != null) {
1110 cl.set_ref_function (ref_function);
1111 cl.ref_function_void = ref_function_void;
1113 if (copy_function != null) {
1114 cl.set_dup_function (copy_function);
1116 if (unref_function != null) {
1117 cl.set_unref_function (unref_function);
1118 } else if (free_function != null) {
1119 cl.set_free_function (free_function);
1122 current_data_type = null;
1126 private void parse_enum (IdlNodeEnum en_node, Symbol container, IdlModule module, bool is_flags) {
1127 weak IdlNode node = (IdlNode) en_node;
1128 string name = fix_type_name (node.name, container);
1129 bool existing = true;
1131 var en = container.scope.lookup (name) as Enum;
1132 if (en == null) {
1133 en = new Enum (name, current_source_reference);
1134 en.access = SymbolAccessibility.PUBLIC;
1135 existing = false;
1136 } else {
1137 // ignore dummy enum values in -custom.vala files
1138 // they exist for syntactical reasons
1139 var dummy = (EnumValue) en.scope.lookup ("__DUMMY__");
1140 if (dummy != null) {
1141 en.get_values ().remove (dummy);
1142 en.scope.remove ("__DUMMY__");
1146 en.has_type_id = (en_node.gtype_name != null && en_node.gtype_name != "");
1148 string common_prefix = null;
1150 foreach (weak IdlNode value in en_node.values) {
1151 var val_attributes = get_attributes (value.name);
1152 bool is_hidden = false;
1153 if (val_attributes != null) {
1154 foreach (string attr in val_attributes) {
1155 var nv = attr.split ("=", 2);
1156 if (nv[0] == "hidden" && eval(nv[1]) == "1") {
1157 is_hidden = true;
1162 if (is_hidden) {
1163 continue;
1166 if (common_prefix == null) {
1167 common_prefix = value.name;
1168 while (common_prefix.length > 0 && !common_prefix.has_suffix ("_")) {
1169 // FIXME: could easily be made faster
1170 common_prefix = common_prefix.ndup (common_prefix.length - 1);
1172 } else {
1173 while (!value.name.has_prefix (common_prefix)) {
1174 common_prefix = common_prefix.ndup (common_prefix.length - 1);
1177 while (common_prefix.length > 0 && (!common_prefix.has_suffix ("_") ||
1178 (value.name.offset (common_prefix.length).get_char ().isdigit ()) && (value.name.length - common_prefix.length) <= 1)) {
1179 // enum values may not consist solely of digits
1180 common_prefix = common_prefix.ndup (common_prefix.length - 1);
1184 bool is_errordomain = false;
1186 var cheader_filenames = new ArrayList<string> ();
1188 var en_attributes = get_attributes (node.name);
1189 if (en_attributes != null) {
1190 foreach (string attr in en_attributes) {
1191 var nv = attr.split ("=", 2);
1192 if (nv[0] == "common_prefix") {
1193 common_prefix = eval (nv[1]);
1194 } else if (nv[0] == "cheader_filename") {
1195 cheader_filenames.add (eval (nv[1]));
1196 en.add_cheader_filename (eval (nv[1]));
1197 } else if (nv[0] == "hidden") {
1198 if (eval (nv[1]) == "1") {
1199 return;
1201 } else if (nv[0] == "deprecated") {
1202 if (eval (nv[1]) == "1") {
1203 en.deprecated = true;
1205 } else if (nv[0] == "replacement") {
1206 en.replacement = eval (nv[1]);
1207 } else if (nv[0] == "deprecated_since") {
1208 en.deprecated_since = eval (nv[1]);
1209 } else if (nv[0] == "rename_to") {
1210 en.name = eval (nv[1]);
1211 } else if (nv[0] == "errordomain") {
1212 if (eval (nv[1]) == "1") {
1213 is_errordomain = true;
1215 } else if (nv[0] == "to_string") {
1216 var return_type = new UnresolvedType ();
1217 return_type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1218 return_type.value_owned = false;
1219 var m = new Method ("to_string", return_type, current_source_reference);
1220 m.access = SymbolAccessibility.PUBLIC;
1221 m.set_cname (eval(nv[1]));
1222 en.add_method (m);
1227 en.set_cprefix (common_prefix);
1229 foreach (weak IdlNode value2 in en_node.values) {
1230 var val_attributes = get_attributes (value2.name);
1231 bool is_hidden = false;
1232 if (val_attributes != null) {
1233 foreach (string attr in val_attributes) {
1234 var nv = attr.split ("=", 2);
1235 if (nv[0] == "hidden" && eval(nv[1]) == "1") {
1236 is_hidden = true;
1241 if (!is_hidden) {
1242 var ev = new EnumValue (value2.name.offset (common_prefix.length), null);
1243 en.add_value (ev);
1247 if (is_errordomain) {
1248 var ed = new ErrorDomain (en.name, current_source_reference);
1249 ed.access = SymbolAccessibility.PUBLIC;
1250 ed.set_cprefix (common_prefix);
1252 foreach (string filename in cheader_filenames) {
1253 ed.add_cheader_filename (filename);
1256 foreach (EnumValue ev in en.get_values ()) {
1257 ed.add_code (new ErrorCode (ev.name));
1260 current_source_file.add_node (ed);
1261 if (!existing) {
1262 add_symbol_to_container (container, ed);
1264 } else {
1265 en.is_flags = is_flags;
1266 current_source_file.add_node (en);
1267 if (!existing) {
1268 add_symbol_to_container (container, en);
1273 private void parse_object (IdlNodeInterface node, Symbol container, IdlModule module) {
1274 string name = fix_type_name (((IdlNode) node).name, container);
1276 string base_class = null;
1278 var cl = container.scope.lookup (name) as Class;
1279 if (cl == null) {
1280 cl = new Class (name, current_source_reference);
1281 cl.access = SymbolAccessibility.PUBLIC;
1283 var attributes = get_attributes (node.gtype_name);
1284 if (attributes != null) {
1285 foreach (string attr in attributes) {
1286 var nv = attr.split ("=", 2);
1287 if (nv[0] == "cheader_filename") {
1288 cl.add_cheader_filename (eval (nv[1]));
1289 } else if (nv[0] == "base_class") {
1290 base_class = eval (nv[1]);
1291 } else if (nv[0] == "hidden") {
1292 if (eval (nv[1]) == "1") {
1293 return;
1295 } else if (nv[0] == "type_check_function") {
1296 cl.type_check_function = eval (nv[1]);
1297 } else if (nv[0] == "deprecated") {
1298 if (eval (nv[1]) == "1") {
1299 cl.deprecated = true;
1301 } else if (nv[0] == "replacement") {
1302 cl.replacement = eval (nv[1]);
1303 } else if (nv[0] == "deprecated_since") {
1304 cl.deprecated_since = eval (nv[1]);
1305 } else if (nv[0] == "type_id") {
1306 cl.set_type_id (eval (nv[1]));
1307 } else if (nv[0] == "abstract") {
1308 if (eval (nv[1]) == "1") {
1309 cl.is_abstract = true;
1315 add_symbol_to_container (container, cl);
1316 current_source_file.add_node (cl);
1319 if (base_class != null) {
1320 var parent = parse_type_string (base_class);
1321 cl.add_base_type (parent);
1322 } else if (node.parent != null) {
1323 var parent = parse_type_string (node.parent);
1324 cl.add_base_type (parent);
1325 } else {
1326 var gobject_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Object");
1327 cl.add_base_type (new UnresolvedType.from_symbol (gobject_symbol));
1330 foreach (string iface_name in node.interfaces) {
1331 bool skip_iface = false;
1333 var attributes = get_attributes (iface_name);
1334 if (attributes != null) {
1335 foreach (string attr in attributes) {
1336 var nv = attr.split ("=", 2);
1337 if (nv[0] == "hidden") {
1338 if (eval (nv[1]) == "1") {
1339 skip_iface = true;
1345 if (skip_iface) {
1346 continue;
1349 var iface = parse_type_string (iface_name);
1350 cl.add_base_type (iface);
1353 current_data_type = cl;
1355 current_type_symbol_set = new HashSet<string> (str_hash, str_equal);
1356 var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
1357 var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
1359 foreach (weak IdlNode member in node.members) {
1360 if (member.type == IdlNodeTypeId.FUNCTION) {
1361 current_type_func_map.set (member.name, (IdlNodeFunction) member);
1363 if (member.type == IdlNodeTypeId.VFUNC) {
1364 current_type_vfunc_map.set (member.name, "1");
1368 foreach (weak IdlNode member in node.members) {
1369 if (member.type == IdlNodeTypeId.FUNCTION) {
1370 // Ignore if vfunc (handled below)
1371 if (!current_type_vfunc_map.contains (member.name)) {
1372 var m = parse_function ((IdlNodeFunction) member);
1373 if (m != null) {
1374 cl.add_method (m);
1377 } else if (member.type == IdlNodeTypeId.VFUNC) {
1378 var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name));
1379 if (m != null) {
1380 cl.add_method (m);
1382 } else if (member.type == IdlNodeTypeId.PROPERTY) {
1383 var prop = parse_property ((IdlNodeProperty) member);
1384 if (prop != null) {
1385 cl.add_property (prop);
1387 } else if (member.type == IdlNodeTypeId.SIGNAL) {
1388 var sig = parse_signal ((IdlNodeSignal) member);
1389 if (sig != null) {
1390 cl.add_signal (sig);
1395 foreach (weak IdlNode member in node.members) {
1396 if (member.type == IdlNodeTypeId.FIELD) {
1397 if (!current_type_symbol_set.contains (member.name)) {
1398 var f = parse_field ((IdlNodeField) member);
1399 if (f != null) {
1400 cl.add_field (f);
1406 foreach (Property prop in cl.get_properties ()) {
1407 var getter = "get_%s".printf (prop.name);
1409 if (prop.get_accessor != null && !current_type_symbol_set.contains (getter)) {
1410 prop.no_accessor_method = true;
1413 var setter = "set_%s".printf (prop.name);
1415 if (prop.set_accessor != null && prop.set_accessor.writable
1416 && !current_type_symbol_set.contains (setter)) {
1417 prop.no_accessor_method = true;
1420 if (prop.no_accessor_method && prop.get_accessor != null) {
1421 prop.get_accessor.value_type.value_owned = true;
1425 handle_async_methods (cl);
1427 if (cl.default_construction_method == null) {
1428 // always provide constructor in generated bindings
1429 // to indicate that implicit Object () chainup is allowed
1430 var cm = new CreationMethod (null, null, cl.source_reference);
1431 cm.has_construct_function = false;
1432 cm.access = SymbolAccessibility.PROTECTED;
1433 cl.add_method (cm);
1436 current_data_type = null;
1437 current_type_symbol_set = null;
1440 private void parse_interface (IdlNodeInterface node, Symbol container, IdlModule module) {
1441 string name = fix_type_name (node.gtype_name, container);
1443 var iface = container.scope.lookup (name) as Interface;
1444 if (iface == null) {
1445 iface = new Interface (name, current_source_reference);
1446 iface.access = SymbolAccessibility.PUBLIC;
1448 var attributes = get_attributes (node.gtype_name);
1449 if (attributes != null) {
1450 foreach (string attr in attributes) {
1451 var nv = attr.split ("=", 2);
1452 if (nv[0] == "cheader_filename") {
1453 iface.add_cheader_filename (eval (nv[1]));
1454 } else if (nv[0] == "lower_case_csuffix") {
1455 iface.set_lower_case_csuffix (eval (nv[1]));
1460 foreach (string prereq_name in node.prerequisites) {
1461 var prereq = parse_type_string (prereq_name);
1462 iface.add_prerequisite (prereq);
1465 add_symbol_to_container (container, iface);
1466 current_source_file.add_node (iface);
1469 current_data_type = iface;
1471 var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
1472 var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
1474 foreach (weak IdlNode member in node.members) {
1475 if (member.type == IdlNodeTypeId.FUNCTION) {
1476 current_type_func_map.set (member.name, (IdlNodeFunction) member);
1478 if (member.type == IdlNodeTypeId.VFUNC) {
1479 current_type_vfunc_map.set (member.name, "1");
1483 foreach (weak IdlNode member in node.members) {
1484 if (member.type == IdlNodeTypeId.FUNCTION) {
1485 // Ignore if vfunc (handled below)
1486 if (!current_type_vfunc_map.contains (member.name)) {
1487 var m = parse_function ((IdlNodeFunction) member, true);
1488 if (m != null) {
1489 iface.add_method (m);
1492 } else if (member.type == IdlNodeTypeId.VFUNC) {
1493 var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name), true);
1494 if (m != null) {
1495 iface.add_method (m);
1497 } else if (member.type == IdlNodeTypeId.PROPERTY) {
1498 var prop = parse_property ((IdlNodeProperty) member);
1499 if (prop != null) {
1500 iface.add_property (prop);
1502 } else if (member.type == IdlNodeTypeId.SIGNAL) {
1503 var sig = parse_signal ((IdlNodeSignal) member);
1504 if (sig != null) {
1505 iface.add_signal (sig);
1506 sig.is_virtual = false;
1511 handle_async_methods (iface);
1513 current_data_type = null;
1516 void handle_async_methods (ObjectTypeSymbol type_symbol) {
1517 Set<Method> finish_methods = new HashSet<Method> ();
1518 var methods = type_symbol.get_methods ();
1520 foreach (Method m in methods) {
1521 if (m.coroutine) {
1522 string finish_method_base;
1523 if (m.name.has_suffix ("_async")) {
1524 finish_method_base = m.name.substring (0, m.name.length - "_async".length);
1525 } else {
1526 finish_method_base = m.name;
1528 var finish_method = type_symbol.scope.lookup (finish_method_base + "_finish") as Method;
1530 // check if the method is using non-standard finish method name
1531 if (finish_method == null) {
1532 var method_cname = m.get_finish_cname ();
1533 foreach (Method method in type_symbol.get_methods ()) {
1534 if (method.get_cname () == method_cname) {
1535 finish_method = method;
1536 break;
1541 if (finish_method != null) {
1542 m.return_type = finish_method.return_type.copy ();
1543 m.no_array_length = finish_method.no_array_length;
1544 m.array_null_terminated = finish_method.array_null_terminated;
1545 foreach (var param in finish_method.get_parameters ()) {
1546 if (param.direction == ParameterDirection.OUT) {
1547 var async_param = param.copy ();
1548 if (m.scope.lookup (param.name) != null) {
1549 // parameter name conflict
1550 async_param.name += "_out";
1552 m.add_parameter (async_param);
1555 foreach (DataType error_type in finish_method.get_error_types ()) {
1556 m.add_error_type (error_type.copy ());
1558 finish_methods.add (finish_method);
1563 foreach (Method m in finish_methods)
1565 type_symbol.scope.remove (m.name);
1566 methods.remove (m);
1570 private DataType? parse_type (IdlNodeType type_node, out ParameterDirection direction = null) {
1571 ParameterDirection dir = ParameterDirection.IN;
1573 var type = new UnresolvedType ();
1574 if (type_node.tag == TypeTag.VOID) {
1575 if (type_node.is_pointer) {
1576 return new PointerType (new VoidType ());
1577 } else {
1578 return new VoidType ();
1580 } else if (type_node.tag == TypeTag.BOOLEAN) {
1581 type.unresolved_symbol = new UnresolvedSymbol (null, "bool");
1582 } else if (type_node.tag == TypeTag.INT8) {
1583 type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1584 } else if (type_node.tag == TypeTag.UINT8) {
1585 type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1586 } else if (type_node.tag == TypeTag.INT16) {
1587 type.unresolved_symbol = new UnresolvedSymbol (null, "int16");
1588 } else if (type_node.tag == TypeTag.UINT16) {
1589 type.unresolved_symbol = new UnresolvedSymbol (null, "uint16");
1590 } else if (type_node.tag == TypeTag.INT32) {
1591 type.unresolved_symbol = new UnresolvedSymbol (null, "int32");
1592 } else if (type_node.tag == TypeTag.UINT32) {
1593 type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
1594 } else if (type_node.tag == TypeTag.INT64) {
1595 type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1596 } else if (type_node.tag == TypeTag.UINT64) {
1597 type.unresolved_symbol = new UnresolvedSymbol (null, "uint64");
1598 } else if (type_node.tag == TypeTag.INT) {
1599 type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1600 } else if (type_node.tag == TypeTag.UINT) {
1601 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1602 } else if (type_node.tag == TypeTag.LONG) {
1603 type.unresolved_symbol = new UnresolvedSymbol (null, "long");
1604 } else if (type_node.tag == TypeTag.ULONG) {
1605 type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1606 } else if (type_node.tag == TypeTag.SSIZE) {
1607 type.unresolved_symbol = new UnresolvedSymbol (null, "ssize_t");
1608 } else if (type_node.tag == TypeTag.SIZE) {
1609 type.unresolved_symbol = new UnresolvedSymbol (null, "size_t");
1610 } else if (type_node.tag == TypeTag.FLOAT) {
1611 type.unresolved_symbol = new UnresolvedSymbol (null, "float");
1612 } else if (type_node.tag == TypeTag.DOUBLE) {
1613 type.unresolved_symbol = new UnresolvedSymbol (null, "double");
1614 } else if (type_node.tag == TypeTag.UTF8) {
1615 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1616 } else if (type_node.tag == TypeTag.FILENAME) {
1617 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1618 } else if (type_node.tag == TypeTag.ARRAY) {
1619 var element_type = parse_type (type_node.parameter_type1);
1620 type = element_type as UnresolvedType;
1621 if (type == null) {
1622 return element_type;
1624 return new ArrayType (element_type, 1, element_type.source_reference);
1625 } else if (type_node.tag == TypeTag.LIST) {
1626 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "List");
1627 } else if (type_node.tag == TypeTag.SLIST) {
1628 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "SList");
1629 } else if (type_node.tag == TypeTag.HASH) {
1630 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "HashTable");
1631 } else if (type_node.tag == TypeTag.ERROR) {
1632 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Error");
1633 } else if (type_node.is_interface) {
1634 var n = type_node.@interface;
1636 if (n == "") {
1637 return null;
1640 if (n.has_prefix ("const-")) {
1641 n = n.offset ("const-".length);
1644 if (type_node.is_pointer &&
1645 (n == "gchar" || n == "char")) {
1646 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1647 if (type_node.unparsed.has_suffix ("**")) {
1648 dir = ParameterDirection.OUT;
1650 } else if (n == "gunichar") {
1651 type.unresolved_symbol = new UnresolvedSymbol (null, "unichar");
1652 } else if (n == "gchar") {
1653 type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1654 } else if (n == "guchar" || n == "guint8") {
1655 type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1656 if (type_node.is_pointer) {
1657 return new ArrayType (type, 1, type.source_reference);
1659 } else if (n == "gushort") {
1660 type.unresolved_symbol = new UnresolvedSymbol (null, "ushort");
1661 } else if (n == "gshort") {
1662 type.unresolved_symbol = new UnresolvedSymbol (null, "short");
1663 } else if (n == "gconstpointer" || n == "void") {
1664 return new PointerType (new VoidType ());
1665 } else if (n == "goffset" || n == "off_t") {
1666 type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1667 } else if (n == "value_array") {
1668 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "ValueArray");
1669 } else if (n == "time_t") {
1670 type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1671 } else if (n == "socklen_t") {
1672 type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
1673 } else if (n == "mode_t") {
1674 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1675 } else if (n == "gint" || n == "pid_t") {
1676 type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1677 } else if (n == "unsigned" || n == "unsigned-int") {
1678 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1679 } else if (n == "FILE") {
1680 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "FileStream");
1681 } else if (n == "struct") {
1682 return new PointerType (new VoidType ());
1683 } else if (n == "iconv_t") {
1684 return new PointerType (new VoidType ());
1685 } else if (n == "GType") {
1686 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Type");
1687 if (type_node.is_pointer) {
1688 return new ArrayType (type, 1, type.source_reference);
1690 } else if (n == "GStrv") {
1691 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1692 return new ArrayType (type, 1, type.source_reference);
1693 } else {
1694 var named_type = parse_type_string (n);
1695 type = named_type as UnresolvedType;
1696 if (type == null) {
1697 return named_type;
1699 if (is_simple_type (n)) {
1700 if (type_node.is_pointer) {
1701 dir = ParameterDirection.OUT;
1703 } else if (type_node.unparsed.has_suffix ("**")) {
1704 dir = ParameterDirection.OUT;
1707 } else {
1708 stdout.printf ("%d\n", type_node.tag);
1710 if (&direction != null) {
1711 direction = dir;
1713 return type;
1716 private bool is_simple_type (string type_name) {
1717 var st = cname_type_map[type_name] as Struct;
1718 if (st != null && st.is_simple_type ()) {
1719 return true;
1722 return false;
1725 private DataType parse_type_string (string n) {
1726 if (n == "va_list") {
1727 // unsupported
1728 return new PointerType (new VoidType ());
1731 var type = new UnresolvedType ();
1733 var dt = cname_type_map[n];
1734 if (dt != null) {
1735 UnresolvedSymbol parent_symbol = null;
1736 if (dt.parent_symbol.name != null) {
1737 parent_symbol = new UnresolvedSymbol (null, dt.parent_symbol.name);
1739 type.unresolved_symbol = new UnresolvedSymbol (parent_symbol, dt.name);
1740 return type;
1743 var type_attributes = get_attributes (n);
1745 string ns_name = null;
1747 if (null != type_attributes) {
1748 foreach (string attr in type_attributes) {
1749 var nv = attr.split ("=", 2);
1751 if (nv[0] == "cprefix") {
1752 type.unresolved_symbol = new UnresolvedSymbol (null, n.offset (eval (nv[1]).length));
1753 } else if (nv[0] == "name") {
1754 type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1755 } else if (nv[0] == "namespace") {
1756 ns_name = eval (nv[1]);
1757 } else if (nv[0] == "rename_to") {
1758 type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
1763 if (type.unresolved_symbol != null) {
1764 if (type.unresolved_symbol.name == "pointer") {
1765 return new PointerType (new VoidType ());
1767 if (ns_name != null) {
1768 type.unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
1770 return type;
1773 if (n.has_prefix (current_namespace.name)) {
1774 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, current_namespace.name), n.offset (current_namespace.name.length));
1775 } else if (n.has_prefix ("G")) {
1776 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), n.offset (1));
1777 } else {
1778 var name_parts = n.split (".", 2);
1779 if (name_parts[1] == null) {
1780 type.unresolved_symbol = new UnresolvedSymbol (null, name_parts[0]);
1781 } else {
1782 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, name_parts[0]), name_parts[1]);
1786 return type;
1789 private DataType? parse_param (IdlNodeParam param, out ParameterDirection direction = null) {
1790 var type = parse_type (param.type, out direction);
1792 // disable for now as null_ok not yet correctly set
1793 // type.non_null = !param.null_ok;
1795 return type;
1798 private UnresolvedSymbol? parse_symbol_from_string (string symbol_string, SourceReference? source_reference = null) {
1799 UnresolvedSymbol? sym = null;
1800 foreach (unowned string s in symbol_string.split (".")) {
1801 sym = new UnresolvedSymbol (sym, s, source_reference);
1803 if (sym == null) {
1804 Report.error (source_reference, "a symbol must be specified");
1806 return sym;
1809 private bool parse_type_arguments_from_string (DataType parent_type, string type_arguments, SourceReference? source_reference = null) {
1810 int type_arguments_length = (int) type_arguments.length;
1811 GLib.StringBuilder current = new GLib.StringBuilder.sized (type_arguments_length);
1813 int depth = 0;
1814 for (var c = 0 ; c < type_arguments_length ; c++) {
1815 if (type_arguments[c] == '<' || type_arguments[c] == '[') {
1816 depth++;
1817 current.append_unichar (type_arguments[c]);
1818 } else if (type_arguments[c] == '>' || type_arguments[c] == ']') {
1819 depth--;
1820 current.append_unichar (type_arguments[c]);
1821 } else if (type_arguments[c] == ',') {
1822 if (depth == 0) {
1823 var dt = parse_type_from_string (current.str, true, source_reference);
1824 if (dt == null) {
1825 return false;
1827 parent_type.add_type_argument (dt);
1828 current.truncate ();
1829 } else {
1830 current.append_unichar (type_arguments[c]);
1832 } else {
1833 current.append_unichar (type_arguments[c]);
1837 var dt = parse_type_from_string (current.str, true, source_reference);
1838 if (dt == null) {
1839 return false;
1841 parent_type.add_type_argument (dt);
1843 return true;
1846 private DataType? parse_type_from_string (string type_string, bool owned_by_default, SourceReference? source_reference = null) {
1847 if (type_from_string_regex == null) {
1848 try {
1849 type_from_string_regex = new GLib.Regex ("^(?:(owned|unowned|weak) +)?([0-9a-zA-Z_\\.]+)(?:<(.+)>)?(\\*+)?(\\[(,*)?\\])?(\\?)?$", GLib.RegexCompileFlags.ANCHORED | GLib.RegexCompileFlags.DOLLAR_ENDONLY | GLib.RegexCompileFlags.OPTIMIZE);
1850 } catch (GLib.RegexError e) {
1851 GLib.error ("Unable to compile regex: %s", e.message);
1855 GLib.MatchInfo match;
1856 if (!type_from_string_regex.match (type_string, 0, out match)) {
1857 Report.error (source_reference, "unable to parse type");
1858 return null;
1861 DataType? type = null;
1863 var ownership_data = match.fetch (1);
1864 var type_name = match.fetch (2);
1865 var type_arguments_data = match.fetch (3);
1866 var pointers_data = match.fetch (4);
1867 var array_data = match.fetch (5);
1868 var nullable_data = match.fetch (6);
1870 var nullable = nullable_data != null && nullable_data.length > 0;
1872 if (ownership_data == null && type_name == "void") {
1873 if (array_data == null && !nullable) {
1874 type = new VoidType (source_reference);
1875 if (pointers_data != null) {
1876 for (int i=0; i < pointers_data.length; i++) {
1877 type = new PointerType (type);
1880 return type;
1881 } else {
1882 Report.error (source_reference, "invalid void type");
1883 return null;
1887 bool value_owned = owned_by_default;
1889 if (ownership_data == "owned") {
1890 if (owned_by_default) {
1891 Report.error (source_reference, "unexpected `owned' keyword");
1892 } else {
1893 value_owned = true;
1895 } else if (ownership_data == "unowned") {
1896 if (owned_by_default) {
1897 value_owned = false;
1898 } else {
1899 Report.error (source_reference, "unexpected `unowned' keyword");
1900 return null;
1904 var sym = parse_symbol_from_string (type_name, source_reference);
1905 if (sym == null) {
1906 return null;
1908 type = new UnresolvedType.from_symbol (sym, source_reference);
1910 if (type_arguments_data != null && type_arguments_data.length > 0) {
1911 if (!parse_type_arguments_from_string (type, type_arguments_data, source_reference)) {
1912 return null;
1916 if (pointers_data != null) {
1917 for (int i=0; i < pointers_data.length; i++) {
1918 type = new PointerType (type);
1922 if (array_data != null) {
1923 type = new ArrayType (type, (int) array_data.length + 1, source_reference);
1926 type.nullable = nullable;
1927 type.value_owned = value_owned;
1928 return type;
1931 private Method? create_method (string name, string symbol, IdlNodeParam? res, GLib.List<IdlNodeParam>? parameters, bool is_constructor, bool is_interface) {
1932 DataType return_type = null;
1933 if (res != null) {
1934 return_type = parse_param (res);
1937 Method m;
1938 if (!is_interface && (is_constructor || name.has_prefix ("new"))) {
1939 m = new CreationMethod (null, name, current_source_reference);
1940 m.has_construct_function = false;
1941 if (m.name == "new") {
1942 m.name = null;
1943 } else if (m.name.has_prefix ("new_")) {
1944 m.name = m.name.offset ("new_".length);
1946 // For classes, check whether a creation method return type equals to the
1947 // type of the class created. If the types do not match (e.g. in most
1948 // gtk widgets) add an attribute to the creation method indicating the used
1949 // return type.
1950 if (current_data_type is Class && res != null) {
1951 if ("%s*".printf (current_data_type.get_cname()) != res.type.unparsed) {
1952 ((CreationMethod)m).custom_return_type_cname = res.type.unparsed;
1955 } else {
1956 m = new Method (name, return_type, current_source_reference);
1958 m.access = SymbolAccessibility.PUBLIC;
1960 if (current_type_symbol_set != null) {
1961 current_type_symbol_set.add (name);
1964 if (current_data_type != null) {
1965 var sig_attributes = get_attributes ("%s::%s".printf (current_data_type.get_cname (), name));
1966 if (sig_attributes != null) {
1967 foreach (string attr in sig_attributes) {
1968 var nv = attr.split ("=", 2);
1969 if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
1970 return null;
1976 bool add_ellipsis = false;
1977 bool suppress_throws = false;
1978 string? error_types = null;
1980 var attributes = get_attributes (symbol);
1981 if (attributes != null) {
1982 foreach (string attr in attributes) {
1983 var nv = attr.split ("=", 2);
1984 if (nv[0] == "name") {
1985 m.set_cname (m.name);
1986 m.name = eval (nv[1]);
1987 } else if (nv[0] == "hidden") {
1988 if (eval (nv[1]) == "1") {
1989 return null;
1991 } else if (nv[0] == "ellipsis") {
1992 if (eval (nv[1]) == "1") {
1993 add_ellipsis = true;
1995 } else if (nv[0] == "printf_format") {
1996 if (eval (nv[1]) == "1") {
1997 m.printf_format = true;
1999 } else if (nv[0] == "transfer_ownership") {
2000 if (eval (nv[1]) == "1") {
2001 return_type.value_owned = true;
2003 } else if (nv[0] == "nullable") {
2004 if (eval (nv[1]) == "1") {
2005 return_type.nullable = true;
2007 } else if (nv[0] == "sentinel") {
2008 m.sentinel = eval (nv[1]);
2009 } else if (nv[0] == "is_array") {
2010 if (eval (nv[1]) == "1") {
2011 return_type = new ArrayType (return_type, 1, return_type.source_reference);
2012 m.return_type = return_type;
2014 } else if (nv[0] == "throws") {
2015 if (eval (nv[1]) == "0") {
2016 suppress_throws = true;
2018 } else if (nv[0] == "error_types") {
2019 error_types = eval (nv[1]);
2020 } else if (nv[0] == "no_array_length") {
2021 if (eval (nv[1]) == "1") {
2022 m.no_array_length = true;
2024 } else if (nv[0] == "array_null_terminated") {
2025 if (eval (nv[1]) == "1") {
2026 m.no_array_length = true;
2027 m.array_null_terminated = true;
2029 } else if (nv[0] == "array_length_type") {
2030 m.array_length_type = eval (nv[1]);
2031 } else if (nv[0] == "type_name") {
2032 m.return_type = return_type = parse_type_from_string (eval (nv[1]), false);
2033 } else if (nv[0] == "type_arguments") {
2034 parse_type_arguments_from_string (return_type, eval (nv[1]));
2035 } else if (nv[0] == "deprecated") {
2036 if (eval (nv[1]) == "1") {
2037 m.deprecated = true;
2039 } else if (nv[0] == "replacement") {
2040 m.replacement = eval (nv[1]);
2041 } else if (nv[0] == "deprecated_since") {
2042 m.deprecated_since = eval (nv[1]);
2043 } else if (nv[0] == "cheader_filename") {
2044 m.add_cheader_filename (eval (nv[1]));
2045 } else if (nv[0] == "abstract") {
2046 if (eval (nv[1]) == "1") {
2047 m.is_abstract = true;
2049 } else if (nv[0] == "virtual") {
2050 if (eval (nv[1]) == "1") {
2051 m.is_virtual = true;
2053 } else if (nv[0] == "vfunc_name") {
2054 m.vfunc_name = eval (nv[1]);
2055 } else if (nv[0] == "finish_name") {
2056 m.set_finish_cname (eval (nv[1]));
2057 } else if (nv[0] == "async") {
2058 if (eval (nv[1]) == "1") {
2059 // force async function, even if it doesn't end in _async
2060 m.coroutine = true;
2062 } else if (nv[0] == "parent") {
2063 Symbol container = get_container_from_name (eval (nv[1]));
2064 var prefix = container.get_lower_case_cprefix ();
2065 if (symbol.has_prefix (prefix)) {
2066 m.set_cname (m.name);
2067 m.name = symbol.offset (prefix.length);
2073 m.set_cname (symbol);
2075 bool first = true;
2076 Parameter last_param = null;
2077 DataType last_param_type = null;
2078 foreach (weak IdlNodeParam param in parameters) {
2079 weak IdlNode param_node = (IdlNode) param;
2081 if (first) {
2082 first = false;
2083 if (!(m is CreationMethod) &&
2084 current_data_type != null &&
2085 param.type.is_interface &&
2086 (param_node.name == "self" ||
2087 param.type.@interface.has_suffix (current_data_type.get_cname ()))) {
2088 // instance method
2089 continue;
2090 } else if (!(m is CreationMethod) &&
2091 current_data_type != null &&
2092 param.type.is_interface &&
2093 (param_node.name == "klass" ||
2094 param.type.@interface.has_suffix ("%sClass".printf(current_data_type.get_cname ())))) {
2095 // class method
2096 m.binding = MemberBinding.CLASS;
2097 if (m.name.has_prefix ("class_")) {
2098 m.name = m.name.substring ("class_".length, m.name.length - "class_".length);
2100 continue;
2101 } else {
2102 // static method
2103 m.binding = MemberBinding.STATIC;
2107 if (param.type.@interface == "GAsyncReadyCallback" && (symbol.has_suffix ("_async") || m.coroutine)) {
2108 // async method
2109 m.coroutine = true;
2110 continue;
2113 if (suppress_throws == false && param_is_exception (param)) {
2114 if (error_types == null)
2115 m.add_error_type (parse_type (param.type));
2116 continue;
2119 string param_name = param_node.name;
2120 if (param_name == "result") {
2121 // avoid conflict with generated result variable
2122 param_name = "_result";
2123 } else if (param_name == "string") {
2124 // avoid conflict with string type
2125 param_name = "str";
2127 ParameterDirection direction;
2128 var param_type = parse_param (param, out direction);
2129 var p = new Parameter (param_name, param_type);
2130 p.direction = direction;
2132 bool hide_param = false;
2133 bool show_param = false;
2134 bool set_array_length_pos = false;
2135 double array_length_pos = 0;
2136 bool set_delegate_target_pos = false;
2137 double delegate_target_pos = 0;
2138 bool array_requested = false;
2139 bool out_requested = false;
2140 attributes = get_attributes ("%s.%s".printf (symbol, param_node.name));
2141 if (attributes != null) {
2142 foreach (string attr in attributes) {
2143 var nv = attr.split ("=", 2);
2144 if (nv[0] == "is_array") {
2145 if (eval (nv[1]) == "1") {
2146 param_type = new ArrayType (param_type, 1, param_type.source_reference);
2147 p.variable_type = param_type;
2148 if (!out_requested) {
2149 p.direction = ParameterDirection.IN;
2151 array_requested = true;
2153 } else if (nv[0] == "is_out") {
2154 if (eval (nv[1]) == "1") {
2155 p.direction = ParameterDirection.OUT;
2156 out_requested = true;
2157 if (!array_requested && param_type is ArrayType) {
2158 var array_type = (ArrayType) param_type;
2159 param_type = array_type.element_type;
2160 p.variable_type = param_type;
2163 } else if (nv[0] == "is_ref") {
2164 if (eval (nv[1]) == "1") {
2165 p.direction = ParameterDirection.REF;
2166 if (!array_requested && param_type is ArrayType) {
2167 var array_type = (ArrayType) param_type;
2168 param_type = array_type.element_type;
2169 p.variable_type = param_type;
2172 } else if (nv[0] == "nullable") {
2173 if (eval (nv[1]) == "1") {
2174 param_type.nullable = true;
2176 } else if (nv[0] == "transfer_ownership") {
2177 if (eval (nv[1]) == "1") {
2178 param_type.value_owned = true;
2180 } else if (nv[0] == "takes_ownership") {
2181 if (eval (nv[1]) == "1") {
2182 param_type.value_owned = true;
2184 } else if (nv[0] == "value_owned") {
2185 if (eval (nv[1]) == "0") {
2186 param_type.value_owned = false;
2187 } else if (eval (nv[1]) == "1") {
2188 param_type.value_owned = true;
2190 } else if (nv[0] == "hidden") {
2191 if (eval (nv[1]) == "1") {
2192 hide_param = true;
2193 } else if (eval (nv[1]) == "0") {
2194 show_param = true;
2196 } else if (nv[0] == "no_array_length") {
2197 if (eval (nv[1]) == "1") {
2198 p.no_array_length = true;
2200 } else if (nv[0] == "array_length_type") {
2201 p.array_length_type = eval (nv[1]);
2202 } else if (nv[0] == "array_null_terminated") {
2203 if (eval (nv[1]) == "1") {
2204 p.no_array_length = true;
2205 p.array_null_terminated = true;
2207 } else if (nv[0] == "array_length_pos") {
2208 set_array_length_pos = true;
2209 array_length_pos = eval (nv[1]).to_double ();
2210 } else if (nv[0] == "delegate_target_pos") {
2211 set_delegate_target_pos = true;
2212 delegate_target_pos = eval (nv[1]).to_double ();
2213 } else if (nv[0] == "type_name") {
2214 p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
2215 } else if (nv[0] == "ctype") {
2216 p.ctype = eval (nv[1]);
2217 } else if (nv[0] == "type_arguments") {
2218 parse_type_arguments_from_string (param_type, eval (nv[1]));
2219 } else if (nv[0] == "default_value") {
2220 var val = eval (nv[1]);
2221 if (val == "null") {
2222 p.initializer = new NullLiteral (param_type.source_reference);
2223 } else if (val == "true") {
2224 p.initializer = new BooleanLiteral (true, param_type.source_reference);
2225 } else if (val == "false") {
2226 p.initializer = new BooleanLiteral (false, param_type.source_reference);
2227 } else if (val == "") {
2228 p.initializer = new StringLiteral ("\"\"", param_type.source_reference);
2229 } else {
2230 unowned string endptr;
2231 unowned string val_end = val.offset (val.length);
2233 val.to_long (out endptr);
2234 if ((long)endptr == (long)val_end) {
2235 p.initializer = new IntegerLiteral (val, param_type.source_reference);
2236 } else {
2237 val.to_double (out endptr);
2238 if ((long)endptr == (long)val_end) {
2239 p.initializer = new RealLiteral (val, param_type.source_reference);
2240 } else {
2241 if (val.has_prefix ("\"") && val.has_suffix ("\"")) {
2242 p.initializer = new StringLiteral (val, param_type.source_reference);
2243 } else {
2244 foreach (var member in val.split (".")) {
2245 p.initializer = new MemberAccess (p.initializer, member, param_type.source_reference);
2255 if (last_param != null && p.name == "n_" + last_param.name) {
2256 if (!(last_param_type is ArrayType)) {
2257 // last_param is array, p is array length
2258 last_param_type = new ArrayType (last_param_type, 1, last_param_type.source_reference);
2259 last_param.variable_type = last_param_type;
2260 last_param.direction = ParameterDirection.IN;
2263 // hide array length param
2264 hide_param = true;
2265 } else if (last_param != null && p.name == "user_data") {
2266 // last_param is delegate
2268 // hide deleate target param
2269 hide_param = true;
2272 if (show_param || !hide_param) {
2273 m.add_parameter (p);
2274 if (set_array_length_pos) {
2275 p.carray_length_parameter_position = array_length_pos;
2277 if (set_delegate_target_pos) {
2278 p.cdelegate_target_parameter_position = delegate_target_pos;
2282 last_param = p;
2283 last_param_type = param_type;
2286 if (suppress_throws == false && error_types != null) {
2287 var type_args = eval (error_types).split (",");
2288 foreach (string type_arg in type_args) {
2289 m.add_error_type (parse_type_from_string (type_arg, true));
2293 if (first) {
2294 // no parameters => static method
2295 m.binding = MemberBinding.STATIC;
2298 if (last_param != null && last_param.name.has_prefix ("first_")) {
2299 last_param.ellipsis = true;
2300 } else if (add_ellipsis) {
2301 m.add_parameter (new Parameter.with_ellipsis ());
2304 return m;
2307 private bool param_is_exception (IdlNodeParam param) {
2308 if (!param.type.is_error) {
2309 return false;
2311 var s = param.type.unparsed.chomp ();
2312 if (s.has_suffix ("**")) {
2313 return true;
2315 return false;
2318 private Method? parse_function (IdlNodeFunction f, bool is_interface = false) {
2319 weak IdlNode node = (IdlNode) f;
2321 if (f.deprecated) {
2322 return null;
2325 return create_method (node.name, f.symbol, f.result, f.parameters, f.is_constructor, is_interface);
2328 private Method parse_virtual (IdlNodeVFunc v, IdlNodeFunction? func, bool is_interface = false) {
2329 weak IdlNode node = (IdlNode) v;
2330 string symbol = "%s%s".printf (current_data_type.get_lower_case_cprefix(), node.name);
2332 if (func != null) {
2333 symbol = func.symbol;
2336 Method m = create_method (node.name, symbol, v.result, func != null ? func.parameters : v.parameters, false, is_interface);
2337 if (m != null) {
2338 m.binding = MemberBinding.INSTANCE;
2339 m.is_virtual = !(m.is_abstract || is_interface);
2340 m.is_abstract = m.is_abstract || is_interface;
2342 var attributes = get_attributes (symbol);
2343 if (attributes != null) {
2344 foreach (string attr in attributes) {
2345 var nv = attr.split ("=", 2);
2346 if (nv[0] == "virtual") {
2347 if (eval (nv[1]) == "0") {
2348 m.is_virtual = false;
2349 m.is_abstract = false;
2350 } else {
2351 m.is_virtual = true;
2352 m.is_abstract = false;
2358 if (func == null) {
2359 m.attributes.append (new Attribute ("NoWrapper", null));
2363 return m;
2366 private string fix_prop_name (string name) {
2367 var str = new StringBuilder ();
2369 string i = name;
2371 while (i.length > 0) {
2372 unichar c = i.get_char ();
2373 if (c == '-') {
2374 str.append_c ('_');
2375 } else {
2376 str.append_unichar (c);
2379 i = i.next_char ();
2382 return str.str;
2385 private Property? parse_property (IdlNodeProperty prop_node) {
2386 weak IdlNode node = (IdlNode) prop_node;
2388 if (prop_node.deprecated) {
2389 return null;
2392 if (!prop_node.readable && !prop_node.writable) {
2393 // buggy GIDL definition
2394 prop_node.readable = true;
2395 prop_node.writable = true;
2398 var prop = new Property (fix_prop_name (node.name), parse_type (prop_node.type), null, null, current_source_reference);
2399 prop.access = SymbolAccessibility.PUBLIC;
2400 prop.interface_only = true;
2402 if (prop_node.type.is_interface && prop_node.type.interface == "GStrv") {
2403 prop.no_array_length = true;
2404 prop.array_null_terminated = true;
2407 if (prop_node.readable) {
2408 prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, null);
2410 if (prop_node.writable) {
2411 prop.set_accessor = new PropertyAccessor (false, false, false, prop.property_type.copy (), null, null);
2412 if (prop_node.construct_only) {
2413 prop.set_accessor.construction = true;
2414 } else {
2415 prop.set_accessor.writable = true;
2416 prop.set_accessor.construction = prop_node.@construct;
2420 var attributes = get_attributes ("%s:%s".printf (current_data_type.get_cname (), node.name));
2421 if (attributes != null) {
2422 foreach (string attr in attributes) {
2423 var nv = attr.split ("=", 2);
2424 if (nv[0] == "hidden") {
2425 if (eval (nv[1]) == "1") {
2426 return null;
2428 } else if (nv[0] == "type_arguments") {
2429 parse_type_arguments_from_string (prop.property_type, eval (nv[1]));
2430 } else if (nv[0] == "deprecated") {
2431 if (eval (nv[1]) == "1") {
2432 prop.deprecated = true;
2434 } else if (nv[0] == "replacement") {
2435 prop.replacement = eval (nv[1]);
2436 } else if (nv[0] == "deprecated_since") {
2437 prop.deprecated_since = eval (nv[1]);
2438 } else if (nv[0] == "accessor_method") {
2439 if (eval (nv[1]) == "0") {
2440 prop.no_accessor_method = true;
2442 } else if (nv[0] == "owned_get") {
2443 if (eval (nv[1]) == "1") {
2444 prop.get_accessor.value_type.value_owned = true;
2446 } else if (nv[0] == "type_name") {
2447 prop.property_type = parse_type_from_string (eval (nv[1]), false);
2452 if (current_type_symbol_set != null) {
2453 current_type_symbol_set.add (prop.name);
2456 return prop;
2459 private Constant? parse_constant (IdlNodeConstant const_node) {
2460 weak IdlNode node = (IdlNode) const_node;
2462 var type = parse_type (const_node.type);
2463 if (type == null) {
2464 return null;
2467 var c = new Constant (node.name, type, null, current_source_reference);
2468 c.external = true;
2470 string[] attributes = get_attributes (node.name);
2471 if (attributes != null) {
2472 foreach (string attr in attributes) {
2473 var nv = attr.split ("=", 2);
2474 if (nv[0] == "cheader_filename") {
2475 c.add_cheader_filename (eval (nv[1]));
2476 } else if (nv[0] == "deprecated") {
2477 if (eval (nv[1]) == "1") {
2478 c.deprecated = true;
2480 } else if (nv[0] == "replacement") {
2481 c.replacement = eval (nv[1]);
2482 } else if (nv[0] == "deprecated_since") {
2483 c.deprecated_since = eval (nv[1]);
2484 } else if (nv[0] == "hidden") {
2485 if (eval (nv[1]) == "1") {
2486 return null;
2492 c.access = SymbolAccessibility.PUBLIC;
2494 return c;
2497 private Field? parse_field (IdlNodeField field_node) {
2498 weak IdlNode node = (IdlNode) field_node;
2499 bool unhidden = false;
2501 var type = parse_type (field_node.type);
2502 if (type == null) {
2503 return null;
2506 string cheader_filename = null;
2507 string ctype = null;
2508 string array_length_cname = null;
2509 string array_length_type = null;
2510 bool array_null_terminated = false;
2511 bool deprecated = false;
2512 string deprecated_since = null;
2513 string replacement = null;
2515 var attributes = get_attributes ("%s.%s".printf (current_data_type.get_cname (), node.name));
2516 if (attributes != null) {
2517 foreach (string attr in attributes) {
2518 var nv = attr.split ("=", 2);
2519 if (nv[0] == "hidden") {
2520 if (eval (nv[1]) == "1") {
2521 return null;
2522 } else {
2523 unhidden = true;
2525 } else if (nv[0] == "is_array") {
2526 if (eval (nv[1]) == "1") {
2527 type = new ArrayType (type, 1, type.source_reference);
2529 } else if (nv[0] == "weak") {
2530 if (eval (nv[1]) == "0") {
2531 type.value_owned = true;
2533 } else if (nv[0] == "type_name") {
2534 type = parse_type_from_string (eval (nv[1]), true);
2535 } else if (nv[0] == "type_arguments") {
2536 parse_type_arguments_from_string (type, eval (nv[1]));
2537 } else if (nv[0] == "deprecated") {
2538 if (eval (nv[1]) == "1") {
2539 deprecated = true;
2541 } else if (nv[0] == "replacement") {
2542 replacement = eval (nv[1]);
2543 } else if (nv[0] == "deprecated_since") {
2544 deprecated_since = eval (nv[1]);
2545 } else if (nv[0] == "cheader_filename") {
2546 cheader_filename = eval (nv[1]);
2547 } else if (nv[0] == "ctype") {
2548 ctype = eval (nv[1]);
2549 } else if (nv[0] == "array_null_terminated") {
2550 if (eval (nv[1]) == "1") {
2551 array_null_terminated = true;
2553 } else if (nv[0] == "array_length_cname") {
2554 array_length_cname = eval (nv[1]);
2555 } else if (nv[0] == "array_length_type") {
2556 array_length_type = eval (nv[1]);
2561 if (node.name.has_prefix("_") && !unhidden) {
2562 return null;
2565 if (current_type_symbol_set != null) {
2566 current_type_symbol_set.add (node.name);
2569 string field_name = node.name;
2570 if (field_name == "string") {
2571 // avoid conflict with string type
2572 field_name = "str";
2575 var field = new Field (field_name, type, null, current_source_reference);
2576 field.access = SymbolAccessibility.PUBLIC;
2578 if (field_name != node.name) {
2579 field.set_cname (node.name);
2582 if (deprecated) {
2583 field.deprecated = true;
2585 if (deprecated_since != null) {
2586 field.deprecated_since = deprecated_since;
2589 if (replacement != null) {
2590 field.replacement = replacement;
2594 if (ctype != null) {
2595 field.set_ctype (ctype);
2598 if (cheader_filename != null) {
2599 field.add_cheader_filename (cheader_filename);
2602 if (array_null_terminated) {
2603 field.array_null_terminated = true;
2606 if (array_length_cname != null || array_length_type != null) {
2607 if (array_length_cname != null) {
2608 field.set_array_length_cname (array_length_cname);
2610 if (array_length_type != null) {
2611 field.array_length_type = array_length_type;
2613 } else {
2614 field.no_array_length = true;
2617 return field;
2620 private string[]? get_attributes (string codenode) {
2621 var attributes = codenode_attributes_map.get (codenode);
2623 if (attributes == null) {
2624 var dot_required = (null != codenode.chr (-1, '.'));
2625 var colon_required = (null != codenode.chr (-1, ':'));
2627 var pattern_specs = codenode_attributes_patterns.get_keys ();
2628 foreach (PatternSpec* pattern in pattern_specs) {
2629 var pspec = codenode_attributes_patterns[pattern];
2631 if ((dot_required && null == pspec.chr (-1, '.')) ||
2632 (colon_required && null == pspec.chr (-1, ':'))) {
2633 continue;
2636 if (pattern->match_string (codenode)) {
2637 return get_attributes (pspec);
2642 if (attributes == null) {
2643 return null;
2646 GLib.SList<string> attr_list = new GLib.SList<string> ();
2647 var attr = new GLib.StringBuilder.sized (attributes.length);
2648 var attributes_len = attributes.length;
2649 unowned string remaining = attributes;
2650 bool quoted = false, escaped = false;
2651 for (int b = 0 ; b < attributes_len ; b++) {
2652 unichar c = remaining.get_char ();
2654 if (escaped) {
2655 escaped = false;
2656 attr.append_unichar (c);
2657 } else {
2658 if (c == '"') {
2659 attr.append_unichar (c);
2660 quoted = !quoted;
2661 } else if (c == '\\') {
2662 escaped = true;
2663 } else if (!quoted && (c == ' ')) {
2664 attr_list.prepend (attr.str);
2665 attr.truncate (0);
2666 } else {
2667 attr.append_unichar (c);
2671 remaining = remaining.offset (1);
2674 if (attr.len > 0) {
2675 attr_list.prepend (attr.str);
2678 var attrs = new string[attr_list.length ()];
2679 unowned GLib.SList<string>? attr_i = attr_list;
2680 for (int a = 0 ; a < attrs.length ; a++, attr_i = attr_i.next) {
2681 attrs[(attrs.length - 1) - a] = attr_i.data;
2684 return attrs;
2687 private string eval (string s) {
2688 return ((s.length >= 2) && s.has_prefix ("\"") && s.has_suffix ("\"")) ? s.offset (1).ndup (s.length - 2) : s;
2691 private Signal? parse_signal (IdlNodeSignal sig_node) {
2692 weak IdlNode node = (IdlNode) sig_node;
2694 if (sig_node.deprecated || sig_node.result == null) {
2695 return null;
2698 var sig = new Signal (fix_prop_name (node.name), parse_param (sig_node.result), current_source_reference);
2699 sig.access = SymbolAccessibility.PUBLIC;
2701 var attributes = get_attributes ("%s::%s".printf (current_data_type.get_cname (), sig.name));
2702 if (attributes != null) {
2703 string ns_name = null;
2704 foreach (string attr in attributes) {
2705 var nv = attr.split ("=", 2);
2706 if (nv[0] == "name") {
2707 sig.set_cname (sig.name);
2708 sig.name = eval (nv[1]);
2709 } else if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
2710 sig.has_emitter = true;
2711 } else if (nv[0] == "hidden") {
2712 if (eval (nv[1]) == "1") {
2713 return null;
2715 } else if (nv[0] == "deprecated") {
2716 if (eval (nv[1]) == "1") {
2717 sig.deprecated = true;
2719 } else if (nv[0] == "replacement") {
2720 sig.replacement = eval (nv[1]);
2721 } else if (nv[0] == "deprecated_since") {
2722 sig.deprecated_since = eval (nv[1]);
2723 } else if (nv[0] == "transfer_ownership") {
2724 if (eval (nv[1]) == "1") {
2725 sig.return_type.value_owned = true;
2727 } else if (nv[0] == "namespace_name") {
2728 ns_name = eval (nv[1]);
2729 } else if (nv[0] == "type_name") {
2730 sig.return_type = parse_type_from_string (eval (nv[1]), false);
2731 } else if (nv[0] == "type_arguments") {
2732 parse_type_arguments_from_string (sig.return_type, eval (nv[1]));
2735 if (ns_name != null) {
2736 ((UnresolvedType) sig.return_type).unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
2740 sig.is_virtual = true;
2742 bool first = true;
2744 foreach (weak IdlNodeParam param in sig_node.parameters) {
2745 if (first) {
2746 // ignore implicit first signal parameter (sender)
2747 first = false;
2748 continue;
2751 weak IdlNode param_node = (IdlNode) param;
2753 ParameterDirection direction;
2754 var param_type = parse_param (param, out direction);
2755 var p = new Parameter (param_node.name, param_type);
2756 p.direction = direction;
2758 bool hide_param = false;
2759 bool show_param = false;
2760 attributes = get_attributes ("%s::%s.%s".printf (current_data_type.get_cname (), sig.name, param_node.name));
2761 if (attributes != null) {
2762 string ns_name = null;
2763 foreach (string attr in attributes) {
2764 var nv = attr.split ("=", 2);
2765 if (nv[0] == "hidden") {
2766 if (eval (nv[1]) == "1") {
2767 hide_param = true;
2768 } else if (eval (nv[1]) == "0") {
2769 show_param = true;
2771 } else if (nv[0] == "is_array") {
2772 if (eval (nv[1]) == "1") {
2773 param_type = new ArrayType (param_type, 1, param_type.source_reference);
2774 p.variable_type = param_type;
2775 p.direction = ParameterDirection.IN;
2777 } else if (nv[0] == "is_out") {
2778 if (eval (nv[1]) == "1") {
2779 p.direction = ParameterDirection.OUT;
2781 } else if (nv[0] == "is_ref") {
2782 if (eval (nv[1]) == "1") {
2783 p.direction = ParameterDirection.REF;
2785 } else if (nv[0] == "nullable") {
2786 if (eval (nv[1]) == "1") {
2787 param_type.nullable = true;
2789 } else if (nv[0] == "transfer_ownership") {
2790 if (eval (nv[1]) == "1") {
2791 param_type.value_owned = true;
2793 } else if (nv[0] == "type_name") {
2794 p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
2795 } else if (nv[0] == "type_arguments") {
2796 parse_type_arguments_from_string (p.variable_type, eval (nv[1]));
2797 } else if (nv[0] == "namespace_name") {
2798 ns_name = eval (nv[1]);
2801 if (ns_name != null) {
2802 ((UnresolvedType) param_type).unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
2806 if (show_param || !hide_param) {
2807 sig.add_parameter (p);
2811 return sig;
2815 // vim:sw=8 noet