manual: Update from wiki.gnome.org
[vala-gnome.git] / vapigen / valagidlparser.vala
blobbb3c4bb866582d4c6a54fbd7f8428cccf65df459
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 (get_cname (t))) {
92 cname_type_map[get_cname (t)] = 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>) 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 (unowned 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, SourceLocation (null, 0, 0), SourceLocation (null, 0, 0));
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 {
169 var cprefix = get_cprefix (container);
170 if (type_name.has_prefix (cprefix)) {
171 return type_name.substring (cprefix.length);;
175 return type_name;
178 private string fix_const_name (string const_name, Symbol container) {
179 var pref = get_lower_case_cprefix (container).ascii_up ();
180 if (const_name.has_prefix (pref)) {
181 return const_name.substring (pref.length);
183 return const_name;
186 private string get_cheader_filename (Symbol sym) {
187 var cheader_filename = sym.get_attribute_string ("CCode", "cheader_filename");
188 if (cheader_filename != null) {
189 return cheader_filename;
191 if (sym.parent_symbol != null) {
192 return get_cheader_filename (sym.parent_symbol);
193 } else if (sym.source_reference != null) {
194 return sym.source_reference.file.get_cinclude_filename ();
196 return "";
199 private string get_cname (Symbol sym, Symbol? container = null) {
200 if (container == null) {
201 container = sym.parent_symbol;
203 var cname = sym.get_attribute_string ("CCode", "cname");
204 if (cname != null) {
205 return cname;
207 if (sym is Method) {
208 var name = sym.name;
209 if (sym is CreationMethod) {
210 if (name == null || name == ".new") {
211 name = "new";
212 } else {
213 name = "new_%s".printf (name);
216 if (container != null) {
217 return "%s%s".printf (get_lower_case_cprefix (container), name);
218 } else {
219 return name;
221 } else {
222 if (container != null) {
223 return "%s%s".printf (get_cprefix (container), sym.name);
224 } else {
225 return sym.name;
230 private string get_finish_cname (Method m) {
231 var finish_cname = m.get_attribute_string ("CCode", "finish_name");
232 if (finish_cname != null) {
233 return finish_cname;
235 var result = get_cname (m);
236 if (result.has_suffix ("_async")) {
237 result = result.substring (0, result.length - "_async".length);
239 return result + "_finish";
242 private string get_lower_case_cname (Symbol sym) {
243 var lower_case_csuffix = Symbol.camel_case_to_lower_case (sym.name);
244 if (sym is ObjectTypeSymbol) {
245 // remove underscores in some cases to avoid conflicts of type macros
246 if (lower_case_csuffix.has_prefix ("type_")) {
247 lower_case_csuffix = "type" + lower_case_csuffix.substring ("type_".length);
248 } else if (lower_case_csuffix.has_prefix ("is_")) {
249 lower_case_csuffix = "is" + lower_case_csuffix.substring ("is_".length);
251 if (lower_case_csuffix.has_suffix ("_class")) {
252 lower_case_csuffix = lower_case_csuffix.substring (0, lower_case_csuffix.length - "_class".length) + "class";
255 if (sym.parent_symbol != null) {
256 return "%s%s".printf (get_lower_case_cprefix (sym.parent_symbol), lower_case_csuffix);
257 } else {
258 return lower_case_csuffix;
262 private string get_lower_case_cprefix (Symbol sym) {
263 if (sym.name == null) {
264 return "";
266 string cprefix;
267 cprefix = sym.get_attribute_string ("CCode", "lower_case_cprefix");
268 if (cprefix == null && (sym is ObjectTypeSymbol || sym is Struct)) {
269 cprefix = sym.get_attribute_string ("CCode", "cprefix");
271 if (cprefix != null) {
272 return cprefix;
274 return get_lower_case_cname (sym) + "_";
277 public string get_cprefix (Symbol sym) {
278 if (sym is ObjectTypeSymbol) {
279 return get_cname (sym);
280 } else if (sym is Enum || sym is ErrorDomain) {
281 return "%s_".printf (get_lower_case_cname (sym).ascii_up ());
282 } else if (sym is Namespace) {
283 if (sym.name != null) {
284 var cprefix = sym.get_attribute_string ("CCode", "cprefix");
285 if (cprefix != null) {
286 return cprefix;
288 if (sym.parent_symbol != null) {
289 return "%s%s".printf (get_cprefix (sym.parent_symbol), sym.name);
290 } else {
291 return sym.name;
293 } else {
294 return "";
296 } else if (sym.name != null) {
297 return sym.name;
299 return "";
302 private string[] get_attributes_for_node (IdlNode node) {
303 string name;
305 if (node.type == IdlNodeTypeId.FUNCTION) {
306 name = ((IdlNodeFunction) node).symbol;
307 } else if (node.type == IdlNodeTypeId.SIGNAL) {
308 name = "%s::%s".printf (get_cname (current_data_type), node.name);
309 } else if (node.type == IdlNodeTypeId.PROPERTY) {
310 name = "%s:%s".printf (get_cname (current_data_type), node.name);
311 } else if (node.type == IdlNodeTypeId.FIELD) {
312 name = "%s.%s".printf (get_cname (current_data_type), node.name);
313 } else {
314 name = node.name;
317 return get_attributes (name);
320 private void add_symbol_to_container (Symbol container, Symbol sym) {
321 if (container is Class) {
322 unowned Class cl = (Class) container;
324 if (sym is Class) {
325 cl.add_class ((Class) sym);
326 } else if (sym is Constant) {
327 cl.add_constant ((Constant) sym);
328 } else if (sym is Enum) {
329 cl.add_enum ((Enum) sym);
330 } else if (sym is Field) {
331 cl.add_field ((Field) sym);
332 } else if (sym is Method) {
333 cl.add_method ((Method) sym);
334 } else if (sym is Property) {
335 cl.add_property ((Property) sym);
336 } else if (sym is Signal) {
337 cl.add_signal ((Signal) sym);
338 } else if (sym is Struct) {
339 cl.add_struct ((Struct) sym);
341 } else if (container is Enum) {
342 unowned Enum en = (Enum) container;
344 if (sym is EnumValue) {
345 en.add_value ((EnumValue) sym);
346 } else if (sym is Constant) {
347 en.add_constant ((Constant) sym);
348 } else if (sym is Method) {
349 en.add_method ((Method) sym);
351 } else if (container is Interface) {
352 unowned Interface iface = (Interface) container;
354 if (sym is Class) {
355 iface.add_class ((Class) sym);
356 } else if (sym is Constant) {
357 iface.add_constant ((Constant) sym);
358 } else if (sym is Enum) {
359 iface.add_enum ((Enum) sym);
360 } else if (sym is Field) {
361 iface.add_field ((Field) sym);
362 } else if (sym is Method) {
363 iface.add_method ((Method) sym);
364 } else if (sym is Property) {
365 iface.add_property ((Property) sym);
366 } else if (sym is Signal) {
367 iface.add_signal ((Signal) sym);
368 } else if (sym is Struct) {
369 iface.add_struct ((Struct) sym);
371 } else if (container is Namespace) {
372 unowned Namespace ns = (Namespace) container;
374 if (sym is Namespace) {
375 ns.add_namespace ((Namespace) sym);
376 } else if (sym is Class) {
377 ns.add_class ((Class) sym);
378 } else if (sym is Constant) {
379 ns.add_constant ((Constant) sym);
380 } else if (sym is Delegate) {
381 ns.add_delegate ((Delegate) sym);
382 } else if (sym is Enum) {
383 ns.add_enum ((Enum) sym);
384 } else if (sym is ErrorDomain) {
385 ns.add_error_domain ((ErrorDomain) sym);
386 } else if (sym is Field) {
387 ns.add_field ((Field) sym);
388 } else if (sym is Interface) {
389 ns.add_interface ((Interface) sym);
390 } else if (sym is Method) {
391 ns.add_method ((Method) sym);
392 } else if (sym is Namespace) {
393 ns.add_namespace ((Namespace) sym);
394 } else if (sym is Struct) {
395 ns.add_struct ((Struct) sym);
397 } else if (container is Struct) {
398 unowned Struct st = (Struct) container;
400 if (sym is Constant) {
401 st.add_constant ((Constant) sym);
402 } else if (sym is Field) {
403 st.add_field ((Field) sym);
404 } else if (sym is Method) {
405 st.add_method ((Method) sym);
406 } else if (sym is Property) {
407 st.add_property ((Property) sym);
411 if (!(sym is Namespace) && container is Namespace) {
412 // set C headers
413 sym.set_attribute_string ("CCode", "cheader_filename", get_cheader_filename (sym));
417 private void parse_node (IdlNode node, IdlModule module, Symbol container) {
418 if (node.type == IdlNodeTypeId.CALLBACK) {
419 var cb = parse_delegate ((IdlNodeFunction) node);
420 if (cb == null) {
421 return;
423 cb.name = fix_type_name (cb.name, container);
424 add_symbol_to_container (container, cb);
425 current_source_file.add_node (cb);
426 } else if (node.type == IdlNodeTypeId.STRUCT) {
427 parse_struct ((IdlNodeStruct) node, container, module);
428 } else if (node.type == IdlNodeTypeId.UNION) {
429 parse_union ((IdlNodeUnion) node, container, module);
430 } else if (node.type == IdlNodeTypeId.BOXED) {
431 parse_boxed ((IdlNodeBoxed) node, container, module);
432 } else if (node.type == IdlNodeTypeId.ENUM) {
433 parse_enum ((IdlNodeEnum) node, container, module, false);
434 } else if (node.type == IdlNodeTypeId.FLAGS) {
435 parse_enum ((IdlNodeEnum) node, container, module, true);
436 } else if (node.type == IdlNodeTypeId.OBJECT) {
437 parse_object ((IdlNodeInterface) node, container, module);
438 } else if (node.type == IdlNodeTypeId.INTERFACE) {
439 parse_interface ((IdlNodeInterface) node, container, module);
440 } else if (node.type == IdlNodeTypeId.CONSTANT) {
441 var c = parse_constant ((IdlNodeConstant) node);
442 if (c != null) {
443 c.name = fix_const_name (c.name, container);
444 add_symbol_to_container (container, c);
445 current_source_file.add_node (c);
447 } else if (node.type == IdlNodeTypeId.FUNCTION) {
448 var m = parse_function ((IdlNodeFunction) node);
449 if (m != null) {
450 m.binding = MemberBinding.STATIC;
451 add_symbol_to_container (container, m);
452 current_source_file.add_node (m);
457 private Symbol? get_container_from_name (string name) {
458 var path = name.split (".");
459 Symbol? cp = current_namespace;
460 if (cp.parent_symbol != context.root) {
461 cp = cp.parent_symbol;
463 Symbol? cc = null;
465 foreach ( unowned string tok in path ) {
466 cc = cp.scope.lookup (tok) as Symbol;
467 if ( cc == null ) {
468 cc = new Namespace (tok, current_source_reference);
469 add_symbol_to_container (cp, cc);
471 cp = cc;
474 return cc;
477 private Namespace? parse_module (IdlModule module) {
478 Symbol sym = context.root.scope.lookup (module.name);
479 Namespace ns;
480 if (sym is Namespace) {
481 ns = (Namespace) sym;
482 if (ns.external_package) {
483 ns.attributes = null;
484 ns.source_reference = current_source_reference;
486 } else {
487 ns = new Namespace (module.name, current_source_reference);
490 current_namespace = ns;
492 var attributes = get_attributes (ns.name);
493 if (attributes != null) {
494 foreach (string attr in attributes) {
495 var nv = attr.split ("=", 2);
496 if (nv[0] == "cheader_filename") {
497 ns.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
498 } else if (nv[0] == "cprefix") {
499 ns.set_attribute_string ("CCode", "cprefix", eval (nv[1]));
500 } else if (nv[0] == "lower_case_cprefix") {
501 ns.set_attribute_string ("CCode", "lower_case_cprefix", eval (nv[1]));
502 } else if (nv[0] == "gir_namespace") {
503 ns.source_reference.file.gir_namespace = eval (nv[1]);
504 ns.set_attribute_string ("CCode", "gir_namespace", eval (nv[1]));
505 } else if (nv[0] == "gir_version") {
506 ns.source_reference.file.gir_version = eval (nv[1]);
507 ns.set_attribute_string ("CCode", "gir_version", eval (nv[1]));
508 } else if (nv[0] == "deprecated") {
509 if (eval (nv[1]) == "1") {
510 ns.set_attribute_bool ("Version", "deprecated", true);
512 } else if (nv[0] == "replacement") {
513 ns.set_attribute_string ("Version", "replacement", eval (nv[1]));
514 } else if (nv[0] == "deprecated_since") {
515 ns.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
520 var deferred = new ArrayList<unowned IdlNode> ();
522 foreach (weak IdlNode node in module.entries) {
523 bool is_deferred = false;
524 var child_attributes = get_attributes_for_node (node);
525 if (child_attributes != null) {
526 foreach (unowned string attr in child_attributes) {
527 var nv = attr.split ("=", 2);
528 if (nv[0] == "parent") {
529 deferred.add (node);
530 is_deferred = true;
535 if (!is_deferred) {
536 parse_node (node, module, ns);
540 foreach (unowned IdlNode node in deferred) {
541 Symbol container = ns;
542 var child_attributes = get_attributes_for_node (node);
543 if (child_attributes != null) {
544 foreach (unowned string attr in child_attributes) {
545 var nv = attr.split ("=", 2);
546 if (nv[0] == "parent") {
547 container = get_container_from_name (eval (nv[1]));
552 if (container is Namespace) {
553 current_namespace = (Namespace) container;
554 } else {
555 current_data_type = (TypeSymbol) container;
557 parse_node (node, module, container);
558 current_namespace = ns;
559 current_data_type = null;
562 current_namespace = null;
564 if (sym is Namespace) {
565 return null;
567 return ns;
570 private Delegate? parse_delegate (IdlNodeFunction f_node) {
571 weak IdlNode node = (IdlNode) f_node;
573 var return_type = parse_param (f_node.result);
575 var cb = new Delegate (node.name, return_type, current_source_reference);
576 cb.access = SymbolAccessibility.PUBLIC;
577 cb.has_target = false;
579 bool check_has_target = true;
580 bool suppress_throws = false;
581 string? error_types = null;
583 var attributes = get_attributes (node.name);
584 if (attributes != null) {
585 foreach (string attr in attributes) {
586 var nv = attr.split ("=", 2);
587 if (nv[0] == "hidden") {
588 if (eval (nv[1]) == "1") {
589 return null;
591 } else if (nv[0] == "cheader_filename") {
592 cb.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
593 } else if (nv[0] == "has_target") {
594 if (eval (nv[1]) == "0") {
595 check_has_target = false;
596 } else if (eval (nv[1]) == "1") {
597 cb.has_target = true;
599 } else if (nv[0] == "transfer_ownership") {
600 if (eval (nv[1]) == "1") {
601 return_type.value_owned = true;
603 } else if (nv[0] == "is_array") {
604 if (eval (nv[1]) == "1") {
605 return_type.value_owned = true;
606 return_type = new ArrayType (return_type, 1, return_type.source_reference);
607 cb.return_type = return_type;
609 } else if (nv[0] == "throws") {
610 if (eval (nv[1]) == "0") {
611 suppress_throws = true;
613 } else if (nv[0] == "error_types") {
614 error_types = eval (nv[1]);
615 } else if (nv[0] == "array_length_type") {
616 cb.set_attribute_string ("CCode", "array_length_type", eval (nv[1]));
617 } else if (nv[0] == "type_name") {
618 cb.return_type = return_type = parse_type_from_string (eval (nv[1]), return_type.value_owned);
619 } else if (nv[0] == "deprecated") {
620 if (eval (nv[1]) == "1") {
621 cb.set_attribute_bool ("Version", "deprecated", true);
623 } else if (nv[0] == "replacement") {
624 cb.set_attribute_string ("Version", "replacement", eval (nv[1]));
625 } else if (nv[0] == "deprecated_since") {
626 cb.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
627 } else if (nv[0] == "type_arguments") {
628 parse_type_arguments_from_string (return_type, eval (nv[1]));
629 } else if (nv[0] == "instance_pos") {
630 cb.set_attribute_double ("CCode", "instance_pos", double.parse (eval (nv[1])));
631 } else if (nv[0] == "type_parameters") {
632 foreach (string type_param_name in eval (nv[1]).split (",")) {
633 cb.add_type_parameter (new TypeParameter (type_param_name, current_source_reference));
635 } else if (nv[0] == "experimental") {
636 if (eval (nv[1]) == "1") {
637 cb.set_attribute_bool ("Version", "experimental", true);
643 uint remaining_params = f_node.parameters.length ();
644 foreach (weak IdlNodeParam param in f_node.parameters) {
645 weak IdlNode param_node = (IdlNode) param;
647 if (check_has_target && remaining_params == 1 && (param_node.name == "user_data" || param_node.name == "data")) {
648 // hide user_data parameter for instance delegates
649 cb.has_target = true;
650 } else {
651 // check for GError parameter
652 if (suppress_throws == false && param_is_exception (param)) {
653 if (error_types == null)
654 cb.add_error_type (parse_type (param.type));
655 remaining_params--;
656 continue;
659 string param_name = param_node.name;
660 if (param_name == "string") {
661 // avoid conflict with string type
662 param_name = "str";
663 } else if (param_name == "self") {
664 // avoid conflict with delegate target
665 param_name = "_self";
668 ParameterDirection direction;
669 var param_type = parse_param (param, out direction);
670 var p = new Parameter (param_name, param_type);
671 p.direction = direction;
673 bool hide_param = false;
674 bool show_param = false;
675 bool array_requested = false;
676 bool out_requested = false;
677 attributes = get_attributes ("%s.%s".printf (node.name, param_node.name));
678 if (attributes != null) {
679 foreach (string attr in attributes) {
680 var nv = attr.split ("=", 2);
681 if (nv[0] == "hidden") {
682 if (eval (nv[1]) == "1") {
683 hide_param = true;
684 } else if (eval (nv[1]) == "0") {
685 show_param = true;
687 } else if (nv[0] == "is_array") {
688 if (eval (nv[1]) == "1") {
689 param_type.value_owned = true;
690 param_type = new ArrayType (param_type, 1, param_type.source_reference);
691 p.variable_type = param_type;
692 if (!out_requested) {
693 p.direction = ParameterDirection.IN;
695 array_requested = true;
697 } else if (nv[0] == "is_out") {
698 if (eval (nv[1]) == "1") {
699 p.direction = ParameterDirection.OUT;
700 out_requested = true;
701 if (!array_requested && param_type is ArrayType) {
702 var array_type = (ArrayType) param_type;
703 param_type = array_type.element_type;
704 p.variable_type = param_type;
707 } else if (nv[0] == "is_ref") {
708 if (eval (nv[1]) == "1") {
709 p.direction = ParameterDirection.REF;
710 if (!array_requested && param_type is ArrayType) {
711 var array_type = (ArrayType) param_type;
712 param_type = array_type.element_type;
713 p.variable_type = param_type;
716 } else if (nv[0] == "takes_ownership") {
717 if (eval (nv[1]) == "1") {
718 param_type.value_owned = true;
720 } else if (nv[0] == "nullable") {
721 if (eval (nv[1]) == "1") {
722 param_type.nullable = true;
724 } else if (nv[0] == "type_arguments") {
725 parse_type_arguments_from_string (param_type, eval (nv[1]));
726 } else if (nv[0] == "no_array_length") {
727 if (eval (nv[1]) == "1") {
728 p.set_attribute_bool ("CCode", "array_length", false);
730 } else if (nv[0] == "array_length_type") {
731 p.set_attribute_string ("CCode", "array_length_type", eval (nv[1]));
732 } else if (nv[0] == "array_null_terminated") {
733 if (eval (nv[1]) == "1") {
734 p.set_attribute_bool ("CCode", "array_length", false);
735 p.set_attribute_bool ("CCode", "array_null_terminated", true);
737 } else if (nv[0] == "type_name") {
738 p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
743 if (show_param || !hide_param) {
744 cb.add_parameter (p);
748 remaining_params--;
751 if (suppress_throws == false && error_types != null) {
752 var type_args = eval (error_types).split (",");
753 foreach (unowned string type_arg in type_args) {
754 cb.add_error_type (parse_type_from_string (type_arg, true));
758 return cb;
761 private bool is_reference_type (string cname) {
762 var st_attributes = get_attributes (cname);
763 if (st_attributes != null) {
764 foreach (string attr in st_attributes) {
765 var nv = attr.split ("=", 2);
766 if (nv[0] == "is_value_type" && eval (nv[1]) == "1") {
767 return false;
771 return true;
774 private void parse_struct (IdlNodeStruct st_node, Symbol container, IdlModule module) {
775 weak IdlNode node = (IdlNode) st_node;
777 if (st_node.deprecated) {
778 return;
781 string name = fix_type_name (node.name, container);
783 if (!is_reference_type (node.name)) {
784 var st = container.scope.lookup (name) as Struct;
785 if (st == null) {
786 st = new Struct (name, current_source_reference);
787 st.access = SymbolAccessibility.PUBLIC;
789 var st_attributes = get_attributes (node.name);
790 if (st_attributes != null) {
791 foreach (string attr in st_attributes) {
792 var nv = attr.split ("=", 2);
793 if (nv[0] == "cheader_filename") {
794 st.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
795 } else if (nv[0] == "hidden") {
796 if (eval (nv[1]) == "1") {
797 return;
799 } else if (nv[0] == "base_type") {
800 st.base_type = parse_type_string (eval (nv[1]));
801 } else if (nv[0] == "rank") {
802 st.set_rank (int.parse (eval (nv[1])));
803 } else if (nv[0] == "simple_type") {
804 if (eval (nv[1]) == "1") {
805 st.set_simple_type (true);
807 } else if (nv[0] == "immutable") {
808 if (eval (nv[1]) == "1") {
809 st.set_attribute ("Immutable", true);
811 } else if (nv[0] == "has_type_id") {
812 if (eval (nv[1]) == "0") {
813 st.set_attribute_bool ("CCode", "has_type_id", false);
815 } else if (nv[0] == "type_id") {
816 st.set_attribute_string ("CCode", "type_id", eval (nv[1]));
817 } else if (nv[0] == "has_copy_function") {
818 if (eval (nv[1]) == "0") {
819 st.set_attribute_bool ("CCode", "has_copy_function", false);
821 } else if (nv[0] == "deprecated") {
822 if (eval (nv[1]) == "1") {
823 st.set_attribute_bool ("Version", "deprecated", true);
825 } else if (nv[0] == "replacement") {
826 st.set_attribute_string ("Version", "replacement", eval (nv[1]));
827 } else if (nv[0] == "deprecated_since") {
828 st.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
829 } else if (nv[0] == "has_destroy_function") {
830 if (eval (nv[1]) == "0") {
831 st.set_attribute_bool ("CCode", "has_destroy_function", false);
833 } else if (nv[0] == "experimental") {
834 if (eval (nv[1]) == "1") {
835 st.set_attribute_bool ("Version", "experimental", true);
841 add_symbol_to_container (container, st);
842 current_source_file.add_node (st);
845 current_data_type = st;
847 foreach (weak IdlNode member in st_node.members) {
848 if (member.type == IdlNodeTypeId.FUNCTION) {
849 var m = parse_function ((IdlNodeFunction) member);
850 if (m != null) {
851 st.add_method (m);
853 } else if (member.type == IdlNodeTypeId.FIELD) {
854 var f = parse_field ((IdlNodeField) member);
855 if (f != null) {
856 st.add_field (f);
861 current_data_type = null;
862 } else {
863 bool ref_function_void = false;
864 string ref_function = null;
865 string unref_function = null;
866 string copy_function = null;
867 string free_function = null;
869 var cl = container.scope.lookup (name) as Class;
870 if (cl == null) {
871 string base_class = null;
872 bool is_fundamental = false;
874 cl = new Class (name, current_source_reference);
875 cl.access = SymbolAccessibility.PUBLIC;
877 var cl_attributes = get_attributes (node.name);
878 if (cl_attributes != null) {
879 foreach (string attr in cl_attributes) {
880 var nv = attr.split ("=", 2);
881 if (nv[0] == "cheader_filename") {
882 cl.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
883 } else if (nv[0] == "base_class") {
884 base_class = eval (nv[1]);
885 } else if (nv[0] == "hidden") {
886 if (eval (nv[1]) == "1") {
887 return;
889 } else if (nv[0] == "is_immutable") {
890 if (eval (nv[1]) == "1") {
891 cl.is_immutable = true;
893 } else if (nv[0] == "const_cname") {
894 cl.set_attribute_string ("CCode", "const_cname", eval (nv[1]));
895 } else if (nv[0] == "is_fundamental") {
896 if (eval (nv[1]) == "1") {
897 is_fundamental = true;
899 } else if (nv[0] == "abstract" && base_class != null) {
900 if (eval (nv[1]) == "1") {
901 cl.is_abstract = true;
903 } else if (nv[0] == "free_function") {
904 free_function = eval (nv[1]);
905 } else if (nv[0] == "ref_function") {
906 ref_function = eval (nv[1]);
907 } else if (nv[0] == "unref_function") {
908 unref_function = eval (nv[1]);
909 } else if (nv[0] == "copy_function") {
910 copy_function = eval (nv[1]);
911 } else if (nv[0] == "ref_function_void") {
912 if (eval (nv[1]) == "1") {
913 ref_function_void = true;
915 } else if (nv[0] == "deprecated") {
916 if (eval (nv[1]) == "1") {
917 cl.set_attribute_bool ("Version", "deprecated", true);
919 } else if (nv[0] == "replacement") {
920 cl.set_attribute_string ("Version", "replacement", eval (nv[1]));
921 } else if (nv[0] == "deprecated_since") {
922 cl.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
923 } else if (nv[0] == "type_parameters") {
924 foreach (unowned string type_param_name in eval (nv[1]).split (",")) {
925 cl.add_type_parameter (new TypeParameter (type_param_name, current_source_reference));
927 } else if (nv[0] == "experimental") {
928 if (eval (nv[1]) == "1") {
929 cl.set_attribute_bool ("Version", "experimental", true);
931 } else if (nv[0] == "delegate_target_cname") {
932 cl.set_attribute_string ("CCode", "delegate_target_cname", eval (nv[1]));
937 add_symbol_to_container (container, cl);
938 current_source_file.add_node (cl);
940 if (base_class != null) {
941 var parent = parse_type_string (base_class);
942 cl.add_base_type (parent);
944 if (base_class == null && !is_fundamental) {
945 cl.is_compact = true;
949 current_data_type = cl;
951 foreach (weak IdlNode member in st_node.members) {
952 if (member.type == IdlNodeTypeId.FUNCTION) {
953 if ((ref_function == null) && (member.name == "ref")) {
954 ref_function = ((IdlNodeFunction) member).symbol;
955 ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
956 } else if ((unref_function == null) && (member.name == "unref")) {
957 unref_function = ((IdlNodeFunction) member).symbol;
958 } else if ((free_function == null) && (member.name == "free" || member.name == "destroy")) {
959 free_function = ((IdlNodeFunction) member).symbol;
960 } else {
961 if ((copy_function == null) && (member.name == "copy")) {
962 copy_function = ((IdlNodeFunction) member).symbol;
964 var m = parse_function ((IdlNodeFunction) member);
965 if (m != null) {
966 cl.add_method (m);
969 } else if (member.type == IdlNodeTypeId.FIELD) {
970 var f = parse_field ((IdlNodeField) member);
971 if (f != null) {
972 cl.add_field (f);
977 if (ref_function != null) {
978 cl.set_attribute_string ("CCode", "ref_function", ref_function);
979 if (ref_function_void) {
980 cl.set_attribute_bool ("CCode", "ref_function_void", ref_function_void);
982 } else if (copy_function != null) {
983 cl.set_attribute_string ("CCode", "copy_function", copy_function);
985 if (unref_function != null) {
986 cl.set_attribute_string ("CCode", "unref_function", unref_function);
987 } else if (free_function != null && free_function != "%sfree".printf (get_lower_case_cprefix (cl))) {
988 cl.set_attribute_string ("CCode", "free_function", free_function);
991 current_data_type = null;
995 private void parse_union (IdlNodeUnion un_node, Symbol container, IdlModule module) {
996 weak IdlNode node = (IdlNode) un_node;
998 if (un_node.deprecated) {
999 return;
1002 string name = fix_type_name (node.name, container);
1004 if (!is_reference_type (node.name)) {
1005 var st = container.scope.lookup (name) as Struct;
1006 if (st == null) {
1007 st = new Struct (name, current_source_reference);
1008 st.access = SymbolAccessibility.PUBLIC;
1010 var st_attributes = get_attributes (node.name);
1011 if (st_attributes != null) {
1012 foreach (string attr in st_attributes) {
1013 var nv = attr.split ("=", 2);
1014 if (nv[0] == "cheader_filename") {
1015 st.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
1016 } else if (nv[0] == "deprecated") {
1017 if (eval (nv[1]) == "1") {
1018 st.set_attribute_bool ("Version", "deprecated", true);
1020 } else if (nv[0] == "replacement") {
1021 st.set_attribute_string ("Version", "replacement", eval (nv[1]));
1022 } else if (nv[0] == "deprecated_since") {
1023 st.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
1024 } else if (nv[0] == "hidden") {
1025 if (eval (nv[1]) == "1") {
1026 return;
1028 } else if (nv[0] == "experimental") {
1029 if (eval (nv[1]) == "1") {
1030 st.set_attribute_bool ("Version", "experimental", true);
1036 add_symbol_to_container (container, st);
1037 current_source_file.add_node (st);
1040 current_data_type = st;
1042 foreach (weak IdlNode member in un_node.members) {
1043 if (member.type == IdlNodeTypeId.FUNCTION) {
1044 var m = parse_function ((IdlNodeFunction) member);
1045 if (m != null) {
1046 st.add_method (m);
1048 } else if (member.type == IdlNodeTypeId.FIELD) {
1049 var f = parse_field ((IdlNodeField) member);
1050 if (f != null) {
1051 st.add_field (f);
1056 current_data_type = null;
1057 } else {
1058 var cl = container.scope.lookup (name) as Class;
1059 if (cl == null) {
1060 cl = new Class (name, current_source_reference);
1061 cl.access = SymbolAccessibility.PUBLIC;
1062 cl.is_compact = true;
1064 var cl_attributes = get_attributes (node.name);
1065 if (cl_attributes != null) {
1066 foreach (string attr in cl_attributes) {
1067 var nv = attr.split ("=", 2);
1068 if (nv[0] == "cheader_filename") {
1069 cl.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
1070 } else if (nv[0] == "hidden") {
1071 if (eval (nv[1]) == "1") {
1072 return;
1078 add_symbol_to_container (container, cl);
1079 current_source_file.add_node (cl);
1082 current_data_type = cl;
1084 bool ref_function_void = false;
1085 string ref_function = null;
1086 string unref_function = null;
1087 string copy_function = null;
1088 string free_function = null;
1090 foreach (weak IdlNode member in un_node.members) {
1091 if (member.type == IdlNodeTypeId.FUNCTION) {
1092 if (member.name == "ref") {
1093 ref_function = ((IdlNodeFunction) member).symbol;
1094 ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
1095 } else if (member.name == "unref") {
1096 unref_function = ((IdlNodeFunction) member).symbol;
1097 } else if (member.name == "free" || member.name == "destroy") {
1098 free_function = ((IdlNodeFunction) member).symbol;
1099 } else {
1100 if (member.name == "copy") {
1101 copy_function = ((IdlNodeFunction) member).symbol;
1103 var m = parse_function ((IdlNodeFunction) member);
1104 if (m != null) {
1105 cl.add_method (m);
1108 } else if (member.type == IdlNodeTypeId.FIELD) {
1109 var f = parse_field ((IdlNodeField) member);
1110 if (f != null) {
1111 cl.add_field (f);
1116 if (ref_function != null) {
1117 cl.set_attribute_string ("CCode", "ref_function", ref_function);
1118 if (ref_function_void) {
1119 cl.set_attribute_bool ("CCode", "ref_function_void", ref_function_void);
1121 } else if (copy_function != null) {
1122 cl.set_attribute_string ("CCode", "copy_function", copy_function);
1124 if (unref_function != null) {
1125 cl.set_attribute_string ("CCode", "unref_function", unref_function);
1126 } else if (free_function != null && free_function != "%sfree".printf (get_lower_case_cprefix (cl))) {
1127 cl.set_attribute_string ("CCode", "free_function", free_function);
1130 current_data_type = null;
1134 private void parse_boxed (IdlNodeBoxed boxed_node, Symbol container, IdlModule module) {
1135 weak IdlNode node = (IdlNode) boxed_node;
1137 string name = fix_type_name (node.name, container);
1139 var node_attributes = get_attributes (node.name);
1140 if (node_attributes != null) {
1141 foreach (string attr in node_attributes) {
1142 var nv = attr.split ("=", 2);
1143 if (nv[0] == "hidden") {
1144 return;
1149 if (!is_reference_type (node.name)) {
1150 var st = container.scope.lookup (name) as Struct;
1151 if (st == null) {
1152 st = new Struct (name, current_source_reference);
1153 st.access = SymbolAccessibility.PUBLIC;
1155 var st_attributes = get_attributes (node.name);
1156 if (st_attributes != null) {
1157 foreach (string attr in st_attributes) {
1158 var nv = attr.split ("=", 2);
1159 if (nv[0] == "cheader_filename") {
1160 st.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
1161 } else if (nv[0] == "deprecated") {
1162 if (eval (nv[1]) == "1") {
1163 st.set_attribute_bool ("Version", "deprecated", true);
1165 } else if (nv[0] == "replacement") {
1166 st.set_attribute_string ("Version", "replacement", eval (nv[1]));
1167 } else if (nv[0] == "deprecated_since") {
1168 st.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
1169 } else if (nv[0] == "immutable") {
1170 if (eval (nv[1]) == "1") {
1171 st.set_attribute ("Immutable", true);
1173 } else if (nv[0] == "has_copy_function") {
1174 if (eval (nv[1]) == "0") {
1175 st.set_attribute_bool ("CCode", "has_copy_function", false);
1177 } else if (nv[0] == "has_destroy_function") {
1178 if (eval (nv[1]) == "0") {
1179 st.set_attribute_bool ("CCode", "has_destroy_function", false);
1181 } else if (nv[0] == "experimental") {
1182 if (eval (nv[1]) == "1") {
1183 st.set_attribute_bool ("Version", "experimental", true);
1189 add_symbol_to_container (container, st);
1190 current_source_file.add_node (st);
1193 current_data_type = st;
1195 foreach (weak IdlNode member in boxed_node.members) {
1196 if (member.type == IdlNodeTypeId.FUNCTION) {
1197 var m = parse_function ((IdlNodeFunction) member);
1198 if (m != null) {
1199 st.add_method (m);
1201 } else if (member.type == IdlNodeTypeId.FIELD) {
1202 var f = parse_field ((IdlNodeField) member);
1203 if (f != null) {
1204 st.add_field (f);
1209 current_data_type = null;
1210 } else {
1211 bool ref_function_void = false;
1212 string ref_function = null;
1213 string unref_function = null;
1214 string copy_function = null;
1215 string free_function = null;
1217 var cl = container.scope.lookup (name) as Class;
1218 if (cl == null) {
1219 string base_class = null;
1221 cl = new Class (name, current_source_reference);
1222 cl.access = SymbolAccessibility.PUBLIC;
1223 cl.is_compact = true;
1224 if (boxed_node.gtype_init != null) {
1225 cl.set_attribute_string ("CCode", "type_id", "%s ()".printf (boxed_node.gtype_init));
1228 var cl_attributes = get_attributes (node.name);
1229 if (cl_attributes != null) {
1230 foreach (string attr in cl_attributes) {
1231 var nv = attr.split ("=", 2);
1232 if (nv[0] == "cheader_filename") {
1233 cl.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
1234 } else if (nv[0] == "base_class") {
1235 base_class = eval (nv[1]);
1236 } else if (nv[0] == "is_immutable") {
1237 if (eval (nv[1]) == "1") {
1238 cl.is_immutable = true;
1240 } else if (nv[0] == "deprecated") {
1241 if (eval (nv[1]) == "1") {
1242 cl.set_attribute_bool ("Version", "deprecated", true);
1244 } else if (nv[0] == "replacement") {
1245 cl.set_attribute_string ("Version", "replacement", eval (nv[1]));
1246 } else if (nv[0] == "deprecated_since") {
1247 cl.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
1248 } else if (nv[0] == "const_cname") {
1249 cl.set_attribute_string ("CCode", "const_cname", eval (nv[1]));
1250 } else if (nv[0] == "free_function") {
1251 free_function = eval (nv[1]);
1252 } else if (nv[0] == "ref_function") {
1253 ref_function = eval (nv[1]);
1254 } else if (nv[0] == "unref_function") {
1255 unref_function = eval (nv[1]);
1256 } else if (nv[0] == "copy_function") {
1257 copy_function = eval (nv[1]);
1258 } else if (nv[0] == "ref_function_void") {
1259 if (eval (nv[1]) == "1") {
1260 ref_function_void = true;
1262 } else if (nv[0] == "experimental") {
1263 if (eval (nv[1]) == "1") {
1264 cl.set_attribute_bool ("Version", "experimental", true);
1270 add_symbol_to_container (container, cl);
1271 current_source_file.add_node (cl);
1273 if (base_class != null) {
1274 var parent = parse_type_string (base_class);
1275 cl.add_base_type (parent);
1279 current_data_type = cl;
1281 foreach (weak IdlNode member in boxed_node.members) {
1282 if (member.type == IdlNodeTypeId.FUNCTION) {
1283 if (member.name == "ref") {
1284 ref_function = ((IdlNodeFunction) member).symbol;
1285 ref_function_void = (parse_type (((IdlNodeFunction) member).result.type) is VoidType);
1286 } else if (member.name == "unref") {
1287 unref_function = ((IdlNodeFunction) member).symbol;
1288 } else if (member.name == "free" || member.name == "destroy") {
1289 free_function = ((IdlNodeFunction) member).symbol;
1290 } else {
1291 if (member.name == "copy") {
1292 copy_function = ((IdlNodeFunction) member).symbol;
1294 var m = parse_function ((IdlNodeFunction) member);
1295 if (m != null) {
1296 cl.add_method (m);
1299 } else if (member.type == IdlNodeTypeId.FIELD) {
1300 var f = parse_field ((IdlNodeField) member);
1301 if (f != null) {
1302 cl.add_field (f);
1307 if (ref_function != null) {
1308 cl.set_attribute_string ("CCode", "ref_function", ref_function);
1309 if (ref_function_void) {
1310 cl.set_attribute_bool ("CCode", "ref_function_void", ref_function_void);
1312 } else if (copy_function != null) {
1313 cl.set_attribute_string ("CCode", "copy_function", copy_function);
1315 if (unref_function != null) {
1316 cl.set_attribute_string ("CCode", "unref_function", unref_function);
1317 } else if (free_function != null && free_function != "%sfree".printf (get_lower_case_cprefix (cl))) {
1318 cl.set_attribute_string ("CCode", "free_function", free_function);
1321 current_data_type = null;
1325 private void parse_enum (IdlNodeEnum en_node, Symbol container, IdlModule module, bool is_flags) {
1326 weak IdlNode node = (IdlNode) en_node;
1327 string name = fix_type_name (node.name, container);
1328 bool existing = true;
1330 var en = container.scope.lookup (name) as Enum;
1331 if (en == null) {
1332 en = new Enum (name, current_source_reference);
1333 en.access = SymbolAccessibility.PUBLIC;
1334 existing = false;
1335 } else {
1336 // ignore dummy enum values in -custom.vala files
1337 // they exist for syntactical reasons
1338 var dummy = (EnumValue) en.scope.lookup ("__DUMMY__");
1339 if (dummy != null) {
1340 en.get_values ().remove (dummy);
1341 en.scope.remove ("__DUMMY__");
1345 if (en_node.gtype_name == null || en_node.gtype_name == "") {
1346 en.set_attribute_bool ("CCode", "has_type_id", false);
1349 string common_prefix = null;
1351 foreach (weak IdlNode value in en_node.values) {
1352 var val_attributes = get_attributes (value.name);
1353 bool is_hidden = false;
1354 if (val_attributes != null) {
1355 foreach (string attr in val_attributes) {
1356 var nv = attr.split ("=", 2);
1357 if (nv[0] == "hidden" && eval(nv[1]) == "1") {
1358 is_hidden = true;
1363 if (is_hidden) {
1364 continue;
1367 if (common_prefix == null) {
1368 common_prefix = value.name;
1369 while (common_prefix.length > 0 && !common_prefix.has_suffix ("_")) {
1370 // FIXME: could easily be made faster
1371 common_prefix = common_prefix.substring (0, common_prefix.length - 1);
1373 } else {
1374 while (!value.name.has_prefix (common_prefix)) {
1375 common_prefix = common_prefix.substring (0, common_prefix.length - 1);
1378 while (common_prefix.length > 0 && (!common_prefix.has_suffix ("_") ||
1379 (value.name.get_char (common_prefix.length).isdigit ()) && (value.name.length - common_prefix.length) <= 1)) {
1380 // enum values may not consist solely of digits
1381 common_prefix = common_prefix.substring (0, common_prefix.length - 1);
1385 bool is_errordomain = false;
1387 string cheader_filename = null;
1389 var en_attributes = get_attributes (node.name);
1390 if (en_attributes != null) {
1391 foreach (string attr in en_attributes) {
1392 var nv = attr.split ("=", 2);
1393 if (nv[0] == "common_prefix") {
1394 common_prefix = eval (nv[1]);
1395 } else if (nv[0] == "cheader_filename") {
1396 cheader_filename = eval (nv[1]);
1397 en.set_attribute_string ("CCode", "cheader_filename", cheader_filename);
1398 } else if (nv[0] == "hidden") {
1399 if (eval (nv[1]) == "1") {
1400 return;
1402 } else if (nv[0] == "deprecated") {
1403 if (eval (nv[1]) == "1") {
1404 en.set_attribute_bool ("Version", "deprecated", true);
1406 } else if (nv[0] == "default_value") {
1407 en.set_attribute_string ("CCode", "default_value", eval (nv[1]));
1408 } else if (nv[0] == "replacement") {
1409 en.set_attribute_string ("Version", "replacement", eval (nv[1]));
1410 } else if (nv[0] == "deprecated_since") {
1411 en.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
1412 } else if (nv[0] == "rename_to") {
1413 en.name = eval (nv[1]);
1414 } else if (nv[0] == "errordomain") {
1415 if (eval (nv[1]) == "1") {
1416 is_errordomain = true;
1418 } else if (nv[0] == "to_string") {
1419 var return_type = new UnresolvedType ();
1420 return_type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1421 return_type.value_owned = false;
1422 var m = new Method ("to_string", return_type, current_source_reference);
1423 m.access = SymbolAccessibility.PUBLIC;
1424 m.set_attribute_string ("CCode", "cname", eval(nv[1]));
1425 en.add_method (m);
1426 } else if (nv[0] == "experimental") {
1427 if (eval (nv[1]) == "1") {
1428 en.set_attribute_bool ("Version", "experimental", true);
1434 en.set_attribute_string ("CCode", "cprefix", common_prefix);
1436 foreach (weak IdlNode value2 in en_node.values) {
1437 EnumValue ev = new EnumValue (value2.name.substring (common_prefix.length), null);
1439 var val_attributes = get_attributes (value2.name);
1440 bool is_hidden = false;
1441 if (val_attributes != null) {
1442 foreach (string attr in val_attributes) {
1443 var nv = attr.split ("=", 2);
1444 if (nv[0] == "hidden" && eval(nv[1]) == "1") {
1445 is_hidden = true;
1446 } else if (nv[0] == "deprecated") {
1447 if (eval (nv[1]) == "1") {
1448 ev.set_attribute_bool ("Version", "deprecated", true);
1450 } else if (nv[0] == "replacement") {
1451 ev.set_attribute_string ("Version", "replacement", eval (nv[1]));
1452 } else if (nv[0] == "deprecated_since") {
1453 ev.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
1458 if (!is_hidden) {
1459 en.add_value (ev);
1463 if (is_errordomain) {
1464 var ed = new ErrorDomain (en.name, current_source_reference);
1465 ed.access = SymbolAccessibility.PUBLIC;
1466 ed.set_attribute_string ("CCode", "cprefix", common_prefix);
1468 if (cheader_filename != null) {
1469 ed.set_attribute_string ("CCode", "cheader_filename", cheader_filename);
1472 foreach (EnumValue ev in en.get_values ()) {
1473 ed.add_code (new ErrorCode (ev.name));
1476 current_source_file.add_node (ed);
1477 if (!existing) {
1478 add_symbol_to_container (container, ed);
1480 } else {
1481 en.set_attribute ("Flags", is_flags);
1482 current_source_file.add_node (en);
1483 if (!existing) {
1484 add_symbol_to_container (container, en);
1489 private void parse_object (IdlNodeInterface node, Symbol container, IdlModule module) {
1490 string name = fix_type_name (((IdlNode) node).name, container);
1492 string base_class = null;
1494 var cl = container.scope.lookup (name) as Class;
1495 if (cl == null) {
1496 cl = new Class (name, current_source_reference);
1497 cl.access = SymbolAccessibility.PUBLIC;
1499 var attributes = get_attributes (node.gtype_name);
1500 if (attributes != null) {
1501 foreach (string attr in attributes) {
1502 var nv = attr.split ("=", 2);
1503 if (nv[0] == "cheader_filename") {
1504 cl.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
1505 } else if (nv[0] == "base_class") {
1506 base_class = eval (nv[1]);
1507 } else if (nv[0] == "hidden") {
1508 if (eval (nv[1]) == "1") {
1509 return;
1511 } else if (nv[0] == "type_check_function") {
1512 cl.set_attribute_string ("CCode", "type_check_function", eval (nv[1]));
1513 } else if (nv[0] == "deprecated") {
1514 if (eval (nv[1]) == "1") {
1515 cl.set_attribute_bool ("Version", "deprecated", true);
1517 } else if (nv[0] == "replacement") {
1518 cl.set_attribute_string ("Version", "replacement", eval (nv[1]));
1519 } else if (nv[0] == "deprecated_since") {
1520 cl.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
1521 } else if (nv[0] == "type_id") {
1522 cl.set_attribute_string ("CCode", "type_id", eval (nv[1]));
1523 } else if (nv[0] == "abstract") {
1524 if (eval (nv[1]) == "1") {
1525 cl.is_abstract = true;
1527 } else if (nv[0] == "experimental") {
1528 if (eval (nv[1]) == "1") {
1529 cl.set_attribute_bool ("Version", "experimental", true);
1531 } else if (nv[0] == "compact") {
1532 if (eval (nv[1]) == "1") {
1533 cl.is_compact = true;
1535 } else if (nv[0] == "ref_function") {
1536 cl.set_attribute_string ("CCode", "ref_function", eval (nv[1]));
1537 } else if (nv[0] == "unref_function") {
1538 cl.set_attribute_string ("CCode", "unref_function", eval (nv[1]));
1539 } else if (nv[0] == "copy_function") {
1540 cl.set_attribute_string ("CCode", "copy_function", eval (nv[1]));
1541 } else if (nv[0] == "free_function") {
1542 cl.set_attribute_string ("CCode", "free_function", eval (nv[1]));
1547 add_symbol_to_container (container, cl);
1548 current_source_file.add_node (cl);
1551 if (base_class != null) {
1552 var parent = parse_type_string (base_class);
1553 cl.add_base_type (parent);
1554 } else if (node.parent != null) {
1555 if (!cl.is_compact) {
1556 var parent = parse_type_string (node.parent);
1557 cl.add_base_type (parent);
1559 } else {
1560 var gobject_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Object");
1561 cl.add_base_type (new UnresolvedType.from_symbol (gobject_symbol));
1564 foreach (string iface_name in node.interfaces) {
1565 bool skip_iface = false;
1567 var attributes = get_attributes (iface_name);
1568 if (attributes != null) {
1569 foreach (string attr in attributes) {
1570 var nv = attr.split ("=", 2);
1571 if (nv[0] == "hidden") {
1572 if (eval (nv[1]) == "1") {
1573 skip_iface = true;
1579 if (skip_iface) {
1580 continue;
1583 var iface = parse_type_string (iface_name);
1584 cl.add_base_type (iface);
1587 current_data_type = cl;
1589 current_type_symbol_set = new HashSet<string> (str_hash, str_equal);
1590 var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
1591 var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
1593 foreach (weak IdlNode member in node.members) {
1594 if (member.type == IdlNodeTypeId.FUNCTION) {
1595 current_type_func_map.set (member.name, (IdlNodeFunction) member);
1597 if (member.type == IdlNodeTypeId.VFUNC) {
1598 current_type_vfunc_map.set (member.name, "1");
1602 foreach (weak IdlNode member in node.members) {
1603 if (member.type == IdlNodeTypeId.FUNCTION) {
1604 // Ignore if vfunc (handled below)
1605 if (!current_type_vfunc_map.contains (member.name)) {
1606 var m = parse_function ((IdlNodeFunction) member);
1607 if (m != null) {
1608 cl.add_method (m);
1611 } else if (member.type == IdlNodeTypeId.VFUNC) {
1612 var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name));
1613 if (m != null) {
1614 cl.add_method (m);
1616 } else if (member.type == IdlNodeTypeId.PROPERTY) {
1617 var prop = parse_property ((IdlNodeProperty) member);
1618 if (prop != null) {
1619 cl.add_property (prop);
1621 } else if (member.type == IdlNodeTypeId.SIGNAL) {
1622 var sig = parse_signal ((IdlNodeSignal) member);
1623 if (sig != null) {
1624 cl.add_signal (sig);
1629 foreach (weak IdlNode member in node.members) {
1630 if (member.type == IdlNodeTypeId.FIELD) {
1631 if (!current_type_symbol_set.contains (member.name)) {
1632 var f = parse_field ((IdlNodeField) member);
1633 if (f != null) {
1634 cl.add_field (f);
1640 foreach (Property prop in cl.get_properties ()) {
1641 var getter = "get_%s".printf (prop.name);
1643 if (prop.get_accessor != null && !current_type_symbol_set.contains (getter)) {
1644 prop.set_attribute ("NoAccessorMethod", true);
1647 var setter = "set_%s".printf (prop.name);
1649 if (prop.set_accessor != null && prop.set_accessor.writable
1650 && !current_type_symbol_set.contains (setter)) {
1651 prop.set_attribute ("NoAccessorMethod", true);
1654 if (prop.get_attribute ("NoAccessorMethod") != null && prop.get_accessor != null) {
1655 prop.get_accessor.value_type.value_owned = true;
1659 handle_async_methods (cl);
1661 if (cl.default_construction_method == null) {
1662 // always provide constructor in generated bindings
1663 // to indicate that implicit Object () chainup is allowed
1664 var cm = new CreationMethod (null, null, cl.source_reference);
1665 cm.has_construct_function = false;
1666 cm.access = SymbolAccessibility.PROTECTED;
1667 cl.add_method (cm);
1670 current_data_type = null;
1671 current_type_symbol_set = null;
1674 private void parse_interface (IdlNodeInterface node, Symbol container, IdlModule module) {
1675 string name = fix_type_name (node.gtype_name, container);
1677 var iface = container.scope.lookup (name) as Interface;
1678 if (iface == null) {
1679 iface = new Interface (name, current_source_reference);
1680 iface.access = SymbolAccessibility.PUBLIC;
1682 var attributes = get_attributes (node.gtype_name);
1683 if (attributes != null) {
1684 foreach (string attr in attributes) {
1685 var nv = attr.split ("=", 2);
1686 if (nv[0] == "cheader_filename") {
1687 iface.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
1688 } else if (nv[0] == "hidden") {
1689 if (eval (nv[1]) == "1") {
1690 return;
1692 } else if (nv[0] == "type_cname") {
1693 iface.set_attribute_string ("CCode", "type_cname", eval (nv[1]));
1694 } else if (nv[0] == "lower_case_csuffix") {
1695 iface.set_attribute_string ("CCode", "lower_case_csuffix", eval (nv[1]));
1700 foreach (string prereq_name in node.prerequisites) {
1701 var prereq = parse_type_string (prereq_name);
1702 iface.add_prerequisite (prereq);
1705 add_symbol_to_container (container, iface);
1706 current_source_file.add_node (iface);
1709 current_data_type = iface;
1711 current_type_symbol_set = new HashSet<string> (str_hash, str_equal);
1712 var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
1713 var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
1715 foreach (weak IdlNode member in node.members) {
1716 if (member.type == IdlNodeTypeId.FUNCTION) {
1717 current_type_func_map.set (member.name, (IdlNodeFunction) member);
1719 if (member.type == IdlNodeTypeId.VFUNC) {
1720 current_type_vfunc_map.set (member.name, "1");
1724 foreach (weak IdlNode member in node.members) {
1725 if (member.type == IdlNodeTypeId.FUNCTION) {
1726 // Ignore if vfunc (handled below)
1727 if (!current_type_vfunc_map.contains (member.name)) {
1728 var m = parse_function ((IdlNodeFunction) member, true);
1729 if (m != null) {
1730 iface.add_method (m);
1733 } else if (member.type == IdlNodeTypeId.VFUNC) {
1734 var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get (member.name), true);
1735 if (m != null) {
1736 iface.add_method (m);
1738 } else if (member.type == IdlNodeTypeId.PROPERTY) {
1739 var prop = parse_property ((IdlNodeProperty) member);
1740 if (prop != null) {
1741 iface.add_property (prop);
1743 } else if (member.type == IdlNodeTypeId.SIGNAL) {
1744 var sig = parse_signal ((IdlNodeSignal) member);
1745 if (sig != null) {
1746 iface.add_signal (sig);
1747 sig.is_virtual = false;
1752 foreach (Property prop in iface.get_properties ()) {
1753 var getter = "get_%s".printf (prop.name);
1755 if (prop.get_accessor != null && !current_type_symbol_set.contains (getter)) {
1756 prop.set_attribute ("NoAccessorMethod", true);
1759 var setter = "set_%s".printf (prop.name);
1761 if (prop.set_accessor != null && prop.set_accessor.writable
1762 && !current_type_symbol_set.contains (setter)) {
1763 prop.set_attribute ("NoAccessorMethod", true);
1766 if (prop.get_attribute ("NoAccessorMethod") != null && prop.get_accessor != null) {
1767 prop.get_accessor.value_type.value_owned = true;
1771 handle_async_methods (iface);
1773 current_data_type = null;
1776 void handle_async_methods (ObjectTypeSymbol type_symbol) {
1777 Set<Method> finish_methods = new HashSet<Method> ();
1778 var methods = type_symbol.get_methods ();
1780 foreach (Method m in methods) {
1781 if (m.coroutine) {
1782 string finish_method_base;
1783 if (m.name.has_suffix ("_async")) {
1784 finish_method_base = m.name.substring (0, m.name.length - "_async".length);
1785 } else {
1786 finish_method_base = m.name;
1788 var finish_method = type_symbol.scope.lookup (finish_method_base + "_finish") as Method;
1790 // check if the method is using non-standard finish method name
1791 if (finish_method == null) {
1792 var method_cname = get_finish_cname (m);
1793 foreach (Method method in type_symbol.get_methods ()) {
1794 if (get_cname (method) == method_cname) {
1795 finish_method = method;
1796 break;
1801 if (finish_method != null) {
1802 m.return_type = finish_method.return_type.copy ();
1803 var a = finish_method.get_attribute ("CCode");
1804 if (a != null && a.has_argument ("array_length")) {
1805 m.set_attribute_bool ("CCode", "array_length", a.get_bool ("array_length"));
1807 if (a != null && a.has_argument ("array_null_terminated")) {
1808 m.set_attribute_bool ("CCode", "array_null_terminated", a.get_bool ("array_null_terminated"));
1810 foreach (var param in finish_method.get_parameters ()) {
1811 if (param.direction == ParameterDirection.OUT) {
1812 var async_param = param.copy ();
1813 if (m.scope.lookup (param.name) != null) {
1814 // parameter name conflict
1815 async_param.name += "_out";
1817 m.add_parameter (async_param);
1820 foreach (DataType error_type in finish_method.get_error_types ()) {
1821 m.add_error_type (error_type.copy ());
1823 finish_methods.add (finish_method);
1828 foreach (Method m in finish_methods)
1830 type_symbol.scope.remove (m.name);
1831 methods.remove (m);
1835 private DataType? parse_type (IdlNodeType type_node, out ParameterDirection direction = null) {
1836 direction = ParameterDirection.IN;
1838 var type = new UnresolvedType ();
1839 if (type_node.tag == TypeTag.VOID) {
1840 if (type_node.is_pointer) {
1841 return new PointerType (new VoidType ());
1842 } else {
1843 return new VoidType ();
1845 } else if (type_node.tag == TypeTag.BOOLEAN) {
1846 type.unresolved_symbol = new UnresolvedSymbol (null, "bool");
1847 } else if (type_node.tag == TypeTag.INT8) {
1848 type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1849 } else if (type_node.tag == TypeTag.UINT8) {
1850 type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1851 } else if (type_node.tag == TypeTag.INT16) {
1852 type.unresolved_symbol = new UnresolvedSymbol (null, "int16");
1853 } else if (type_node.tag == TypeTag.UINT16) {
1854 type.unresolved_symbol = new UnresolvedSymbol (null, "uint16");
1855 } else if (type_node.tag == TypeTag.INT32) {
1856 type.unresolved_symbol = new UnresolvedSymbol (null, "int32");
1857 } else if (type_node.tag == TypeTag.UINT32) {
1858 type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
1859 } else if (type_node.tag == TypeTag.INT64) {
1860 type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1861 } else if (type_node.tag == TypeTag.UINT64) {
1862 type.unresolved_symbol = new UnresolvedSymbol (null, "uint64");
1863 } else if (type_node.tag == TypeTag.INT) {
1864 type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1865 } else if (type_node.tag == TypeTag.UINT) {
1866 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1867 } else if (type_node.tag == TypeTag.LONG) {
1868 type.unresolved_symbol = new UnresolvedSymbol (null, "long");
1869 } else if (type_node.tag == TypeTag.ULONG) {
1870 type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1871 } else if (type_node.tag == TypeTag.SSIZE) {
1872 type.unresolved_symbol = new UnresolvedSymbol (null, "ssize_t");
1873 } else if (type_node.tag == TypeTag.SIZE) {
1874 type.unresolved_symbol = new UnresolvedSymbol (null, "size_t");
1875 } else if (type_node.tag == TypeTag.FLOAT) {
1876 type.unresolved_symbol = new UnresolvedSymbol (null, "float");
1877 } else if (type_node.tag == TypeTag.DOUBLE) {
1878 type.unresolved_symbol = new UnresolvedSymbol (null, "double");
1879 } else if (type_node.tag == TypeTag.UTF8) {
1880 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1881 } else if (type_node.tag == TypeTag.FILENAME) {
1882 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1883 } else if (type_node.tag == TypeTag.ARRAY) {
1884 var element_type = parse_type (type_node.parameter_type1);
1885 type = element_type as UnresolvedType;
1886 if (type == null) {
1887 return element_type;
1889 element_type.value_owned = true;
1890 return new ArrayType (element_type, 1, element_type.source_reference);
1891 } else if (type_node.tag == TypeTag.LIST) {
1892 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "List");
1893 } else if (type_node.tag == TypeTag.SLIST) {
1894 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "SList");
1895 } else if (type_node.tag == TypeTag.HASH) {
1896 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "HashTable");
1897 } else if (type_node.tag == TypeTag.ERROR) {
1898 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Error");
1899 } else if (type_node.unparsed.has_prefix ("cairo_device_t") || type_node.unparsed.has_prefix ("cairo_pattern_t") ||
1900 type_node.unparsed.has_prefix ("cairo_surface_t")) {
1901 if (type_node.unparsed.has_prefix ("cairo_device_t")) {
1902 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "Cairo"), "Device");
1903 } else if (type_node.unparsed.has_prefix ("cairo_pattern_t")) {
1904 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "Cairo"), "Pattern");
1905 } else if (type_node.unparsed.has_prefix ("cairo_surface_t")) {
1906 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "Cairo"), "Surface");
1908 if (type_node.unparsed.has_suffix ("**")) {
1909 direction = ParameterDirection.OUT;
1911 } else if (type_node.is_interface) {
1912 var n = type_node.@interface;
1914 if (n == "") {
1915 return null;
1918 if (n.has_prefix ("const-")) {
1919 n = n.substring ("const-".length);
1922 if (type_node.is_pointer &&
1923 (n == "gchar" || n == "char")) {
1924 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1925 if (type_node.unparsed.has_suffix ("**")) {
1926 direction = ParameterDirection.OUT;
1928 } else if (n == "gunichar") {
1929 type.unresolved_symbol = new UnresolvedSymbol (null, "unichar");
1930 } else if (n == "gchar") {
1931 type.unresolved_symbol = new UnresolvedSymbol (null, "char");
1932 } else if (n == "guchar" || n == "guint8") {
1933 type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
1934 if (type_node.is_pointer) {
1935 type.value_owned = true;
1936 return new ArrayType (type, 1, type.source_reference);
1938 } else if (n == "gushort") {
1939 type.unresolved_symbol = new UnresolvedSymbol (null, "ushort");
1940 } else if (n == "gshort") {
1941 type.unresolved_symbol = new UnresolvedSymbol (null, "short");
1942 } else if (n == "gconstpointer" || n == "void") {
1943 return new PointerType (new VoidType ());
1944 } else if (n == "goffset" || n == "off_t") {
1945 type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
1946 } else if (n == "value_array") {
1947 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "ValueArray");
1948 } else if (n == "time_t") {
1949 type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
1950 } else if (n == "socklen_t") {
1951 type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
1952 } else if (n == "mode_t") {
1953 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1954 } else if (n == "gint" || n == "pid_t") {
1955 type.unresolved_symbol = new UnresolvedSymbol (null, "int");
1956 } else if (n == "unsigned" || n == "unsigned-int") {
1957 type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
1958 } else if (n == "FILE") {
1959 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "FileStream");
1960 } else if (n == "struct") {
1961 return new PointerType (new VoidType ());
1962 } else if (n == "iconv_t") {
1963 return new PointerType (new VoidType ());
1964 } else if (n == "GType") {
1965 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), "Type");
1966 if (type_node.is_pointer) {
1967 type.value_owned = true;
1968 return new ArrayType (type, 1, type.source_reference);
1970 } else if (n == "GStrv") {
1971 type.unresolved_symbol = new UnresolvedSymbol (null, "string");
1972 type.value_owned = true;
1973 return new ArrayType (type, 1, type.source_reference);
1974 } else {
1975 var named_type = parse_type_string (n);
1976 type = named_type as UnresolvedType;
1977 if (type == null) {
1978 return named_type;
1980 if (is_simple_type (n)) {
1981 if (type_node.is_pointer) {
1982 direction = ParameterDirection.OUT;
1984 } else if (type_node.unparsed.has_suffix ("**")) {
1985 direction = ParameterDirection.OUT;
1988 } else {
1989 stdout.printf ("%d\n", type_node.tag);
1991 return type;
1994 private bool is_simple_type (string type_name) {
1995 var st = cname_type_map[type_name] as Struct;
1996 if (st != null && st.is_simple_type ()) {
1997 return true;
2000 return false;
2003 private DataType parse_type_string (string n) {
2004 if (n == "va_list") {
2005 // unsupported
2006 return new PointerType (new VoidType ());
2009 var type = new UnresolvedType ();
2011 var dt = cname_type_map[n];
2012 if (dt != null) {
2013 UnresolvedSymbol parent_symbol = null;
2014 if (dt.parent_symbol.name != null) {
2015 parent_symbol = new UnresolvedSymbol (null, dt.parent_symbol.name);
2017 type.unresolved_symbol = new UnresolvedSymbol (parent_symbol, dt.name);
2018 return type;
2021 var type_attributes = get_attributes (n);
2023 string ns_name = null;
2025 if (null != type_attributes) {
2026 foreach (string attr in type_attributes) {
2027 var nv = attr.split ("=", 2);
2029 if (nv[0] == "cprefix") {
2030 type.unresolved_symbol = new UnresolvedSymbol (null, n.substring (eval (nv[1]).length));
2031 } else if (nv[0] == "name") {
2032 type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
2033 } else if (nv[0] == "namespace") {
2034 ns_name = eval (nv[1]);
2035 } else if (nv[0] == "rename_to") {
2036 type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
2041 if (type.unresolved_symbol != null) {
2042 if (type.unresolved_symbol.name == "pointer") {
2043 return new PointerType (new VoidType ());
2045 if (ns_name != null) {
2046 type.unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
2048 return type;
2051 if (n.has_prefix (current_namespace.name)) {
2052 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, current_namespace.name), n.substring (current_namespace.name.length));
2053 } else if (current_namespace.parent_symbol != null && current_namespace.parent_symbol.name != null && n.has_prefix (current_namespace.parent_symbol.name)) {
2054 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, current_namespace.parent_symbol.name), n.substring (current_namespace.parent_symbol.name.length));
2055 } else if (n.has_prefix ("G")) {
2056 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), n.substring (1));
2057 } else {
2058 var name_parts = n.split (".", 2);
2059 if (name_parts[1] == null) {
2060 type.unresolved_symbol = new UnresolvedSymbol (null, name_parts[0]);
2061 } else {
2062 type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, name_parts[0]), name_parts[1]);
2066 return type;
2069 private DataType? parse_param (IdlNodeParam param, out ParameterDirection direction = null) {
2070 var type = parse_type (param.type, out direction);
2072 // disable for now as null_ok not yet correctly set
2073 // type.non_null = !param.null_ok;
2075 return type;
2078 private UnresolvedSymbol? parse_symbol_from_string (string symbol_string, SourceReference? source_reference = null) {
2079 UnresolvedSymbol? sym = null;
2080 foreach (unowned string s in symbol_string.split (".")) {
2081 sym = new UnresolvedSymbol (sym, s, source_reference);
2083 if (sym == null) {
2084 Report.error (source_reference, "a symbol must be specified");
2086 return sym;
2089 private bool parse_type_arguments_from_string (DataType parent_type, string type_arguments, SourceReference? source_reference = null) {
2090 int type_arguments_length = (int) type_arguments.length;
2091 GLib.StringBuilder current = new GLib.StringBuilder.sized (type_arguments_length);
2093 int depth = 0;
2094 for (var c = 0 ; c < type_arguments_length ; c++) {
2095 if (type_arguments[c] == '<' || type_arguments[c] == '[') {
2096 depth++;
2097 current.append_unichar (type_arguments[c]);
2098 } else if (type_arguments[c] == '>' || type_arguments[c] == ']') {
2099 depth--;
2100 current.append_unichar (type_arguments[c]);
2101 } else if (type_arguments[c] == ',') {
2102 if (depth == 0) {
2103 var dt = parse_type_from_string (current.str, true, source_reference);
2104 if (dt == null) {
2105 return false;
2107 parent_type.add_type_argument (dt);
2108 current.truncate ();
2109 } else {
2110 current.append_unichar (type_arguments[c]);
2112 } else {
2113 current.append_unichar (type_arguments[c]);
2117 var dt = parse_type_from_string (current.str, true, source_reference);
2118 if (dt == null) {
2119 return false;
2121 parent_type.add_type_argument (dt);
2123 return true;
2126 private DataType? parse_type_from_string (string type_string, bool owned_by_default, SourceReference? source_reference = null) {
2127 if (type_from_string_regex == null) {
2128 try {
2129 type_from_string_regex = new GLib.Regex ("^(?:(owned|unowned|weak) +)?([0-9a-zA-Z_\\.]+)(?:<(.+)>)?(\\*+)?(\\[(,*)?\\])?(\\?)?$", GLib.RegexCompileFlags.ANCHORED | GLib.RegexCompileFlags.DOLLAR_ENDONLY | GLib.RegexCompileFlags.OPTIMIZE);
2130 } catch (GLib.RegexError e) {
2131 GLib.error ("Unable to compile regex: %s", e.message);
2135 GLib.MatchInfo match;
2136 if (!type_from_string_regex.match (type_string, 0, out match)) {
2137 Report.error (source_reference, "unable to parse type");
2138 return null;
2141 DataType? type = null;
2143 var ownership_data = match.fetch (1);
2144 var type_name = match.fetch (2);
2145 var type_arguments_data = match.fetch (3);
2146 var pointers_data = match.fetch (4);
2147 var array_data = match.fetch (5);
2148 var array_dimension_data = match.fetch (6);
2149 var nullable_data = match.fetch (7);
2151 var nullable = nullable_data != null && nullable_data.length > 0;
2153 if (ownership_data == null && type_name == "void") {
2154 if (array_data == null && !nullable) {
2155 type = new VoidType (source_reference);
2156 if (pointers_data != null) {
2157 for (int i=0; i < pointers_data.length; i++) {
2158 type = new PointerType (type);
2161 return type;
2162 } else {
2163 Report.error (source_reference, "invalid void type");
2164 return null;
2168 bool value_owned = owned_by_default;
2170 if (ownership_data == "owned") {
2171 value_owned = true;
2172 } else if (ownership_data == "unowned") {
2173 value_owned = false;
2176 var sym = parse_symbol_from_string (type_name, source_reference);
2177 if (sym == null) {
2178 return null;
2180 type = new UnresolvedType.from_symbol (sym, source_reference);
2182 if (type_arguments_data != null && type_arguments_data.length > 0) {
2183 if (!parse_type_arguments_from_string (type, type_arguments_data, source_reference)) {
2184 return null;
2188 if (pointers_data != null) {
2189 for (int i=0; i < pointers_data.length; i++) {
2190 type = new PointerType (type);
2194 if (array_data != null && array_data.length > 0) {
2195 type.value_owned = true;
2196 type = new ArrayType (type, array_dimension_data.length + 1, source_reference);
2199 type.nullable = nullable;
2200 type.value_owned = value_owned;
2201 return type;
2204 private Method? create_method (string name, string symbol, IdlNodeParam? res, GLib.List<IdlNodeParam>? parameters, bool is_constructor, bool is_interface) {
2205 DataType return_type = null;
2206 if (res != null) {
2207 return_type = parse_param (res);
2210 Method m;
2211 if (!is_interface && (is_constructor || name.has_prefix ("new"))) {
2212 m = new CreationMethod (null, name, current_source_reference);
2213 m.has_construct_function = false;
2214 if (m.name == "new") {
2215 m.name = null;
2216 } else if (m.name.has_prefix ("new_")) {
2217 m.name = m.name.substring ("new_".length);
2219 // For classes, check whether a creation method return type equals to the
2220 // type of the class created. If the types do not match (e.g. in most
2221 // gtk widgets) add an attribute to the creation method indicating the used
2222 // return type.
2223 if (current_data_type is Class && res != null) {
2224 if ("%s*".printf (get_cname (current_data_type)) != res.type.unparsed) {
2225 m.set_attribute_string ("CCode", "type", res.type.unparsed);
2228 } else {
2229 m = new Method (name, return_type, current_source_reference);
2231 m.access = SymbolAccessibility.PUBLIC;
2233 if (current_type_symbol_set != null) {
2234 current_type_symbol_set.add (name);
2237 if (current_data_type != null) {
2238 var sig_attributes = get_attributes ("%s::%s".printf (get_cname (current_data_type), name));
2239 if (sig_attributes != null) {
2240 foreach (string attr in sig_attributes) {
2241 var nv = attr.split ("=", 2);
2242 if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
2243 return null;
2249 bool add_ellipsis = false;
2250 bool suppress_throws = false;
2251 string? error_types = null;
2252 Symbol? container = null;
2254 var attributes = get_attributes (symbol);
2255 if (attributes != null) {
2256 foreach (string attr in attributes) {
2257 var nv = attr.split ("=", 2);
2258 if (nv[0] == "name") {
2259 m.name = eval (nv[1]);
2260 } else if (nv[0] == "hidden") {
2261 if (eval (nv[1]) == "1") {
2262 return null;
2264 } else if (nv[0] == "ellipsis") {
2265 if (eval (nv[1]) == "1") {
2266 add_ellipsis = true;
2268 } else if (nv[0] == "printf_format") {
2269 if (eval (nv[1]) == "1") {
2270 m.set_attribute ("PrintfFormat", true);
2272 } else if (nv[0] == "transfer_ownership") {
2273 if (eval (nv[1]) == "1") {
2274 return_type.value_owned = true;
2276 } else if (nv[0] == "transfer_container") {
2277 if (eval (nv[1]) == "1") {
2278 return_type.value_owned = true;
2279 if (return_type is ArrayType) {
2280 ((ArrayType) return_type).element_type.value_owned = false;
2283 } else if (nv[0] == "destroys_instance") {
2284 if (eval (nv[1]) == "1") {
2285 m.set_attribute ("DestroysInstance", true, m.source_reference);
2287 } else if (nv[0] == "returns_floating_reference") {
2288 if (eval (nv[1]) == "1") {
2289 m.set_attribute_bool ("CCode", "returns_floating_reference", true);
2290 m.return_type.value_owned = true;
2292 } else if (nv[0] == "nullable") {
2293 if (eval (nv[1]) == "1" && !(return_type is VoidType)) {
2294 return_type.nullable = true;
2296 } else if (nv[0] == "sentinel") {
2297 m.set_attribute_string ("CCode", "sentinel", eval (nv[1]));
2298 } else if (nv[0] == "is_array") {
2299 if (eval (nv[1]) == "1") {
2300 return_type.value_owned = true;
2301 return_type = new ArrayType (return_type, 1, return_type.source_reference);
2302 m.return_type = return_type;
2304 } else if (nv[0] == "is_pointer") {
2305 if (eval (nv[1]) == "1") {
2306 return_type = new PointerType (return_type, return_type.source_reference);
2307 m.return_type = return_type;
2309 } else if (nv[0] == "throws") {
2310 if (eval (nv[1]) == "0") {
2311 suppress_throws = true;
2313 } else if (nv[0] == "error_types") {
2314 error_types = eval (nv[1]);
2315 } else if (nv[0] == "no_array_length") {
2316 if (eval (nv[1]) == "1") {
2317 m.set_attribute_bool ("CCode", "array_length", false);
2319 } else if (nv[0] == "array_null_terminated") {
2320 if (eval (nv[1]) == "1") {
2321 m.set_attribute_bool ("CCode", "array_length", false);
2322 m.set_attribute_bool ("CCode", "array_null_terminated", true);;
2324 } else if (nv[0] == "array_length_type") {
2325 m.set_attribute_string ("CCode", "array_length_type", eval (nv[1]));
2326 } else if (nv[0] == "type_name") {
2327 m.return_type = return_type = parse_type_from_string (eval (nv[1]), return_type.value_owned);
2328 } else if (nv[0] == "ctype") {
2329 m.set_attribute_string ("CCode", "type", eval (nv[1]));
2330 } else if (nv[0] == "type_arguments") {
2331 parse_type_arguments_from_string (return_type, eval (nv[1]));
2332 } else if (nv[0] == "deprecated") {
2333 if (eval (nv[1]) == "1") {
2334 m.set_attribute_bool ("Version", "deprecated", true);
2336 } else if (nv[0] == "replacement") {
2337 m.set_attribute_string ("Version", "replacement", eval (nv[1]));
2338 } else if (nv[0] == "deprecated_since") {
2339 m.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
2340 } else if (nv[0] == "cheader_filename") {
2341 m.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
2342 } else if (nv[0] == "abstract") {
2343 if (eval (nv[1]) == "1") {
2344 m.is_abstract = true;
2346 } else if (nv[0] == "virtual") {
2347 if (eval (nv[1]) == "1") {
2348 m.is_virtual = true;
2350 } else if (nv[0] == "vfunc_name") {
2351 m.set_attribute_string ("CCode", "vfunc_name", eval (nv[1]));
2352 } else if (nv[0] == "finish_vfunc_name") {
2353 m.set_attribute_string ("CCode", "finish_vfunc_name", eval (nv[1]));
2354 } else if (nv[0] == "finish_name") {
2355 m.set_attribute_string ("CCode", "finish_name", eval (nv[1]));
2356 } else if (nv[0] == "async") {
2357 if (eval (nv[1]) == "1") {
2358 // force async function, even if it doesn't end in _async
2359 m.coroutine = true;
2361 } else if (nv[0] == "parent") {
2362 container = get_container_from_name (eval (nv[1]));
2363 var prefix = get_lower_case_cprefix (container);
2364 if (symbol.has_prefix (prefix)) {
2365 m.name = symbol.substring (prefix.length);
2367 } else if (nv[0] == "experimental") {
2368 if (eval (nv[1]) == "1") {
2369 m.set_attribute_bool ("Version", "experimental", true);
2371 } else if (nv[0] == "simple_generics") {
2372 if (eval (nv[1]) == "1") {
2373 m.set_attribute_bool ("CCode", "simple_generics", true);
2379 bool first = true;
2380 Parameter last_param = null;
2381 DataType last_param_type = null;
2382 foreach (weak IdlNodeParam param in parameters) {
2383 weak IdlNode param_node = (IdlNode) param;
2385 if (first) {
2386 first = false;
2387 if (!(m is CreationMethod) &&
2388 current_data_type != null &&
2389 param.type.is_interface &&
2390 (param_node.name == "self" ||
2391 param.type.@interface.has_suffix (get_cname (current_data_type)))) {
2392 // instance method
2393 continue;
2394 } else if (!(m is CreationMethod) &&
2395 current_data_type != null &&
2396 param.type.is_interface &&
2397 (param_node.name == "klass" ||
2398 param.type.@interface.has_suffix ("%sClass".printf(get_cname (current_data_type))))) {
2399 // class method
2400 m.binding = MemberBinding.CLASS;
2401 if (m.name.has_prefix ("class_")) {
2402 m.name = m.name.substring ("class_".length, m.name.length - "class_".length);
2404 continue;
2405 } else {
2406 // static method
2407 m.binding = MemberBinding.STATIC;
2411 if (param.type.@interface == "GAsyncReadyCallback" && (symbol.has_suffix ("_async") || m.coroutine)) {
2412 // async method
2413 m.coroutine = true;
2414 continue;
2417 // check for GError parameter
2418 if (suppress_throws == false && param_is_exception (param)) {
2419 if (error_types == null)
2420 m.add_error_type (parse_type (param.type));
2421 continue;
2424 string param_name = param_node.name;
2425 if (param_name == "result") {
2426 // avoid conflict with generated result variable
2427 param_name = "_result";
2428 } else if (param_name == "string") {
2429 // avoid conflict with string type
2430 param_name = "str";
2432 ParameterDirection direction;
2433 var param_type = parse_param (param, out direction);
2434 var p = new Parameter (param_name, param_type);
2435 p.direction = direction;
2437 bool hide_param = false;
2438 bool show_param = false;
2439 bool set_array_length_pos = false;
2440 double array_length_pos = 0;
2441 bool set_delegate_target_pos = false;
2442 double delegate_target_pos = 0;
2443 bool array_requested = false;
2444 bool out_requested = false;
2445 attributes = get_attributes ("%s.%s".printf (symbol, param_node.name));
2446 if (attributes != null) {
2447 foreach (string attr in attributes) {
2448 var nv = attr.split ("=", 2);
2449 if (nv[0] == "is_array") {
2450 if (eval (nv[1]) == "1") {
2451 param_type.value_owned = true;
2452 param_type = new ArrayType (param_type, 1, param_type.source_reference);
2453 p.variable_type = param_type;
2454 if (!out_requested) {
2455 p.direction = ParameterDirection.IN;
2457 array_requested = true;
2459 } else if (nv[0] == "is_pointer") {
2460 if (eval (nv[1]) == "1") {
2461 param_type = new PointerType (param_type, return_type.source_reference);
2462 p.variable_type = param_type;
2463 if (!out_requested) {
2464 p.direction = ParameterDirection.IN;
2467 } else if (nv[0] == "is_out") {
2468 if (eval (nv[1]) == "1") {
2469 p.direction = ParameterDirection.OUT;
2470 out_requested = true;
2471 if (!array_requested && param_type is ArrayType) {
2472 var array_type = (ArrayType) param_type;
2473 param_type = array_type.element_type;
2474 p.variable_type = param_type;
2477 } else if (nv[0] == "is_ref") {
2478 if (eval (nv[1]) == "1") {
2479 p.direction = ParameterDirection.REF;
2480 if (!array_requested && param_type is ArrayType) {
2481 var array_type = (ArrayType) param_type;
2482 param_type = array_type.element_type;
2483 p.variable_type = param_type;
2486 } else if (nv[0] == "nullable") {
2487 if (eval (nv[1]) == "1" && !(param_type is VoidType)) {
2488 param_type.nullable = true;
2490 } else if (nv[0] == "transfer_ownership") {
2491 if (eval (nv[1]) == "1") {
2492 param_type.value_owned = true;
2494 } else if (nv[0] == "takes_ownership") {
2495 if (eval (nv[1]) == "1") {
2496 param_type.value_owned = true;
2498 } else if (nv[0] == "value_owned") {
2499 if (eval (nv[1]) == "0") {
2500 param_type.value_owned = false;
2501 } else if (eval (nv[1]) == "1") {
2502 param_type.value_owned = true;
2504 } else if (nv[0] == "hidden") {
2505 if (eval (nv[1]) == "1") {
2506 hide_param = true;
2507 } else if (eval (nv[1]) == "0") {
2508 show_param = true;
2510 } else if (nv[0] == "no_array_length") {
2511 if (eval (nv[1]) == "1") {
2512 p.set_attribute_bool ("CCode", "array_length", false);
2514 } else if (nv[0] == "array_length_type") {
2515 p.set_attribute_string ("CCode", "array_length_type", eval (nv[1]));
2516 } else if (nv[0] == "array_null_terminated") {
2517 if (eval (nv[1]) == "1") {
2518 p.set_attribute_bool ("CCode", "array_length", false);
2519 p.set_attribute_bool ("CCode", "array_null_terminated", true);
2521 } else if (nv[0] == "array_length_pos") {
2522 set_array_length_pos = true;
2523 array_length_pos = double.parse (eval (nv[1]));
2524 } else if (nv[0] == "delegate_target_pos") {
2525 set_delegate_target_pos = true;
2526 delegate_target_pos = double.parse (eval (nv[1]));
2527 } else if (nv[0] == "type_name") {
2528 p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
2529 } else if (nv[0] == "ctype") {
2530 p.set_attribute_string ("CCode", "type", eval (nv[1]));
2531 } else if (nv[0] == "scope") {
2532 p.set_attribute_string ("CCode", "scope", eval (nv[1]));
2533 } else if (nv[0] == "type_arguments") {
2534 parse_type_arguments_from_string (param_type, eval (nv[1]));
2535 } else if (nv[0] == "default_value") {
2536 var val = eval (nv[1]);
2537 if (val == "null") {
2538 p.initializer = new NullLiteral (param_type.source_reference);
2539 } else if (val == "true") {
2540 p.initializer = new BooleanLiteral (true, param_type.source_reference);
2541 } else if (val == "false") {
2542 p.initializer = new BooleanLiteral (false, param_type.source_reference);
2543 } else if (val == "") {
2544 p.initializer = new StringLiteral ("\"\"", param_type.source_reference);
2545 } else {
2546 if (int64.try_parse (val)) {
2547 p.initializer = new IntegerLiteral (val, param_type.source_reference);
2548 } else {
2549 if (double.try_parse (val)) {
2550 p.initializer = new RealLiteral (val, param_type.source_reference);
2551 } else {
2552 if (val.has_prefix ("\"") && val.has_suffix ("\"")) {
2553 p.initializer = new StringLiteral (val, param_type.source_reference);
2554 } else {
2555 foreach (unowned string member in val.split (".")) {
2556 p.initializer = new MemberAccess (p.initializer, member, param_type.source_reference);
2566 if (last_param != null && p.name == "n_" + last_param.name) {
2567 if (!(last_param_type is ArrayType)) {
2568 // last_param is array, p is array length
2569 last_param_type.value_owned = true;
2570 last_param_type = new ArrayType (last_param_type, 1, last_param_type.source_reference);
2571 last_param.variable_type = last_param_type;
2572 last_param.direction = ParameterDirection.IN;
2575 // hide array length param
2576 hide_param = true;
2577 } else if (last_param != null && p.name == "user_data") {
2578 // last_param is delegate
2580 // hide deleate target param
2581 hide_param = true;
2584 if (show_param || !hide_param) {
2585 m.add_parameter (p);
2586 if (set_array_length_pos) {
2587 p.set_attribute_double ("CCode", "array_length_pos", array_length_pos);
2589 if (set_delegate_target_pos) {
2590 p.set_attribute_double ("CCode", "delegate_target_pos", delegate_target_pos);
2594 last_param = p;
2595 last_param_type = param_type;
2598 if (suppress_throws == false && error_types != null) {
2599 var type_args = eval (error_types).split (",");
2600 foreach (unowned string type_arg in type_args) {
2601 m.add_error_type (parse_type_from_string (type_arg, true));
2605 if (first) {
2606 // no parameters => static method
2607 m.binding = MemberBinding.STATIC;
2610 if (last_param != null && last_param.name.has_prefix ("first_")) {
2611 last_param.ellipsis = true;
2612 } else if (add_ellipsis) {
2613 m.add_parameter (new Parameter.with_ellipsis ());
2616 if (container == null) {
2617 container = current_data_type;
2618 if (container == null) {
2619 container = current_namespace;
2622 if (symbol != get_cname (m, container)) {
2623 m.set_attribute_string ("CCode", "cname", symbol);
2626 return m;
2629 private bool param_is_exception (IdlNodeParam param) {
2630 if (!param.type.is_error) {
2631 return false;
2633 var s = param.type.unparsed.chomp ();
2634 if (s.has_suffix ("**")) {
2635 return true;
2637 return false;
2640 private Method? parse_function (IdlNodeFunction f, bool is_interface = false) {
2641 weak IdlNode node = (IdlNode) f;
2643 if (f.deprecated) {
2644 return null;
2647 return create_method (node.name, f.symbol, f.result, f.parameters, f.is_constructor, is_interface);
2650 private Method parse_virtual (IdlNodeVFunc v, IdlNodeFunction? func, bool is_interface = false) {
2651 weak IdlNode node = (IdlNode) v;
2652 string symbol = "%s%s".printf (get_lower_case_cprefix (current_data_type), node.name);
2654 if (func != null) {
2655 symbol = func.symbol;
2658 Method m = create_method (node.name, symbol, v.result, func != null ? func.parameters : v.parameters, false, is_interface);
2659 if (m != null) {
2660 m.binding = MemberBinding.INSTANCE;
2661 m.is_virtual = !(m.is_abstract || is_interface);
2662 m.is_abstract = m.is_abstract || is_interface;
2664 var attributes = get_attributes (symbol);
2665 if (attributes != null) {
2666 foreach (string attr in attributes) {
2667 var nv = attr.split ("=", 2);
2668 if (nv[0] == "virtual") {
2669 if (eval (nv[1]) == "0") {
2670 m.is_virtual = false;
2671 m.is_abstract = false;
2672 } else {
2673 m.is_virtual = true;
2674 m.is_abstract = false;
2680 if (func == null) {
2681 m.set_attribute ("NoWrapper", true);
2685 return m;
2688 private string fix_prop_name (string name) {
2689 var str = new StringBuilder ();
2691 string i = name;
2693 while (i.length > 0) {
2694 unichar c = i.get_char ();
2695 if (c == '-') {
2696 str.append_c ('_');
2697 } else {
2698 str.append_unichar (c);
2701 i = i.next_char ();
2704 return str.str;
2707 private Property? parse_property (IdlNodeProperty prop_node) {
2708 weak IdlNode node = (IdlNode) prop_node;
2710 if (prop_node.deprecated) {
2711 return null;
2714 if (!prop_node.readable && !prop_node.writable) {
2715 // buggy GIDL definition
2716 prop_node.readable = true;
2717 prop_node.writable = true;
2720 var prop = new Property (fix_prop_name (node.name), parse_type (prop_node.type), null, null, current_source_reference);
2721 prop.access = SymbolAccessibility.PUBLIC;
2722 prop.interface_only = true;
2724 if (prop_node.type.is_interface && prop_node.type.interface == "GStrv") {
2725 prop.set_attribute_bool ("CCode", "array_length", false);
2726 prop.set_attribute_bool ("CCode", "array_null_terminated", true);
2729 if (prop_node.readable) {
2730 prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, null);
2732 if (prop_node.writable) {
2733 if (prop_node.construct_only) {
2734 prop.set_accessor = new PropertyAccessor (false, false, true, prop.property_type.copy (), null, null);
2735 } else {
2736 prop.set_accessor = new PropertyAccessor (false, true, prop_node.@construct, prop.property_type.copy (), null, null);
2740 var attributes = get_attributes ("%s:%s".printf (get_cname (current_data_type), node.name));
2741 if (attributes != null) {
2742 foreach (string attr in attributes) {
2743 var nv = attr.split ("=", 2);
2744 if (nv[0] == "hidden") {
2745 if (eval (nv[1]) == "1") {
2746 return null;
2748 } else if (nv[0] == "type_arguments") {
2749 parse_type_arguments_from_string (prop.property_type, eval (nv[1]));
2750 } else if (nv[0] == "deprecated") {
2751 if (eval (nv[1]) == "1") {
2752 prop.set_attribute_bool ("Version", "deprecated", true);
2754 } else if (nv[0] == "replacement") {
2755 prop.set_attribute_string ("Version", "replacement", eval (nv[1]));
2756 } else if (nv[0] == "deprecated_since") {
2757 prop.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
2758 } else if (nv[0] == "accessor_method") {
2759 if (eval (nv[1]) == "0") {
2760 prop.set_attribute ("NoAccessorMethod", true);
2762 } else if (nv[0] == "owned_get") {
2763 if (eval (nv[1]) == "1") {
2764 prop.get_accessor.value_type.value_owned = true;
2766 } else if (nv[0] == "type_name") {
2767 prop.property_type = parse_type_from_string (eval (nv[1]), false);
2768 } else if (nv[0] == "experimental") {
2769 if (eval (nv[1]) == "1") {
2770 prop.set_attribute_bool ("Version", "experimental", true);
2772 } else if (nv[0] == "nullable") {
2773 if (eval (nv[1]) == "1" && !(prop.property_type is VoidType)) {
2774 prop.property_type.nullable = true;
2776 } else if (nv[0] == "abstract") {
2777 if (eval (nv[1]) == "1") {
2778 prop.is_abstract = true;
2784 if (current_type_symbol_set != null) {
2785 current_type_symbol_set.add (prop.name);
2788 return prop;
2791 private Constant? parse_constant (IdlNodeConstant const_node) {
2792 weak IdlNode node = (IdlNode) const_node;
2794 var type = parse_type (const_node.type);
2795 if (type == null) {
2796 return null;
2799 var c = new Constant (node.name, type, null, current_source_reference);
2800 c.external = true;
2802 string[] attributes = get_attributes (node.name);
2803 if (attributes != null) {
2804 foreach (string attr in attributes) {
2805 var nv = attr.split ("=", 2);
2806 if (nv[0] == "cheader_filename") {
2807 c.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
2808 } else if (nv[0] == "deprecated") {
2809 if (eval (nv[1]) == "1") {
2810 c.set_attribute_bool ("Version", "deprecated", true);
2812 } else if (nv[0] == "replacement") {
2813 c.set_attribute_string ("Version", "replacement", eval (nv[1]));
2814 } else if (nv[0] == "deprecated_since") {
2815 c.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
2816 } else if (nv[0] == "hidden") {
2817 if (eval (nv[1]) == "1") {
2818 return null;
2820 } else if (nv[0] == "experimental") {
2821 if (eval (nv[1]) == "1") {
2822 c.set_attribute_bool ("Version", "experimental", true);
2828 c.access = SymbolAccessibility.PUBLIC;
2830 return c;
2833 private Field? parse_field (IdlNodeField field_node) {
2834 weak IdlNode node = (IdlNode) field_node;
2835 bool unhidden = false;
2837 var type = parse_type (field_node.type);
2838 if (type == null) {
2839 return null;
2842 string cheader_filename = null;
2843 string ctype = null;
2844 string array_length_cname = null;
2845 string array_length_type = null;
2846 bool array_null_terminated = false;
2847 bool deprecated = false;
2848 string deprecated_since = null;
2849 string replacement = null;
2850 bool experimental = false;
2851 bool no_delegate_target = false;
2853 var attributes = get_attributes ("%s.%s".printf (get_cname (current_data_type), node.name));
2854 if (attributes != null) {
2855 foreach (string attr in attributes) {
2856 var nv = attr.split ("=", 2);
2857 if (nv[0] == "hidden") {
2858 if (eval (nv[1]) == "1") {
2859 return null;
2860 } else {
2861 unhidden = true;
2863 } else if (nv[0] == "is_array") {
2864 if (eval (nv[1]) == "1") {
2865 type.value_owned = true;
2866 type = new ArrayType (type, 1, type.source_reference);
2868 } else if (nv[0] == "weak") {
2869 if (eval (nv[1]) == "0") {
2870 type.value_owned = true;
2872 } else if (nv[0] == "value_owned") {
2873 if (eval (nv[1]) == "0") {
2874 type.value_owned = false;
2875 } else if (eval (nv[1]) == "1") {
2876 type.value_owned = true;
2878 } else if (nv[0] == "type_name") {
2879 type = parse_type_from_string (eval (nv[1]), true);
2880 } else if (nv[0] == "type_arguments") {
2881 parse_type_arguments_from_string (type, eval (nv[1]));
2882 } else if (nv[0] == "deprecated") {
2883 if (eval (nv[1]) == "1") {
2884 deprecated = true;
2886 } else if (nv[0] == "replacement") {
2887 replacement = eval (nv[1]);
2888 } else if (nv[0] == "deprecated_since") {
2889 deprecated_since = eval (nv[1]);
2890 } else if (nv[0] == "cheader_filename") {
2891 cheader_filename = eval (nv[1]);
2892 } else if (nv[0] == "ctype") {
2893 ctype = eval (nv[1]);
2894 } else if (nv[0] == "array_null_terminated") {
2895 if (eval (nv[1]) == "1") {
2896 array_null_terminated = true;
2898 } else if (nv[0] == "array_length_cname") {
2899 array_length_cname = eval (nv[1]);
2900 } else if (nv[0] == "array_length_type") {
2901 array_length_type = eval (nv[1]);
2902 } else if (nv[0] == "no_delegate_target") {
2903 if (eval (nv[1]) == "1") {
2904 no_delegate_target = true;
2906 } else if (nv[0] == "experimental") {
2907 if (eval (nv[1]) == "1") {
2908 experimental = true;
2914 if (node.name.has_prefix("_") && !unhidden) {
2915 return null;
2918 if (current_type_symbol_set != null) {
2919 current_type_symbol_set.add (node.name);
2922 string field_name = node.name;
2923 if (field_name == "string") {
2924 // avoid conflict with string type
2925 field_name = "str";
2928 var field = new Field (field_name, type, null, current_source_reference);
2929 field.access = SymbolAccessibility.PUBLIC;
2931 if (field_name != node.name) {
2932 field.set_attribute_string ("CCode", "cname", node.name);
2935 if (deprecated) {
2936 field.set_attribute_bool ("Version", "deprecated", true);
2938 if (deprecated_since != null) {
2939 field.set_attribute_string ("Version", "deprecated_since", deprecated_since);
2942 if (replacement != null) {
2943 field.set_attribute_string ("Version", "replacement", replacement);
2947 if (experimental) {
2948 field.set_attribute_bool ("Version", "experimental", true);
2951 if (ctype != null) {
2952 field.set_attribute_string ("CCode", "type", ctype);
2955 if (cheader_filename != null) {
2956 field.set_attribute_string ("CCode", "cheader_filename", cheader_filename);
2959 if (array_null_terminated) {
2960 field.set_attribute_bool ("CCode", "array_null_terminated", true);
2963 if (array_length_cname != null || array_length_type != null) {
2964 if (array_length_cname != null) {
2965 field.set_attribute_string ("CCode", "array_length_cname", array_length_cname);
2967 if (array_length_type != null) {
2968 field.set_attribute_string ("CCode", "array_length_type", array_length_type);
2970 } else if (field.variable_type is ArrayType) {
2971 field.set_attribute_bool ("CCode", "array_length", false);
2974 if (no_delegate_target) {
2975 field.set_attribute_bool ("CCode", "delegate_target", false);
2978 return field;
2981 private string[]? get_attributes (string codenode) {
2982 var attributes = codenode_attributes_map.get (codenode);
2984 if (attributes == null) {
2985 var dot_required = (-1 != codenode.index_of_char ('.'));
2986 var colon_required = (-1 != codenode.index_of_char (':'));
2988 var pattern_specs = codenode_attributes_patterns.get_keys ();
2989 foreach (PatternSpec* pattern in pattern_specs) {
2990 var pspec = codenode_attributes_patterns[pattern];
2992 if ((dot_required && -1 == pspec.index_of_char ('.')) ||
2993 (colon_required && -1 == pspec.index_of_char (':'))) {
2994 continue;
2997 if (pattern->match_string (codenode)) {
2998 return get_attributes (pspec);
3003 if (attributes == null) {
3004 return null;
3007 GLib.SList<string> attr_list = new GLib.SList<string> ();
3008 var attr = new GLib.StringBuilder.sized (attributes.length);
3009 var attributes_len = attributes.length;
3010 unowned string remaining = attributes;
3011 bool quoted = false, escaped = false;
3012 for (int b = 0 ; b < attributes_len ; b++) {
3013 unichar c = remaining.get_char ();
3015 if (escaped) {
3016 escaped = false;
3017 attr.append_unichar (c);
3018 } else {
3019 if (c == '"') {
3020 attr.append_unichar (c);
3021 quoted = !quoted;
3022 } else if (c == '\\') {
3023 escaped = true;
3024 } else if (!quoted && (c == ' ')) {
3025 attr_list.prepend (attr.str);
3026 attr.truncate (0);
3027 } else {
3028 attr.append_unichar (c);
3032 remaining = (string) ((char*) remaining + remaining.index_of_nth_char (1));
3035 if (attr.len > 0) {
3036 attr_list.prepend (attr.str);
3039 var attrs = new string[attr_list.length ()];
3040 unowned GLib.SList<string>? attr_i = attr_list;
3041 for (int a = 0 ; a < attrs.length ; a++, attr_i = attr_i.next) {
3042 attrs[(attrs.length - 1) - a] = attr_i.data;
3045 return attrs;
3048 private string eval (string s) {
3049 return ((s.length >= 2) && s.has_prefix ("\"") && s.has_suffix ("\"")) ? s.substring (1, s.length - 2) : s;
3052 private Signal? parse_signal (IdlNodeSignal sig_node) {
3053 weak IdlNode node = (IdlNode) sig_node;
3055 if (sig_node.deprecated || sig_node.result == null) {
3056 return null;
3059 var sig = new Signal (fix_prop_name (node.name), parse_param (sig_node.result), current_source_reference);
3060 sig.access = SymbolAccessibility.PUBLIC;
3062 var attributes = get_attributes ("%s::%s".printf (get_cname (current_data_type), sig.name));
3063 if (attributes != null) {
3064 string ns_name = null;
3065 foreach (string attr in attributes) {
3066 var nv = attr.split ("=", 2);
3067 if (nv[0] == "name") {
3068 sig.set_attribute_string ("CCode", "cname", sig.name.replace ("_", "-"));
3069 sig.name = eval (nv[1]);
3070 } else if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
3071 sig.set_attribute ("HasEmitter", true);
3072 } else if (nv[0] == "hidden") {
3073 if (eval (nv[1]) == "1") {
3074 return null;
3076 } else if (nv[0] == "deprecated") {
3077 if (eval (nv[1]) == "1") {
3078 sig.set_attribute_bool ("Version", "deprecated", true);
3080 } else if (nv[0] == "replacement") {
3081 sig.set_attribute_string ("Version", "replacement", eval (nv[1]));
3082 } else if (nv[0] == "deprecated_since") {
3083 sig.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
3084 } else if (nv[0] == "transfer_ownership") {
3085 if (eval (nv[1]) == "1") {
3086 sig.return_type.value_owned = true;
3088 } else if (nv[0] == "namespace_name") {
3089 ns_name = eval (nv[1]);
3090 } else if (nv[0] == "type_name") {
3091 sig.return_type = parse_type_from_string (eval (nv[1]), false);
3092 } else if (nv[0] == "type_arguments") {
3093 parse_type_arguments_from_string (sig.return_type, eval (nv[1]));
3094 } else if (nv[0] == "experimental") {
3095 if (eval (nv[1]) == "1") {
3096 sig.set_attribute_bool ("Version", "experimental", true);
3100 if (ns_name != null) {
3101 ((UnresolvedType) sig.return_type).unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
3105 sig.is_virtual = true;
3107 bool first = true;
3109 foreach (weak IdlNodeParam param in sig_node.parameters) {
3110 if (first) {
3111 // ignore implicit first signal parameter (sender)
3112 first = false;
3113 continue;
3116 weak IdlNode param_node = (IdlNode) param;
3118 ParameterDirection direction;
3119 var param_type = parse_param (param, out direction);
3120 var p = new Parameter (param_node.name, param_type);
3121 p.direction = direction;
3123 bool hide_param = false;
3124 bool show_param = false;
3125 attributes = get_attributes ("%s::%s.%s".printf (get_cname (current_data_type), sig.name, param_node.name));
3126 if (attributes != null) {
3127 string ns_name = null;
3128 foreach (string attr in attributes) {
3129 var nv = attr.split ("=", 2);
3130 if (nv[0] == "hidden") {
3131 if (eval (nv[1]) == "1") {
3132 hide_param = true;
3133 } else if (eval (nv[1]) == "0") {
3134 show_param = true;
3136 } else if (nv[0] == "is_array") {
3137 if (eval (nv[1]) == "1") {
3138 param_type.value_owned = true;
3139 param_type = new ArrayType (param_type, 1, param_type.source_reference);
3140 p.variable_type = param_type;
3141 p.direction = ParameterDirection.IN;
3143 } else if (nv[0] == "no_array_length") {
3144 if (eval (nv[1]) == "1") {
3145 p.set_attribute_bool ("CCode", "array_length", false);
3147 } else if (nv[0] == "array_length_type") {
3148 p.set_attribute_string ("CCode", "array_length_type", nv[1]);
3149 } else if (nv[0] == "array_null_terminated") {
3150 if (eval (nv[1]) == "1") {
3151 p.set_attribute_bool ("CCode", "array_length", false);
3152 p.set_attribute_bool ("CCode", "array_null_terminated", true);
3154 } else if (nv[0] == "is_out") {
3155 if (eval (nv[1]) == "1") {
3156 p.direction = ParameterDirection.OUT;
3158 } else if (nv[0] == "is_ref") {
3159 if (eval (nv[1]) == "1") {
3160 p.direction = ParameterDirection.REF;
3162 } else if (nv[0] == "nullable") {
3163 if (eval (nv[1]) == "1" && !(param_type is VoidType)) {
3164 param_type.nullable = true;
3166 } else if (nv[0] == "transfer_ownership") {
3167 if (eval (nv[1]) == "1") {
3168 param_type.value_owned = true;
3170 } else if (nv[0] == "type_name") {
3171 p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
3172 } else if (nv[0] == "type_arguments") {
3173 parse_type_arguments_from_string (p.variable_type, eval (nv[1]));
3174 } else if (nv[0] == "namespace_name") {
3175 ns_name = eval (nv[1]);
3178 if (ns_name != null) {
3179 ((UnresolvedType) param_type).unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
3183 if (show_param || !hide_param) {
3184 sig.add_parameter (p);
3188 return sig;
3192 // vim:sw=8 noet