codegen: Move main declaration to the beginning in visit_local_variable
[vala-lang.git] / vapigen / valagidlparser.vala
blob81978d1a1741bd9d70f20f912eb316b3f2b8d71e
1 /* valagidlparser.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using GLib;
27 /**
28 * Code visitor parsing all GIDL files.
30 public class Vala.GIdlParser : CodeVisitor {
31 private CodeContext context;
33 private SourceFile current_source_file;
35 private SourceReference current_source_reference;
37 private Namespace current_namespace;
38 private TypeSymbol current_data_type;
39 private Map<string,string> codenode_attributes_map;
40 private Map<PatternSpec*,string> codenode_attributes_patterns;
41 private Set<string> current_type_symbol_set;
43 private Map<string,TypeSymbol> cname_type_map;
45 static GLib.Regex type_from_string_regex;
47 /**
48 * Parse all source files in the specified code context and build a
49 * code tree.
51 * @param context a code context
53 public void parse (CodeContext context) {
54 cname_type_map = new HashMap<string,TypeSymbol> (str_hash, str_equal);
56 this.context = context;
57 context.accept (this);
59 cname_type_map = null;
62 public override void visit_namespace (Namespace ns) {
63 ns.accept_children (this);
66 public override void visit_class (Class cl) {
67 visit_type (cl);
70 public override void visit_struct (Struct st) {
71 visit_type (st);
74 public override void visit_interface (Interface iface) {
75 visit_type (iface);
78 public override void visit_enum (Enum en) {
79 visit_type (en);
82 public override void visit_error_domain (ErrorDomain ed) {
83 visit_type (ed);
86 public override void visit_delegate (Delegate d) {
87 visit_type (d);
90 private void visit_type (TypeSymbol t) {
91 if (!cname_type_map.contains (t.get_cname ())) {
92 cname_type_map[t.get_cname ()] = t;
96 public override void visit_source_file (SourceFile source_file) {
97 if (source_file.filename.has_suffix (".gi")) {
98 parse_file (source_file);
102 private void parse_file (SourceFile source_file) {
103 string metadata_filename = "%s.metadata".printf (source_file.filename.substring (0, source_file.filename.length - ".gi".length));
105 current_source_file = source_file;
107 codenode_attributes_map = new HashMap<string,string> (str_hash, str_equal);
108 codenode_attributes_patterns = new HashMap<PatternSpec*,string> (direct_hash, (EqualFunc) PatternSpec.equal);
110 if (FileUtils.test (metadata_filename, FileTest.EXISTS)) {
111 try {
112 string metadata;
113 FileUtils.get_contents (metadata_filename, out metadata, null);
115 foreach (string line in metadata.split ("\n")) {
116 if (line.has_prefix ("#")) {
117 // ignore comment lines
118 continue;
121 var tokens = line.split (" ", 2);
123 if (null == tokens[0]) {
124 continue;
127 if (-1 != tokens[0].index_of_char ('*')) {
128 PatternSpec* pattern = new PatternSpec (tokens[0]);
129 codenode_attributes_patterns[pattern] = tokens[0];
132 codenode_attributes_map[tokens[0]] = tokens[1];
134 } catch (FileError e) {
135 Report.error (null, "Unable to read metadata file: %s".printf (e.message));
139 try {
140 var modules = Idl.parse_file (source_file.filename);
142 current_source_reference = new SourceReference (source_file);
144 foreach (weak IdlModule module in modules) {
145 var ns = parse_module (module);
146 if (ns != null) {
147 context.root.add_namespace (ns);
150 } catch (MarkupError e) {
151 Report.error (null, "Unable to parse GIDL file: %s".printf (e.message));
155 private string fix_type_name (string type_name, Symbol container) {
156 var attributes = get_attributes (type_name);
157 if (attributes != null) {
158 foreach (string attr in attributes) {
159 var nv = attr.split ("=", 2);
160 if (nv[0] == "name") {
161 return eval (nv[1]);
166 if (type_name.has_prefix (container.name)) {
167 return type_name.substring (container.name.length);
168 } else if (container.name == "GLib" && type_name.has_prefix ("G")) {
169 return type_name.substring (1);
170 } else {
171 string best_match = null;
172 if (container is Namespace) {
173 foreach (string cprefix in ((Namespace) container).get_cprefixes ()) {
174 if (type_name.has_prefix (cprefix)) {
175 if (best_match == null || cprefix.length > best_match.length)
176 best_match = cprefix;
179 } else {
180 best_match = container.get_cprefix ();
183 if (best_match != null) {
184 return type_name.substring (best_match.length);;
188 return type_name;
191 private string fix_const_name (string const_name, Symbol container) {
192 var pref = container.get_lower_case_cprefix ().up ();
193 if (const_name.has_prefix (pref)) {
194 return const_name.substring (pref.length);
196 return const_name;
199 private string[] get_attributes_for_node (IdlNode node) {
200 string name;
202 if (node.type == IdlNodeTypeId.FUNCTION) {
203 name = ((IdlNodeFunction) node).symbol;
204 } else if (node.type == IdlNodeTypeId.SIGNAL) {
205 name = "%s::%s".printf (current_data_type.get_cname (), node.name);
206 } else if (node.type == IdlNodeTypeId.PROPERTY) {
207 name = "%s:%s".printf (current_data_type.get_cname (), node.name);
208 } else if (node.type == IdlNodeTypeId.FIELD) {
209 name = "%s.%s".printf (current_data_type.get_cname (), node.name);
210 } else {
211 name = node.name;
214 return get_attributes (name);
217 private void add_symbol_to_container (Symbol container, Symbol sym) {
218 if (container is Class) {
219 unowned Class cl = (Class) container;
221 if (sym is Class) {
222 cl.add_class ((Class) sym);
223 } else if (sym is Constant) {
224 cl.add_constant ((Constant) sym);
225 } else if (sym is Enum) {
226 cl.add_enum ((Enum) sym);
227 } else if (sym is Field) {
228 cl.add_field ((Field) sym);
229 } else if (sym is Method) {
230 cl.add_method ((Method) sym);
231 } else if (sym is Property) {
232 cl.add_property ((Property) sym);
233 } else if (sym is Signal) {
234 cl.add_signal ((Signal) sym);
235 } else if (sym is Struct) {
236 cl.add_struct ((Struct) sym);
238 } else if (container is Enum) {
239 unowned Enum en = (Enum) container;
241 if (sym is EnumValue) {
242 en.add_value ((EnumValue) sym);
243 } else if (sym is Constant) {
244 en.add_constant ((Constant) sym);
245 } else if (sym is Method) {
246 en.add_method ((Method) sym);
248 } else if (container is Interface) {
249 unowned Interface iface = (Interface) container;
251 if (sym is Class) {
252 iface.add_class ((Class) sym);
253 } else if (sym is Constant) {
254 iface.add_constant ((Constant) sym);
255 } else if (sym is Enum) {
256 iface.add_enum ((Enum) sym);
257 } else if (sym is Field) {
258 iface.add_field ((Field) sym);
259 } else if (sym is Method) {
260 iface.add_method ((Method) sym);
261 } else if (sym is Property) {
262 iface.add_property ((Property) sym);
263 } else if (sym is Signal) {
264 iface.add_signal ((Signal) sym);
265 } else if (sym is Struct) {
266 iface.add_struct ((Struct) sym);
268 } else if (container is Namespace) {
269 unowned Namespace ns = (Namespace) container;
271 if (sym is Namespace) {
272 ns.add_namespace ((Namespace) sym);
273 } else if (sym is Class) {
274 ns.add_class ((Class) sym);
275 } else if (sym is Constant) {
276 ns.add_constant ((Constant) sym);
277 } else if (sym is Delegate) {
278 ns.add_delegate ((Delegate) sym);
279 } else if (sym is Enum) {
280 ns.add_enum ((Enum) sym);
281 } else if (sym is ErrorDomain) {
282 ns.add_error_domain ((ErrorDomain) sym);
283 } else if (sym is Field) {
284 ns.add_field ((Field) sym);
285 } else if (sym is Interface) {
286 ns.add_interface ((Interface) sym);
287 } else if (sym is Method) {
288 ns.add_method ((Method) sym);
289 } else if (sym is Namespace) {
290 ns.add_namespace ((Namespace) sym);
291 } else if (sym is Struct) {
292 ns.add_struct ((Struct) sym);
294 } else if (container is Struct) {
295 unowned Struct st = (Struct) container;
297 if (sym is Constant) {
298 st.add_constant ((Constant) sym);
299 } else if (sym is Field) {
300 st.add_field ((Field) sym);
301 } else if (sym is Method) {
302 st.add_method ((Method) sym);
303 } else if (sym is Property) {
304 st.add_property ((Property) sym);
309 private void parse_node (IdlNode node, IdlModule module, Symbol container) {
310 if (node.type == IdlNodeTypeId.CALLBACK) {
311 var cb = parse_delegate ((IdlNodeFunction) node);
312 if (cb == null) {
313 return;
315 cb.name = fix_type_name (cb.name, container);
316 add_symbol_to_container (container, cb);
317 current_source_file.add_node (cb);
318 } else if (node.type == IdlNodeTypeId.STRUCT) {
319 parse_struct ((IdlNodeStruct) node, container, module);
320 } else if (node.type == IdlNodeTypeId.UNION) {
321 parse_union ((IdlNodeUnion) node, container, module);
322 } else if (node.type == IdlNodeTypeId.BOXED) {
323 parse_boxed ((IdlNodeBoxed) node, container, module);
324 } else if (node.type == IdlNodeTypeId.ENUM) {
325 parse_enum ((IdlNodeEnum) node, container, module, false);
326 } else if (node.type == IdlNodeTypeId.FLAGS) {
327 parse_enum ((IdlNodeEnum) node, container, module, true);
328 } else if (node.type == IdlNodeTypeId.OBJECT) {
329 parse_object ((IdlNodeInterface) node, container, module);
330 } else if (node.type == IdlNodeTypeId.INTERFACE) {
331 parse_interface ((IdlNodeInterface) node, container, module);
332 } else if (node.type == IdlNodeTypeId.CONSTANT) {
333 var c = parse_constant ((IdlNodeConstant) node);
334 if (c != null) {
335 c.name = fix_const_name (c.name, container);
336 add_symbol_to_container (container, c);
337 current_source_file.add_node (c);
339 } else if (node.type == IdlNodeTypeId.FUNCTION) {
340 var m = parse_function ((IdlNodeFunction) node);
341 if (m != null) {
342 m.binding = MemberBinding.STATIC;
343 add_symbol_to_container (container, m);
344 current_source_file.add_node (m);
349 private Symbol? get_container_from_name (string name) {
350 var path = name.split (".");
351 Symbol? cp = current_namespace;
352 Symbol? cc = null;
354 foreach ( unowned string tok in path ) {
355 cc = cp.scope.lookup (tok) as Symbol;
356 if ( cc == null ) {
357 cc = new Namespace (tok, current_source_reference);
358 ((Namespace) cc).add_cprefix (cp.get_cprefix () + tok);
359 add_symbol_to_container (cp, cc);
361 cp = cc;
364 return cc;
367 private Namespace? parse_module (IdlModule module) {
368 Symbol sym = context.root.scope.lookup (module.name);
369 Namespace ns;
370 if (sym is Namespace) {
371 ns = (Namespace) sym;
372 if (ns.external_package) {
373 ns.attributes = null;
374 ns.source_reference = current_source_reference;
376 } else {
377 ns = new Namespace (module.name, current_source_reference);
380 current_namespace = ns;
382 var attributes = get_attributes (ns.name);
383 if (attributes != null) {
384 foreach (string attr in attributes) {
385 var nv = attr.split ("=", 2);
386 if (nv[0] == "cheader_filename") {
387 ns.set_cheader_filename (eval (nv[1]));
388 } else if (nv[0] == "cprefix") {
389 var cprefixes = eval (nv[1]).split (",");
390 foreach(string name in cprefixes) {
391 ns.add_cprefix (name);
393 } else if (nv[0] == "lower_case_cprefix") {
394 ns.set_lower_case_cprefix (eval (nv[1]));
395 } else if (nv[0] == "gir_namespace") {
396 ns.source_reference.file.gir_namespace = eval (nv[1]);
397 } else if (nv[0] == "gir_version") {
398 ns.source_reference.file.gir_version = eval (nv[1]);
403 var deferred = new ArrayList<unowned IdlNode> ();
405 foreach (weak IdlNode node in module.entries) {
406 bool is_deferred = false;
407 var child_attributes = get_attributes_for_node (node);
408 if (child_attributes != null) {
409 foreach (unowned string attr in child_attributes) {
410 var nv = attr.split ("=", 2);
411 if (nv[0] == "parent") {
412 deferred.add (node);
413 is_deferred = true;
418 if (!is_deferred) {
419 parse_node (node, module, ns);
423 foreach (unowned IdlNode node in deferred) {
424 Symbol container = ns;
425 var child_attributes = get_attributes_for_node (node);
426 if (child_attributes != null) {
427 foreach (unowned string attr in child_attributes) {
428 var nv = attr.split ("=", 2);
429 if (nv[0] == "parent") {
430 container = get_container_from_name (eval (nv[1]));
435 parse_node (node, module, container);
438 current_namespace = null;
440 if (sym is Namespace) {
441 return null;
443 return ns;
446 private Delegate? parse_delegate (IdlNodeFunction f_node) {
447 weak IdlNode node = (IdlNode) f_node;
449 var return_type = parse_param (f_node.result);
451 var cb = new Delegate (node.name, return_type, current_source_reference);
452 cb.access = SymbolAccessibility.PUBLIC;
454 bool check_has_target = true;
456 var attributes = get_attributes (node.name);
457 if (attributes != null) {
458 foreach (string attr in attributes) {
459 var nv = attr.split ("=", 2);
460 if (nv[0] == "hidden") {
461 if (eval (nv[1]) == "1") {
462 return null;
464 } else if (nv[0] == "cheader_filename") {
465 cb.add_cheader_filename (eval (nv[1]));
466 } else if (nv[0] == "has_target") {
467 if (eval (nv[1]) == "0") {
468 check_has_target = false;
469 } else if (eval (nv[1]) == "1") {
470 cb.has_target = true;
472 } else if (nv[0] == "transfer_ownership") {
473 if (eval (nv[1]) == "1") {
474 return_type.value_owned = true;
476 } else if (nv[0] == "deprecated") {
477 if (eval (nv[1]) == "1") {
478 cb.deprecated = true;
480 } else if (nv[0] == "replacement") {
481 cb.replacement = eval (nv[1]);
482 } else if (nv[0] == "deprecated_since") {
483 cb.deprecated_since = eval (nv[1]);
484 } else if (nv[0] == "type_arguments") {
485 parse_type_arguments_from_string (return_type, eval (nv[1]));
486 } else if (nv[0] == "instance_pos") {
487 cb.cinstance_parameter_position = 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.substring (0, common_prefix.length - 1);
1172 } else {
1173 while (!value.name.has_prefix (common_prefix)) {
1174 common_prefix = common_prefix.substring (0, common_prefix.length - 1);
1177 while (common_prefix.length > 0 && (!common_prefix.has_suffix ("_") ||
1178 (value.name.get_char (common_prefix.length).isdigit ()) && (value.name.length - common_prefix.length) <= 1)) {
1179 // enum values may not consist solely of digits
1180 common_prefix = common_prefix.substring (0, 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.substring (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.substring ("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.substring (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.substring (current_namespace.name.length));
1775 } else if (n.has_prefix ("G")) {
1776 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), n.substring (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 array_dimension_data = match.fetch (6);
1869 var nullable_data = match.fetch (7);
1871 var nullable = nullable_data != null && nullable_data.length > 0;
1873 if (ownership_data == null && type_name == "void") {
1874 if (array_data == null && !nullable) {
1875 type = new VoidType (source_reference);
1876 if (pointers_data != null) {
1877 for (int i=0; i < pointers_data.length; i++) {
1878 type = new PointerType (type);
1881 return type;
1882 } else {
1883 Report.error (source_reference, "invalid void type");
1884 return null;
1888 bool value_owned = owned_by_default;
1890 if (ownership_data == "owned") {
1891 value_owned = true;
1892 } else if (ownership_data == "unowned") {
1893 value_owned = false;
1896 var sym = parse_symbol_from_string (type_name, source_reference);
1897 if (sym == null) {
1898 return null;
1900 type = new UnresolvedType.from_symbol (sym, source_reference);
1902 if (type_arguments_data != null && type_arguments_data.length > 0) {
1903 if (!parse_type_arguments_from_string (type, type_arguments_data, source_reference)) {
1904 return null;
1908 if (pointers_data != null) {
1909 for (int i=0; i < pointers_data.length; i++) {
1910 type = new PointerType (type);
1914 if (array_data != null && array_data.length > 0) {
1915 type = new ArrayType (type, array_dimension_data.length + 1, source_reference);
1918 type.nullable = nullable;
1919 type.value_owned = value_owned;
1920 return type;
1923 private Method? create_method (string name, string symbol, IdlNodeParam? res, GLib.List<IdlNodeParam>? parameters, bool is_constructor, bool is_interface) {
1924 DataType return_type = null;
1925 if (res != null) {
1926 return_type = parse_param (res);
1929 Method m;
1930 if (!is_interface && (is_constructor || name.has_prefix ("new"))) {
1931 m = new CreationMethod (null, name, current_source_reference);
1932 m.has_construct_function = false;
1933 if (m.name == "new") {
1934 m.name = null;
1935 } else if (m.name.has_prefix ("new_")) {
1936 m.name = m.name.substring ("new_".length);
1938 // For classes, check whether a creation method return type equals to the
1939 // type of the class created. If the types do not match (e.g. in most
1940 // gtk widgets) add an attribute to the creation method indicating the used
1941 // return type.
1942 if (current_data_type is Class && res != null) {
1943 if ("%s*".printf (current_data_type.get_cname()) != res.type.unparsed) {
1944 ((CreationMethod)m).custom_return_type_cname = res.type.unparsed;
1947 } else {
1948 m = new Method (name, return_type, current_source_reference);
1950 m.access = SymbolAccessibility.PUBLIC;
1952 if (current_type_symbol_set != null) {
1953 current_type_symbol_set.add (name);
1956 if (current_data_type != null) {
1957 var sig_attributes = get_attributes ("%s::%s".printf (current_data_type.get_cname (), name));
1958 if (sig_attributes != null) {
1959 foreach (string attr in sig_attributes) {
1960 var nv = attr.split ("=", 2);
1961 if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
1962 return null;
1968 bool add_ellipsis = false;
1969 bool suppress_throws = false;
1970 string? error_types = null;
1972 var attributes = get_attributes (symbol);
1973 if (attributes != null) {
1974 foreach (string attr in attributes) {
1975 var nv = attr.split ("=", 2);
1976 if (nv[0] == "name") {
1977 m.set_cname (m.name);
1978 m.name = eval (nv[1]);
1979 } else if (nv[0] == "hidden") {
1980 if (eval (nv[1]) == "1") {
1981 return null;
1983 } else if (nv[0] == "ellipsis") {
1984 if (eval (nv[1]) == "1") {
1985 add_ellipsis = true;
1987 } else if (nv[0] == "printf_format") {
1988 if (eval (nv[1]) == "1") {
1989 m.printf_format = true;
1991 } else if (nv[0] == "transfer_ownership") {
1992 if (eval (nv[1]) == "1") {
1993 return_type.value_owned = true;
1995 } else if (nv[0] == "nullable") {
1996 if (eval (nv[1]) == "1") {
1997 return_type.nullable = true;
1999 } else if (nv[0] == "sentinel") {
2000 m.sentinel = eval (nv[1]);
2001 } else if (nv[0] == "is_array") {
2002 if (eval (nv[1]) == "1") {
2003 return_type = new ArrayType (return_type, 1, return_type.source_reference);
2004 m.return_type = return_type;
2006 } else if (nv[0] == "throws") {
2007 if (eval (nv[1]) == "0") {
2008 suppress_throws = true;
2010 } else if (nv[0] == "error_types") {
2011 error_types = eval (nv[1]);
2012 } else if (nv[0] == "no_array_length") {
2013 if (eval (nv[1]) == "1") {
2014 m.no_array_length = true;
2016 } else if (nv[0] == "array_null_terminated") {
2017 if (eval (nv[1]) == "1") {
2018 m.no_array_length = true;
2019 m.array_null_terminated = true;
2021 } else if (nv[0] == "array_length_type") {
2022 m.array_length_type = eval (nv[1]);
2023 } else if (nv[0] == "type_name") {
2024 m.return_type = return_type = parse_type_from_string (eval (nv[1]), return_type.value_owned);
2025 } else if (nv[0] == "type_arguments") {
2026 parse_type_arguments_from_string (return_type, eval (nv[1]));
2027 } else if (nv[0] == "deprecated") {
2028 if (eval (nv[1]) == "1") {
2029 m.deprecated = true;
2031 } else if (nv[0] == "replacement") {
2032 m.replacement = eval (nv[1]);
2033 } else if (nv[0] == "deprecated_since") {
2034 m.deprecated_since = eval (nv[1]);
2035 } else if (nv[0] == "cheader_filename") {
2036 m.add_cheader_filename (eval (nv[1]));
2037 } else if (nv[0] == "abstract") {
2038 if (eval (nv[1]) == "1") {
2039 m.is_abstract = true;
2041 } else if (nv[0] == "virtual") {
2042 if (eval (nv[1]) == "1") {
2043 m.is_virtual = true;
2045 } else if (nv[0] == "vfunc_name") {
2046 m.vfunc_name = eval (nv[1]);
2047 } else if (nv[0] == "finish_name") {
2048 m.set_finish_cname (eval (nv[1]));
2049 } else if (nv[0] == "async") {
2050 if (eval (nv[1]) == "1") {
2051 // force async function, even if it doesn't end in _async
2052 m.coroutine = true;
2054 } else if (nv[0] == "parent") {
2055 Symbol container = get_container_from_name (eval (nv[1]));
2056 var prefix = container.get_lower_case_cprefix ();
2057 if (symbol.has_prefix (prefix)) {
2058 m.set_cname (m.name);
2059 m.name = symbol.substring (prefix.length);
2065 m.set_cname (symbol);
2067 bool first = true;
2068 Parameter last_param = null;
2069 DataType last_param_type = null;
2070 foreach (weak IdlNodeParam param in parameters) {
2071 weak IdlNode param_node = (IdlNode) param;
2073 if (first) {
2074 first = false;
2075 if (!(m is CreationMethod) &&
2076 current_data_type != null &&
2077 param.type.is_interface &&
2078 (param_node.name == "self" ||
2079 param.type.@interface.has_suffix (current_data_type.get_cname ()))) {
2080 // instance method
2081 continue;
2082 } else if (!(m is CreationMethod) &&
2083 current_data_type != null &&
2084 param.type.is_interface &&
2085 (param_node.name == "klass" ||
2086 param.type.@interface.has_suffix ("%sClass".printf(current_data_type.get_cname ())))) {
2087 // class method
2088 m.binding = MemberBinding.CLASS;
2089 if (m.name.has_prefix ("class_")) {
2090 m.name = m.name.substring ("class_".length, m.name.length - "class_".length);
2092 continue;
2093 } else {
2094 // static method
2095 m.binding = MemberBinding.STATIC;
2099 if (param.type.@interface == "GAsyncReadyCallback" && (symbol.has_suffix ("_async") || m.coroutine)) {
2100 // async method
2101 m.coroutine = true;
2102 continue;
2105 if (suppress_throws == false && param_is_exception (param)) {
2106 if (error_types == null)
2107 m.add_error_type (parse_type (param.type));
2108 continue;
2111 string param_name = param_node.name;
2112 if (param_name == "result") {
2113 // avoid conflict with generated result variable
2114 param_name = "_result";
2115 } else if (param_name == "string") {
2116 // avoid conflict with string type
2117 param_name = "str";
2119 ParameterDirection direction;
2120 var param_type = parse_param (param, out direction);
2121 var p = new Parameter (param_name, param_type);
2122 p.direction = direction;
2124 bool hide_param = false;
2125 bool show_param = false;
2126 bool set_array_length_pos = false;
2127 double array_length_pos = 0;
2128 bool set_delegate_target_pos = false;
2129 double delegate_target_pos = 0;
2130 bool array_requested = false;
2131 bool out_requested = false;
2132 attributes = get_attributes ("%s.%s".printf (symbol, param_node.name));
2133 if (attributes != null) {
2134 foreach (string attr in attributes) {
2135 var nv = attr.split ("=", 2);
2136 if (nv[0] == "is_array") {
2137 if (eval (nv[1]) == "1") {
2138 param_type = new ArrayType (param_type, 1, param_type.source_reference);
2139 p.variable_type = param_type;
2140 if (!out_requested) {
2141 p.direction = ParameterDirection.IN;
2143 array_requested = true;
2145 } else if (nv[0] == "is_out") {
2146 if (eval (nv[1]) == "1") {
2147 p.direction = ParameterDirection.OUT;
2148 out_requested = true;
2149 if (!array_requested && param_type is ArrayType) {
2150 var array_type = (ArrayType) param_type;
2151 param_type = array_type.element_type;
2152 p.variable_type = param_type;
2155 } else if (nv[0] == "is_ref") {
2156 if (eval (nv[1]) == "1") {
2157 p.direction = ParameterDirection.REF;
2158 if (!array_requested && param_type is ArrayType) {
2159 var array_type = (ArrayType) param_type;
2160 param_type = array_type.element_type;
2161 p.variable_type = param_type;
2164 } else if (nv[0] == "nullable") {
2165 if (eval (nv[1]) == "1") {
2166 param_type.nullable = true;
2168 } else if (nv[0] == "transfer_ownership") {
2169 if (eval (nv[1]) == "1") {
2170 param_type.value_owned = true;
2172 } else if (nv[0] == "takes_ownership") {
2173 if (eval (nv[1]) == "1") {
2174 param_type.value_owned = true;
2176 } else if (nv[0] == "value_owned") {
2177 if (eval (nv[1]) == "0") {
2178 param_type.value_owned = false;
2179 } else if (eval (nv[1]) == "1") {
2180 param_type.value_owned = true;
2182 } else if (nv[0] == "hidden") {
2183 if (eval (nv[1]) == "1") {
2184 hide_param = true;
2185 } else if (eval (nv[1]) == "0") {
2186 show_param = true;
2188 } else if (nv[0] == "no_array_length") {
2189 if (eval (nv[1]) == "1") {
2190 p.no_array_length = true;
2192 } else if (nv[0] == "array_length_type") {
2193 p.array_length_type = eval (nv[1]);
2194 } else if (nv[0] == "array_null_terminated") {
2195 if (eval (nv[1]) == "1") {
2196 p.no_array_length = true;
2197 p.array_null_terminated = true;
2199 } else if (nv[0] == "array_length_pos") {
2200 set_array_length_pos = true;
2201 array_length_pos = eval (nv[1]).to_double ();
2202 } else if (nv[0] == "delegate_target_pos") {
2203 set_delegate_target_pos = true;
2204 delegate_target_pos = eval (nv[1]).to_double ();
2205 } else if (nv[0] == "type_name") {
2206 p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
2207 } else if (nv[0] == "ctype") {
2208 p.ctype = eval (nv[1]);
2209 } else if (nv[0] == "type_arguments") {
2210 parse_type_arguments_from_string (param_type, eval (nv[1]));
2211 } else if (nv[0] == "default_value") {
2212 var val = eval (nv[1]);
2213 if (val == "null") {
2214 p.initializer = new NullLiteral (param_type.source_reference);
2215 } else if (val == "true") {
2216 p.initializer = new BooleanLiteral (true, param_type.source_reference);
2217 } else if (val == "false") {
2218 p.initializer = new BooleanLiteral (false, param_type.source_reference);
2219 } else if (val == "") {
2220 p.initializer = new StringLiteral ("\"\"", param_type.source_reference);
2221 } else {
2222 unowned string endptr;
2223 char* val_end = (char*) val + val.length;
2225 val.to_long (out endptr);
2226 if ((long)endptr == (long)val_end) {
2227 p.initializer = new IntegerLiteral (val, param_type.source_reference);
2228 } else {
2229 val.to_double (out endptr);
2230 if ((long)endptr == (long)val_end) {
2231 p.initializer = new RealLiteral (val, param_type.source_reference);
2232 } else {
2233 if (val.has_prefix ("\"") && val.has_suffix ("\"")) {
2234 p.initializer = new StringLiteral (val, param_type.source_reference);
2235 } else {
2236 foreach (var member in val.split (".")) {
2237 p.initializer = new MemberAccess (p.initializer, member, param_type.source_reference);
2247 if (last_param != null && p.name == "n_" + last_param.name) {
2248 if (!(last_param_type is ArrayType)) {
2249 // last_param is array, p is array length
2250 last_param_type = new ArrayType (last_param_type, 1, last_param_type.source_reference);
2251 last_param.variable_type = last_param_type;
2252 last_param.direction = ParameterDirection.IN;
2255 // hide array length param
2256 hide_param = true;
2257 } else if (last_param != null && p.name == "user_data") {
2258 // last_param is delegate
2260 // hide deleate target param
2261 hide_param = true;
2264 if (show_param || !hide_param) {
2265 m.add_parameter (p);
2266 if (set_array_length_pos) {
2267 p.carray_length_parameter_position = array_length_pos;
2269 if (set_delegate_target_pos) {
2270 p.cdelegate_target_parameter_position = delegate_target_pos;
2274 last_param = p;
2275 last_param_type = param_type;
2278 if (suppress_throws == false && error_types != null) {
2279 var type_args = eval (error_types).split (",");
2280 foreach (string type_arg in type_args) {
2281 m.add_error_type (parse_type_from_string (type_arg, true));
2285 if (first) {
2286 // no parameters => static method
2287 m.binding = MemberBinding.STATIC;
2290 if (last_param != null && last_param.name.has_prefix ("first_")) {
2291 last_param.ellipsis = true;
2292 } else if (add_ellipsis) {
2293 m.add_parameter (new Parameter.with_ellipsis ());
2296 return m;
2299 private bool param_is_exception (IdlNodeParam param) {
2300 if (!param.type.is_error) {
2301 return false;
2303 var s = param.type.unparsed.chomp ();
2304 if (s.has_suffix ("**")) {
2305 return true;
2307 return false;
2310 private Method? parse_function (IdlNodeFunction f, bool is_interface = false) {
2311 weak IdlNode node = (IdlNode) f;
2313 if (f.deprecated) {
2314 return null;
2317 return create_method (node.name, f.symbol, f.result, f.parameters, f.is_constructor, is_interface);
2320 private Method parse_virtual (IdlNodeVFunc v, IdlNodeFunction? func, bool is_interface = false) {
2321 weak IdlNode node = (IdlNode) v;
2322 string symbol = "%s%s".printf (current_data_type.get_lower_case_cprefix(), node.name);
2324 if (func != null) {
2325 symbol = func.symbol;
2328 Method m = create_method (node.name, symbol, v.result, func != null ? func.parameters : v.parameters, false, is_interface);
2329 if (m != null) {
2330 m.binding = MemberBinding.INSTANCE;
2331 m.is_virtual = !(m.is_abstract || is_interface);
2332 m.is_abstract = m.is_abstract || is_interface;
2334 var attributes = get_attributes (symbol);
2335 if (attributes != null) {
2336 foreach (string attr in attributes) {
2337 var nv = attr.split ("=", 2);
2338 if (nv[0] == "virtual") {
2339 if (eval (nv[1]) == "0") {
2340 m.is_virtual = false;
2341 m.is_abstract = false;
2342 } else {
2343 m.is_virtual = true;
2344 m.is_abstract = false;
2350 if (func == null) {
2351 m.attributes.append (new Attribute ("NoWrapper", null));
2355 return m;
2358 private string fix_prop_name (string name) {
2359 var str = new StringBuilder ();
2361 string i = name;
2363 while (i.length > 0) {
2364 unichar c = i.get_char ();
2365 if (c == '-') {
2366 str.append_c ('_');
2367 } else {
2368 str.append_unichar (c);
2371 i = i.next_char ();
2374 return str.str;
2377 private Property? parse_property (IdlNodeProperty prop_node) {
2378 weak IdlNode node = (IdlNode) prop_node;
2380 if (prop_node.deprecated) {
2381 return null;
2384 if (!prop_node.readable && !prop_node.writable) {
2385 // buggy GIDL definition
2386 prop_node.readable = true;
2387 prop_node.writable = true;
2390 var prop = new Property (fix_prop_name (node.name), parse_type (prop_node.type), null, null, current_source_reference);
2391 prop.access = SymbolAccessibility.PUBLIC;
2392 prop.interface_only = true;
2394 if (prop_node.type.is_interface && prop_node.type.interface == "GStrv") {
2395 prop.no_array_length = true;
2396 prop.array_null_terminated = true;
2399 if (prop_node.readable) {
2400 prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, null);
2402 if (prop_node.writable) {
2403 prop.set_accessor = new PropertyAccessor (false, false, false, prop.property_type.copy (), null, null);
2404 if (prop_node.construct_only) {
2405 prop.set_accessor.construction = true;
2406 } else {
2407 prop.set_accessor.writable = true;
2408 prop.set_accessor.construction = prop_node.@construct;
2412 var attributes = get_attributes ("%s:%s".printf (current_data_type.get_cname (), node.name));
2413 if (attributes != null) {
2414 foreach (string attr in attributes) {
2415 var nv = attr.split ("=", 2);
2416 if (nv[0] == "hidden") {
2417 if (eval (nv[1]) == "1") {
2418 return null;
2420 } else if (nv[0] == "type_arguments") {
2421 parse_type_arguments_from_string (prop.property_type, eval (nv[1]));
2422 } else if (nv[0] == "deprecated") {
2423 if (eval (nv[1]) == "1") {
2424 prop.deprecated = true;
2426 } else if (nv[0] == "replacement") {
2427 prop.replacement = eval (nv[1]);
2428 } else if (nv[0] == "deprecated_since") {
2429 prop.deprecated_since = eval (nv[1]);
2430 } else if (nv[0] == "accessor_method") {
2431 if (eval (nv[1]) == "0") {
2432 prop.no_accessor_method = true;
2434 } else if (nv[0] == "owned_get") {
2435 if (eval (nv[1]) == "1") {
2436 prop.get_accessor.value_type.value_owned = true;
2438 } else if (nv[0] == "type_name") {
2439 prop.property_type = parse_type_from_string (eval (nv[1]), false);
2444 if (current_type_symbol_set != null) {
2445 current_type_symbol_set.add (prop.name);
2448 return prop;
2451 private Constant? parse_constant (IdlNodeConstant const_node) {
2452 weak IdlNode node = (IdlNode) const_node;
2454 var type = parse_type (const_node.type);
2455 if (type == null) {
2456 return null;
2459 var c = new Constant (node.name, type, null, current_source_reference);
2460 c.external = true;
2462 string[] attributes = get_attributes (node.name);
2463 if (attributes != null) {
2464 foreach (string attr in attributes) {
2465 var nv = attr.split ("=", 2);
2466 if (nv[0] == "cheader_filename") {
2467 c.add_cheader_filename (eval (nv[1]));
2468 } else if (nv[0] == "deprecated") {
2469 if (eval (nv[1]) == "1") {
2470 c.deprecated = true;
2472 } else if (nv[0] == "replacement") {
2473 c.replacement = eval (nv[1]);
2474 } else if (nv[0] == "deprecated_since") {
2475 c.deprecated_since = eval (nv[1]);
2476 } else if (nv[0] == "hidden") {
2477 if (eval (nv[1]) == "1") {
2478 return null;
2484 c.access = SymbolAccessibility.PUBLIC;
2486 return c;
2489 private Field? parse_field (IdlNodeField field_node) {
2490 weak IdlNode node = (IdlNode) field_node;
2491 bool unhidden = false;
2493 var type = parse_type (field_node.type);
2494 if (type == null) {
2495 return null;
2498 string cheader_filename = null;
2499 string ctype = null;
2500 string array_length_cname = null;
2501 string array_length_type = null;
2502 bool array_null_terminated = false;
2503 bool deprecated = false;
2504 string deprecated_since = null;
2505 string replacement = null;
2507 var attributes = get_attributes ("%s.%s".printf (current_data_type.get_cname (), node.name));
2508 if (attributes != null) {
2509 foreach (string attr in attributes) {
2510 var nv = attr.split ("=", 2);
2511 if (nv[0] == "hidden") {
2512 if (eval (nv[1]) == "1") {
2513 return null;
2514 } else {
2515 unhidden = true;
2517 } else if (nv[0] == "is_array") {
2518 if (eval (nv[1]) == "1") {
2519 type = new ArrayType (type, 1, type.source_reference);
2521 } else if (nv[0] == "weak") {
2522 if (eval (nv[1]) == "0") {
2523 type.value_owned = true;
2525 } else if (nv[0] == "type_name") {
2526 type = parse_type_from_string (eval (nv[1]), true);
2527 } else if (nv[0] == "type_arguments") {
2528 parse_type_arguments_from_string (type, eval (nv[1]));
2529 } else if (nv[0] == "deprecated") {
2530 if (eval (nv[1]) == "1") {
2531 deprecated = true;
2533 } else if (nv[0] == "replacement") {
2534 replacement = eval (nv[1]);
2535 } else if (nv[0] == "deprecated_since") {
2536 deprecated_since = eval (nv[1]);
2537 } else if (nv[0] == "cheader_filename") {
2538 cheader_filename = eval (nv[1]);
2539 } else if (nv[0] == "ctype") {
2540 ctype = eval (nv[1]);
2541 } else if (nv[0] == "array_null_terminated") {
2542 if (eval (nv[1]) == "1") {
2543 array_null_terminated = true;
2545 } else if (nv[0] == "array_length_cname") {
2546 array_length_cname = eval (nv[1]);
2547 } else if (nv[0] == "array_length_type") {
2548 array_length_type = eval (nv[1]);
2553 if (node.name.has_prefix("_") && !unhidden) {
2554 return null;
2557 if (current_type_symbol_set != null) {
2558 current_type_symbol_set.add (node.name);
2561 string field_name = node.name;
2562 if (field_name == "string") {
2563 // avoid conflict with string type
2564 field_name = "str";
2567 var field = new Field (field_name, type, null, current_source_reference);
2568 field.access = SymbolAccessibility.PUBLIC;
2570 if (field_name != node.name) {
2571 field.set_cname (node.name);
2574 if (deprecated) {
2575 field.deprecated = true;
2577 if (deprecated_since != null) {
2578 field.deprecated_since = deprecated_since;
2581 if (replacement != null) {
2582 field.replacement = replacement;
2586 if (ctype != null) {
2587 field.set_ctype (ctype);
2590 if (cheader_filename != null) {
2591 field.add_cheader_filename (cheader_filename);
2594 if (array_null_terminated) {
2595 field.array_null_terminated = true;
2598 if (array_length_cname != null || array_length_type != null) {
2599 if (array_length_cname != null) {
2600 field.set_array_length_cname (array_length_cname);
2602 if (array_length_type != null) {
2603 field.array_length_type = array_length_type;
2605 } else {
2606 field.no_array_length = true;
2609 return field;
2612 private string[]? get_attributes (string codenode) {
2613 var attributes = codenode_attributes_map.get (codenode);
2615 if (attributes == null) {
2616 var dot_required = (-1 != codenode.index_of_char ('.'));
2617 var colon_required = (-1 != codenode.index_of_char (':'));
2619 var pattern_specs = codenode_attributes_patterns.get_keys ();
2620 foreach (PatternSpec* pattern in pattern_specs) {
2621 var pspec = codenode_attributes_patterns[pattern];
2623 if ((dot_required && -1 == pspec.index_of_char ('.')) ||
2624 (colon_required && -1 == pspec.index_of_char (':'))) {
2625 continue;
2628 if (pattern->match_string (codenode)) {
2629 return get_attributes (pspec);
2634 if (attributes == null) {
2635 return null;
2638 GLib.SList<string> attr_list = new GLib.SList<string> ();
2639 var attr = new GLib.StringBuilder.sized (attributes.length);
2640 var attributes_len = attributes.length;
2641 unowned string remaining = attributes;
2642 bool quoted = false, escaped = false;
2643 for (int b = 0 ; b < attributes_len ; b++) {
2644 unichar c = remaining.get_char ();
2646 if (escaped) {
2647 escaped = false;
2648 attr.append_unichar (c);
2649 } else {
2650 if (c == '"') {
2651 attr.append_unichar (c);
2652 quoted = !quoted;
2653 } else if (c == '\\') {
2654 escaped = true;
2655 } else if (!quoted && (c == ' ')) {
2656 attr_list.prepend (attr.str);
2657 attr.truncate (0);
2658 } else {
2659 attr.append_unichar (c);
2663 remaining = (string) ((char*) remaining + remaining.index_of_nth_char (1));
2666 if (attr.len > 0) {
2667 attr_list.prepend (attr.str);
2670 var attrs = new string[attr_list.length ()];
2671 unowned GLib.SList<string>? attr_i = attr_list;
2672 for (int a = 0 ; a < attrs.length ; a++, attr_i = attr_i.next) {
2673 attrs[(attrs.length - 1) - a] = attr_i.data;
2676 return attrs;
2679 private string eval (string s) {
2680 return ((s.length >= 2) && s.has_prefix ("\"") && s.has_suffix ("\"")) ? s.substring (1, s.length - 2) : s;
2683 private Signal? parse_signal (IdlNodeSignal sig_node) {
2684 weak IdlNode node = (IdlNode) sig_node;
2686 if (sig_node.deprecated || sig_node.result == null) {
2687 return null;
2690 var sig = new Signal (fix_prop_name (node.name), parse_param (sig_node.result), current_source_reference);
2691 sig.access = SymbolAccessibility.PUBLIC;
2693 var attributes = get_attributes ("%s::%s".printf (current_data_type.get_cname (), sig.name));
2694 if (attributes != null) {
2695 string ns_name = null;
2696 foreach (string attr in attributes) {
2697 var nv = attr.split ("=", 2);
2698 if (nv[0] == "name") {
2699 sig.set_cname (sig.name);
2700 sig.name = eval (nv[1]);
2701 } else if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
2702 sig.has_emitter = true;
2703 } else if (nv[0] == "hidden") {
2704 if (eval (nv[1]) == "1") {
2705 return null;
2707 } else if (nv[0] == "deprecated") {
2708 if (eval (nv[1]) == "1") {
2709 sig.deprecated = true;
2711 } else if (nv[0] == "replacement") {
2712 sig.replacement = eval (nv[1]);
2713 } else if (nv[0] == "deprecated_since") {
2714 sig.deprecated_since = eval (nv[1]);
2715 } else if (nv[0] == "transfer_ownership") {
2716 if (eval (nv[1]) == "1") {
2717 sig.return_type.value_owned = true;
2719 } else if (nv[0] == "namespace_name") {
2720 ns_name = eval (nv[1]);
2721 } else if (nv[0] == "type_name") {
2722 sig.return_type = parse_type_from_string (eval (nv[1]), false);
2723 } else if (nv[0] == "type_arguments") {
2724 parse_type_arguments_from_string (sig.return_type, eval (nv[1]));
2727 if (ns_name != null) {
2728 ((UnresolvedType) sig.return_type).unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
2732 sig.is_virtual = true;
2734 bool first = true;
2736 foreach (weak IdlNodeParam param in sig_node.parameters) {
2737 if (first) {
2738 // ignore implicit first signal parameter (sender)
2739 first = false;
2740 continue;
2743 weak IdlNode param_node = (IdlNode) param;
2745 ParameterDirection direction;
2746 var param_type = parse_param (param, out direction);
2747 var p = new Parameter (param_node.name, param_type);
2748 p.direction = direction;
2750 bool hide_param = false;
2751 bool show_param = false;
2752 attributes = get_attributes ("%s::%s.%s".printf (current_data_type.get_cname (), sig.name, param_node.name));
2753 if (attributes != null) {
2754 string ns_name = null;
2755 foreach (string attr in attributes) {
2756 var nv = attr.split ("=", 2);
2757 if (nv[0] == "hidden") {
2758 if (eval (nv[1]) == "1") {
2759 hide_param = true;
2760 } else if (eval (nv[1]) == "0") {
2761 show_param = true;
2763 } else if (nv[0] == "is_array") {
2764 if (eval (nv[1]) == "1") {
2765 param_type = new ArrayType (param_type, 1, param_type.source_reference);
2766 p.variable_type = param_type;
2767 p.direction = ParameterDirection.IN;
2769 } else if (nv[0] == "is_out") {
2770 if (eval (nv[1]) == "1") {
2771 p.direction = ParameterDirection.OUT;
2773 } else if (nv[0] == "is_ref") {
2774 if (eval (nv[1]) == "1") {
2775 p.direction = ParameterDirection.REF;
2777 } else if (nv[0] == "nullable") {
2778 if (eval (nv[1]) == "1") {
2779 param_type.nullable = true;
2781 } else if (nv[0] == "transfer_ownership") {
2782 if (eval (nv[1]) == "1") {
2783 param_type.value_owned = true;
2785 } else if (nv[0] == "type_name") {
2786 p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
2787 } else if (nv[0] == "type_arguments") {
2788 parse_type_arguments_from_string (p.variable_type, eval (nv[1]));
2789 } else if (nv[0] == "namespace_name") {
2790 ns_name = eval (nv[1]);
2793 if (ns_name != null) {
2794 ((UnresolvedType) param_type).unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
2798 if (show_param || !hide_param) {
2799 sig.add_parameter (p);
2803 return sig;
2807 // vim:sw=8 noet