3 * Copyright (C) 2006-2009 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
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
29 * Code visitor parsing all GIDL files.
31 public class Vala
.GIdlParser
: CodeVisitor
{
32 private CodeContext context
;
34 private SourceFile current_source_file
;
36 private SourceReference current_source_reference
;
38 private Namespace current_namespace
;
39 private TypeSymbol current_data_type
;
40 private Map
<string,string> codenode_attributes_map
;
41 private Map
<PatternSpec
*,string> codenode_attributes_patterns
;
42 private Gee
.Set
<string> current_type_symbol_set
;
44 private Map
<string,TypeSymbol
> cname_type_map
;
47 * Parse all source files in the specified code context and build a
50 * @param context a code context
52 public void parse (CodeContext context
) {
53 cname_type_map
= new HashMap
<string,TypeSymbol
> (str_hash
, str_equal
);
55 this
.context
= context
;
56 context
.accept (this
);
58 cname_type_map
= null;
61 public override void visit_namespace (Namespace ns
) {
62 ns
.accept_children (this
);
65 public override void visit_class (Class cl
) {
69 public override void visit_struct (Struct st
) {
73 public override void visit_interface (Interface iface
) {
77 public override void visit_enum (Enum en
) {
81 public override void visit_error_domain (ErrorDomain ed
) {
85 public override void visit_delegate (Delegate d
) {
89 private void visit_type (TypeSymbol t
) {
90 if (!cname_type_map
.contains (t
.get_cname ())) {
91 cname_type_map
[t
.get_cname ()] = t
;
95 public override void visit_source_file (SourceFile source_file
) {
96 if (source_file
.filename
.has_suffix (".gi")) {
97 parse_file (source_file
);
101 private void parse_file (SourceFile source_file
) {
102 string metadata_filename
= "%s.metadata".printf (source_file
.filename
.ndup (source_file
.filename
.size () - ".gi".size ()));
104 current_source_file
= source_file
;
106 codenode_attributes_map
= new HashMap
<string,string> (str_hash
, str_equal
);
107 codenode_attributes_patterns
= new HashMap
<PatternSpec
*,string> (direct_hash
, (EqualFunc
) PatternSpec
.equal
);
109 if (FileUtils
.test (metadata_filename
, FileTest
.EXISTS
)) {
112 FileUtils
.get_contents (metadata_filename
, out metadata
, null);
114 foreach (string line
in metadata
.split ("\n")) {
115 if (line
.has_prefix ("#")) {
116 // ignore comment lines
120 var tokens
= line
.split (" ", 2);
122 if (null == tokens
[0]) {
126 if (null != tokens
[0].chr (-1, '*')) {
127 PatternSpec
* pattern
= new
PatternSpec (tokens
[0]);
128 codenode_attributes_patterns
[pattern
] = tokens
[0];
131 codenode_attributes_map
[tokens
[0]] = tokens
[1];
133 } catch (FileError e
) {
134 Report
.error (null, "Unable to read metadata file: %s".printf (e
.message
));
139 var modules
= Idl
.parse_file (source_file
.filename
);
141 current_source_reference
= new
SourceReference (source_file
);
143 foreach (weak IdlModule module
in modules
) {
144 var ns
= parse_module (module
);
146 context
.root
.add_namespace (ns
);
149 } catch (MarkupError e
) {
150 stdout
.printf ("error parsing GIDL file: %s\n", e
.message
);
154 private string fix_type_name (string type_name
, Namespace ns
) {
155 var attributes
= get_attributes (type_name
);
156 if (attributes
!= null) {
157 foreach (string attr
in attributes
) {
158 var nv
= attr
.split ("=", 2);
159 if (nv
[0] == "name") {
165 if (type_name
.has_prefix (ns
.name
)) {
166 return type_name
.offset (ns
.name
.len ());
167 } else if (ns
.name
== "GLib" && type_name
.has_prefix ("G")) {
168 return type_name
.offset (1);
170 string best_match
= null;
171 foreach (string cprefix
in ns
.get_cprefixes ()) {
172 if (type_name
.has_prefix (cprefix
)) {
173 if (best_match
== null || cprefix
.len () > best_match
.len ())
174 best_match
= cprefix
;
178 if (best_match
!= null) {
179 return type_name
.offset (best_match
.len ());;
186 private string fix_const_name (string const_name
, Namespace ns
) {
187 if (const_name
.has_prefix (ns
.name
.up () + "_")) {
188 return const_name
.offset (ns
.name
.len () + 1);
189 } else if (ns
.name
== "GLib" && const_name
.has_prefix ("G_")) {
190 return const_name
.offset (2);
195 private Namespace?
parse_module (IdlModule module
) {
196 Symbol sym
= context
.root
.scope
.lookup (module
.name
);
198 if (sym is Namespace
) {
199 ns
= (Namespace
) sym
;
200 if (ns
.external_package
) {
201 ns
.attributes
= null;
202 ns
.source_reference
= current_source_reference
;
205 ns
= new
Namespace (module
.name
, current_source_reference
);
208 current_namespace
= ns
;
210 var attributes
= get_attributes (ns
.name
);
211 if (attributes
!= null) {
212 foreach (string attr
in attributes
) {
213 var nv
= attr
.split ("=", 2);
214 if (nv
[0] == "cheader_filename") {
215 ns
.set_cheader_filename (eval (nv
[1]));
216 } else if (nv
[0] == "cprefix") {
217 var cprefixes
= eval (nv
[1]).split (",");
218 foreach(string name
in cprefixes
) {
219 ns
.add_cprefix (name
);
221 } else if (nv
[0] == "lower_case_cprefix") {
222 ns
.set_lower_case_cprefix (eval (nv
[1]));
227 foreach (weak IdlNode node
in module
.entries
) {
228 if (node
.type
== IdlNodeTypeId
.CALLBACK
) {
229 var cb
= parse_delegate ((IdlNodeFunction
) node
);
233 cb
.name
= fix_type_name (cb
.name
, ns
);
234 ns
.add_delegate (cb
);
235 current_source_file
.add_node (cb
);
236 } else if (node
.type
== IdlNodeTypeId
.STRUCT
) {
237 parse_struct ((IdlNodeStruct
) node
, ns
, module
);
238 } else if (node
.type
== IdlNodeTypeId
.UNION
) {
239 parse_union ((IdlNodeUnion
) node
, ns
, module
);
240 } else if (node
.type
== IdlNodeTypeId
.BOXED
) {
241 parse_boxed ((IdlNodeBoxed
) node
, ns
, module
);
242 } else if (node
.type
== IdlNodeTypeId
.ENUM
) {
243 var en
= parse_enum ((IdlNodeEnum
) node
);
247 en
.name
= fix_type_name (en
.name
, ns
);
248 if (en is ErrorDomain
) {
249 ns
.add_error_domain (en as ErrorDomain
);
251 ns
.add_enum (en as Enum
);
253 current_source_file
.add_node (en
);
254 } else if (node
.type
== IdlNodeTypeId
.FLAGS
) {
255 var en
= parse_enum ((IdlNodeEnum
) node
) as Enum
;
259 en
.name
= fix_type_name (en
.name
, ns
);
262 current_source_file
.add_node (en
);
263 } else if (node
.type
== IdlNodeTypeId
.OBJECT
) {
264 parse_object ((IdlNodeInterface
) node
, ns
, module
);
265 } else if (node
.type
== IdlNodeTypeId
.INTERFACE
) {
266 parse_interface ((IdlNodeInterface
) node
, ns
, module
);
267 } else if (node
.type
== IdlNodeTypeId
.CONSTANT
) {
268 var c
= parse_constant ((IdlNodeConstant
) node
);
270 c
.name
= fix_const_name (c
.name
, ns
);
272 current_source_file
.add_node (c
);
274 } else if (node
.type
== IdlNodeTypeId
.FUNCTION
) {
275 var m
= parse_function ((IdlNodeFunction
) node
);
277 m
.binding
= MemberBinding
.STATIC
;
279 current_source_file
.add_node (m
);
284 current_namespace
= null;
286 if (sym is Namespace
) {
292 private Delegate?
parse_delegate (IdlNodeFunction f_node
) {
293 weak IdlNode node
= (IdlNode
) f_node
;
295 var return_type
= parse_param (f_node
.result
);
297 var cb
= new
Delegate (node
.name
, return_type
, current_source_reference
);
298 cb
.access
= SymbolAccessibility
.PUBLIC
;
300 bool check_has_target
= true;
302 var attributes
= get_attributes (node
.name
);
303 if (attributes
!= null) {
304 foreach (string attr
in attributes
) {
305 var nv
= attr
.split ("=", 2);
306 if (nv
[0] == "hidden") {
307 if (eval (nv
[1]) == "1") {
310 } else if (nv
[0] == "cheader_filename") {
311 cb
.add_cheader_filename (eval (nv
[1]));
312 } else if (nv
[0] == "has_target") {
313 if (eval (nv
[1]) == "0") {
314 check_has_target
= false;
315 } else if (eval (nv
[1]) == "1") {
316 cb
.has_target
= true;
318 } else if (nv
[0] == "transfer_ownership") {
319 if (eval (nv
[1]) == "1") {
320 return_type
.value_owned
= true;
326 uint remaining_params
= f_node
.parameters
.length ();
327 foreach (weak IdlNodeParam param
in f_node
.parameters
) {
328 weak IdlNode param_node
= (IdlNode
) param
;
330 if (check_has_target
&& remaining_params
== 1 && (param_node
.name
== "user_data" || param_node
.name
== "data")) {
331 // hide user_data parameter for instance delegates
332 cb
.has_target
= true;
334 string param_name
= param_node
.name
;
335 if (param_name
== "string") {
336 // avoid conflict with string type
338 } else if (param_name
== "self") {
339 // avoid conflict with delegate target
340 param_name
= "_self";
343 ParameterDirection direction
;
344 var param_type
= parse_param (param
, out direction
);
345 var p
= new
FormalParameter (param_name
, param_type
);
346 p
.direction
= direction
;
348 bool hide_param
= false;
349 bool show_param
= false;
350 attributes
= get_attributes ("%s.%s".printf (node
.name
, param_node
.name
));
351 if (attributes
!= null) {
352 foreach (string attr
in attributes
) {
353 var nv
= attr
.split ("=", 2);
354 if (nv
[0] == "hidden") {
355 if (eval (nv
[1]) == "1") {
357 } else if (eval (nv
[1]) == "0") {
360 } else if (nv
[0] == "is_out") {
361 if (eval (nv
[1]) == "1") {
362 p
.direction
= ParameterDirection
.OUT
;
364 } else if (nv
[0] == "is_ref") {
365 if (eval (nv
[1]) == "1") {
366 p
.direction
= ParameterDirection
.REF
;
368 } else if (nv
[0] == "takes_ownership") {
369 if (eval (nv
[1]) == "1") {
370 param_type
.value_owned
= true;
376 if (show_param
|| !hide_param
) {
377 cb
.add_parameter (p
);
387 private bool is_reference_type (string cname
) {
388 var st_attributes
= get_attributes (cname
);
389 if (st_attributes
!= null) {
390 foreach (string attr
in st_attributes
) {
391 var nv
= attr
.split ("=", 2);
392 if (nv
[0] == "is_value_type" && eval (nv
[1]) == "1") {
400 private void parse_struct (IdlNodeStruct st_node
, Namespace ns
, IdlModule module
) {
401 weak IdlNode node
= (IdlNode
) st_node
;
403 if (st_node
.deprecated
) {
407 string name
= fix_type_name (node
.name
, ns
);
409 if (!is_reference_type (node
.name
)) {
410 var st
= ns
.scope
.lookup (name
) as Struct
;
412 st
= new
Struct (name
, current_source_reference
);
413 st
.access
= SymbolAccessibility
.PUBLIC
;
415 var st_attributes
= get_attributes (node
.name
);
416 if (st_attributes
!= null) {
417 foreach (string attr
in st_attributes
) {
418 var nv
= attr
.split ("=", 2);
419 if (nv
[0] == "cheader_filename") {
420 st
.add_cheader_filename (eval (nv
[1]));
421 } else if (nv
[0] == "hidden") {
422 if (eval (nv
[1]) == "1") {
425 } else if (nv
[0] == "simple_type") {
426 if (eval (nv
[1]) == "1") {
427 st
.set_simple_type (true);
429 } else if (nv
[0] == "use_const") {
430 if (eval (nv
[1]) == "0") {
431 st
.use_const
= false;
433 } else if (nv
[0] == "has_type_id") {
434 if (eval (nv
[1]) == "0") {
435 st
.has_type_id
= false;
437 } else if (nv
[0] == "type_id") {
438 st
.set_type_id (eval (nv
[1]));
439 } else if (nv
[0] == "has_copy_function") {
440 if (eval (nv
[1]) == "0") {
441 st
.has_copy_function
= false;
443 } else if (nv
[0] == "has_destroy_function") {
444 if (eval (nv
[1]) == "0") {
445 st
.has_destroy_function
= false;
452 current_source_file
.add_node (st
);
455 current_data_type
= st
;
457 foreach (weak IdlNode member
in st_node
.members
) {
458 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
459 var m
= parse_function ((IdlNodeFunction
) member
);
463 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
464 var f
= parse_field ((IdlNodeField
) member
);
471 current_data_type
= null;
473 bool ref_function_void
= false;
474 string ref_function
= null;
475 string unref_function
= null;
476 string copy_function
= null;
477 string free_function
= null;
479 var cl
= ns
.scope
.lookup (name
) as Class
;
481 string base_class
= null;
483 cl
= new
Class (name
, current_source_reference
);
484 cl
.access
= SymbolAccessibility
.PUBLIC
;
485 cl
.is_compact
= true;
487 var cl_attributes
= get_attributes (node
.name
);
488 if (cl_attributes
!= null) {
489 foreach (string attr
in cl_attributes
) {
490 var nv
= attr
.split ("=", 2);
491 if (nv
[0] == "cheader_filename") {
492 cl
.add_cheader_filename (eval (nv
[1]));
493 } else if (nv
[0] == "base_class") {
494 base_class
= eval (nv
[1]);
495 } else if (nv
[0] == "hidden") {
496 if (eval (nv
[1]) == "1") {
499 } else if (nv
[0] == "is_immutable") {
500 if (eval (nv
[1]) == "1") {
501 cl
.is_immutable
= true;
503 } else if (nv
[0] == "is_fundamental") {
504 if (eval (nv
[1]) == "1") {
505 cl
.is_compact
= false;
507 } else if (nv
[0] == "abstract" && base_class
!= null) {
508 if (eval (nv
[1]) == "1") {
509 cl
.is_abstract
= true;
511 } else if (nv
[0] == "free_function") {
512 free_function
= eval (nv
[1]);
513 } else if (nv
[0] == "ref_function") {
514 ref_function
= eval (nv
[1]);
515 } else if (nv
[0] == "unref_function") {
516 unref_function
= eval (nv
[1]);
517 } else if (nv
[0] == "copy_function") {
518 copy_function
= eval (nv
[1]);
519 } else if (nv
[0] == "ref_function_void") {
520 if (eval (nv
[1]) == "1") {
521 ref_function_void
= true;
528 current_source_file
.add_node (cl
);
530 if (base_class
!= null) {
531 var parent
= parse_type_string (base_class
);
532 cl
.add_base_type (parent
);
536 current_data_type
= cl
;
538 foreach (weak IdlNode member
in st_node
.members
) {
539 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
540 if ((ref_function
== null) && (member
.name
== "ref")) {
541 ref_function
= ((IdlNodeFunction
) member
).symbol
;
542 ref_function_void
= (parse_type (((IdlNodeFunction
) member
).result
.type
) is VoidType
);
543 } else if ((unref_function
== null) && (member
.name
== "unref")) {
544 unref_function
= ((IdlNodeFunction
) member
).symbol
;
545 } else if ((free_function
== null) && (member
.name
== "free" || member
.name
== "destroy")) {
546 free_function
= ((IdlNodeFunction
) member
).symbol
;
548 if ((copy_function
== null) && (member
.name
== "copy")) {
549 copy_function
= ((IdlNodeFunction
) member
).symbol
;
551 var m
= parse_function ((IdlNodeFunction
) member
);
556 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
557 var f
= parse_field ((IdlNodeField
) member
);
564 if (ref_function
!= null) {
565 cl
.set_ref_function (ref_function
);
566 cl
.ref_function_void
= ref_function_void
;
568 if (copy_function
!= null) {
569 cl
.set_dup_function (copy_function
);
571 if (unref_function
!= null) {
572 cl
.set_unref_function (unref_function
);
573 } else if (free_function
!= null) {
574 cl
.set_free_function (free_function
);
577 current_data_type
= null;
581 private void parse_union (IdlNodeUnion un_node
, Namespace ns
, IdlModule module
) {
582 weak IdlNode node
= (IdlNode
) un_node
;
584 if (un_node
.deprecated
) {
588 string name
= fix_type_name (node
.name
, ns
);
590 if (!is_reference_type (node
.name
)) {
591 var st
= ns
.scope
.lookup (name
) as Struct
;
593 st
= new
Struct (name
, current_source_reference
);
594 st
.access
= SymbolAccessibility
.PUBLIC
;
596 var st_attributes
= get_attributes (node
.name
);
597 if (st_attributes
!= null) {
598 foreach (string attr
in st_attributes
) {
599 var nv
= attr
.split ("=", 2);
600 if (nv
[0] == "cheader_filename") {
601 st
.add_cheader_filename (eval (nv
[1]));
602 } else if (nv
[0] == "hidden") {
603 if (eval (nv
[1]) == "1") {
611 current_source_file
.add_node (st
);
614 current_data_type
= st
;
616 foreach (weak IdlNode member
in un_node
.members
) {
617 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
618 var m
= parse_function ((IdlNodeFunction
) member
);
622 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
623 var f
= parse_field ((IdlNodeField
) member
);
630 current_data_type
= null;
632 var cl
= ns
.scope
.lookup (name
) as Class
;
634 cl
= new
Class (name
, current_source_reference
);
635 cl
.access
= SymbolAccessibility
.PUBLIC
;
636 cl
.is_compact
= true;
638 var cl_attributes
= get_attributes (node
.name
);
639 if (cl_attributes
!= null) {
640 foreach (string attr
in cl_attributes
) {
641 var nv
= attr
.split ("=", 2);
642 if (nv
[0] == "cheader_filename") {
643 cl
.add_cheader_filename (eval (nv
[1]));
644 } else if (nv
[0] == "hidden") {
645 if (eval (nv
[1]) == "1") {
653 current_source_file
.add_node (cl
);
656 current_data_type
= cl
;
658 bool ref_function_void
= false;
659 string ref_function
= null;
660 string unref_function
= null;
661 string copy_function
= null;
662 string free_function
= null;
664 foreach (weak IdlNode member
in un_node
.members
) {
665 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
666 if (member
.name
== "ref") {
667 ref_function
= ((IdlNodeFunction
) member
).symbol
;
668 ref_function_void
= (parse_type (((IdlNodeFunction
) member
).result
.type
) is VoidType
);
669 } else if (member
.name
== "unref") {
670 unref_function
= ((IdlNodeFunction
) member
).symbol
;
671 } else if (member
.name
== "free" || member
.name
== "destroy") {
672 free_function
= ((IdlNodeFunction
) member
).symbol
;
674 if (member
.name
== "copy") {
675 copy_function
= ((IdlNodeFunction
) member
).symbol
;
677 var m
= parse_function ((IdlNodeFunction
) member
);
682 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
683 var f
= parse_field ((IdlNodeField
) member
);
690 if (ref_function
!= null) {
691 cl
.set_ref_function (ref_function
);
692 cl
.ref_function_void
= ref_function_void
;
694 if (copy_function
!= null) {
695 cl
.set_dup_function (copy_function
);
697 if (unref_function
!= null) {
698 cl
.set_unref_function (unref_function
);
699 } else if (free_function
!= null) {
700 cl
.set_free_function (free_function
);
703 current_data_type
= null;
707 private void parse_boxed (IdlNodeBoxed boxed_node
, Namespace ns
, IdlModule module
) {
708 weak IdlNode node
= (IdlNode
) boxed_node
;
710 string name
= fix_type_name (node
.name
, ns
);
712 var node_attributes
= get_attributes (node
.name
);
713 if (node_attributes
!= null) {
714 foreach (string attr
in node_attributes
) {
715 var nv
= attr
.split ("=", 2);
716 if (nv
[0] == "hidden") {
722 if (!is_reference_type (node
.name
)) {
723 var st
= ns
.scope
.lookup (name
) as Struct
;
725 st
= new
Struct (name
, current_source_reference
);
726 st
.access
= SymbolAccessibility
.PUBLIC
;
728 var st_attributes
= get_attributes (node
.name
);
729 if (st_attributes
!= null) {
730 foreach (string attr
in st_attributes
) {
731 var nv
= attr
.split ("=", 2);
732 if (nv
[0] == "cheader_filename") {
733 st
.add_cheader_filename (eval (nv
[1]));
734 } else if (nv
[0] == "use_const") {
735 if (eval (nv
[1]) == "0") {
736 st
.use_const
= false;
738 } else if (nv
[0] == "has_copy_function") {
739 if (eval (nv
[1]) == "0") {
740 st
.has_copy_function
= false;
742 } else if (nv
[0] == "has_destroy_function") {
743 if (eval (nv
[1]) == "0") {
744 st
.has_destroy_function
= false;
751 st
.set_type_id (st
.get_upper_case_cname ("TYPE_"));
752 current_source_file
.add_node (st
);
755 current_data_type
= st
;
757 foreach (weak IdlNode member
in boxed_node
.members
) {
758 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
759 var m
= parse_function ((IdlNodeFunction
) member
);
763 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
764 var f
= parse_field ((IdlNodeField
) member
);
771 current_data_type
= null;
773 var cl
= ns
.scope
.lookup (name
) as Class
;
775 cl
= new
Class (name
, current_source_reference
);
776 cl
.access
= SymbolAccessibility
.PUBLIC
;
777 cl
.is_compact
= true;
779 var cl_attributes
= get_attributes (node
.name
);
780 if (cl_attributes
!= null) {
781 foreach (string attr
in cl_attributes
) {
782 var nv
= attr
.split ("=", 2);
783 if (nv
[0] == "cheader_filename") {
784 cl
.add_cheader_filename (eval (nv
[1]));
785 } else if (nv
[0] == "is_immutable") {
786 if (eval (nv
[1]) == "1") {
787 cl
.is_immutable
= true;
794 cl
.set_type_id (cl
.get_upper_case_cname ("TYPE_"));
795 current_source_file
.add_node (cl
);
798 current_data_type
= cl
;
800 bool ref_function_void
= false;
801 string ref_function
= null;
802 string unref_function
= null;
803 string copy_function
= null;
804 string free_function
= null;
806 foreach (weak IdlNode member
in boxed_node
.members
) {
807 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
808 if (member
.name
== "ref") {
809 ref_function
= ((IdlNodeFunction
) member
).symbol
;
810 ref_function_void
= (parse_type (((IdlNodeFunction
) member
).result
.type
) is VoidType
);
811 } else if (member
.name
== "unref") {
812 unref_function
= ((IdlNodeFunction
) member
).symbol
;
813 } else if (member
.name
== "free" || member
.name
== "destroy") {
814 free_function
= ((IdlNodeFunction
) member
).symbol
;
816 if (member
.name
== "copy") {
817 copy_function
= ((IdlNodeFunction
) member
).symbol
;
819 var m
= parse_function ((IdlNodeFunction
) member
);
824 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
825 var f
= parse_field ((IdlNodeField
) member
);
832 if (ref_function
!= null) {
833 cl
.set_ref_function (ref_function
);
834 cl
.ref_function_void
= ref_function_void
;
836 if (copy_function
!= null) {
837 cl
.set_dup_function (copy_function
);
839 if (unref_function
!= null) {
840 cl
.set_unref_function (unref_function
);
841 } else if (free_function
!= null) {
842 cl
.set_free_function (free_function
);
845 current_data_type
= null;
849 private TypeSymbol?
parse_enum (IdlNodeEnum en_node
) {
850 weak IdlNode node
= (IdlNode
) en_node
;
852 var en
= new
Enum (node
.name
, current_source_reference
);
853 en
.access
= SymbolAccessibility
.PUBLIC
;
854 en
.has_type_id
= (en_node
.gtype_name
!= null && en_node
.gtype_name
!= "");
856 string common_prefix
= null;
858 foreach (weak IdlNode value
in en_node
.values
) {
859 if (common_prefix
== null) {
860 common_prefix
= value
.name
;
861 while (common_prefix
.len () > 0 && !common_prefix
.has_suffix ("_")) {
862 // FIXME: could easily be made faster
863 common_prefix
= common_prefix
.ndup (common_prefix
.size () - 1);
866 while (!value
.name
.has_prefix (common_prefix
)) {
867 common_prefix
= common_prefix
.ndup (common_prefix
.size () - 1);
870 while (common_prefix
.len () > 0 && (!common_prefix
.has_suffix ("_") ||
871 (value
.name
.offset (common_prefix
.length
).get_char ().isdigit ()) && (value
.name
.len () - common_prefix
.len ()) <= 1)) {
872 // enum values may not consist solely of digits
873 common_prefix
= common_prefix
.ndup (common_prefix
.size () - 1);
877 bool is_errordomain
= false;
879 var cheader_filenames
= new ArrayList
<string> ();
881 var en_attributes
= get_attributes (node
.name
);
882 if (en_attributes
!= null) {
883 foreach (string attr
in en_attributes
) {
884 var nv
= attr
.split ("=", 2);
885 if (nv
[0] == "common_prefix") {
886 common_prefix
= eval (nv
[1]);
887 } else if (nv
[0] == "cheader_filename") {
888 cheader_filenames
.add (eval (nv
[1]));
889 en
.add_cheader_filename (eval (nv
[1]));
890 } else if (nv
[0] == "hidden") {
891 if (eval (nv
[1]) == "1") {
894 } else if (nv
[0] == "rename_to") {
895 en
.name
= eval (nv
[1]);
896 } else if (nv
[0] == "errordomain") {
897 if (eval (nv
[1]) == "1") {
898 is_errordomain
= true;
900 } else if (nv
[0] == "to_string") {
901 var return_type
= new
UnresolvedType ();
902 return_type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
903 return_type
.value_owned
= false;
904 var m
= new
Method ("to_string", return_type
, current_source_reference
);
905 m
.access
= SymbolAccessibility
.PUBLIC
;
906 m
.set_cname (eval(nv
[1]));
912 en
.set_cprefix (common_prefix
);
914 foreach (weak IdlNode value2
in en_node
.values
) {
915 var ev
= new
EnumValue (value2
.name
.offset (common_prefix
.len ()));
919 if (is_errordomain
) {
920 var ed
= new
ErrorDomain (en
.name
, current_source_reference
);
921 ed
.access
= SymbolAccessibility
.PUBLIC
;
922 ed
.set_cprefix (common_prefix
);
924 foreach (string filename
in cheader_filenames
) {
925 ed
.add_cheader_filename (filename
);
928 foreach (EnumValue ev
in en
.get_values ()) {
929 ed
.add_code (new
ErrorCode (ev
.name
));
938 private void parse_object (IdlNodeInterface node
, Namespace ns
, IdlModule module
) {
939 string name
= fix_type_name (((IdlNode
) node
).name
, ns
);
941 string base_class
= null;
943 var cl
= ns
.scope
.lookup (name
) as Class
;
945 cl
= new
Class (name
, current_source_reference
);
946 cl
.access
= SymbolAccessibility
.PUBLIC
;
948 var attributes
= get_attributes (node
.gtype_name
);
949 if (attributes
!= null) {
950 foreach (string attr
in attributes
) {
951 var nv
= attr
.split ("=", 2);
952 if (nv
[0] == "cheader_filename") {
953 cl
.add_cheader_filename (eval (nv
[1]));
954 } else if (nv
[0] == "base_class") {
955 base_class
= eval (nv
[1]);
956 } else if (nv
[0] == "hidden") {
957 if (eval (nv
[1]) == "1") {
960 } else if (nv
[0] == "type_check_function") {
961 cl
.type_check_function
= eval (nv
[1]);
962 } else if (nv
[0] == "abstract") {
963 if (eval (nv
[1]) == "1") {
964 cl
.is_abstract
= true;
971 current_source_file
.add_node (cl
);
974 if (base_class
!= null) {
975 var parent
= parse_type_string (base_class
);
976 cl
.add_base_type (parent
);
977 } else if (node
.parent
!= null) {
978 var parent
= parse_type_string (node
.parent
);
979 cl
.add_base_type (parent
);
981 var gobject_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "Object");
982 cl
.add_base_type (new UnresolvedType
.from_symbol (gobject_symbol
));
985 foreach (string iface_name
in node
.interfaces
) {
986 var iface
= parse_type_string (iface_name
);
987 cl
.add_base_type (iface
);
990 current_data_type
= cl
;
992 current_type_symbol_set
= new HashSet
<string> (str_hash
, str_equal
);
993 var current_type_func_map
= new HashMap
<string,weak IdlNodeFunction
> (str_hash
, str_equal
);
994 var current_type_vfunc_map
= new HashMap
<string,string> (str_hash
, str_equal
);
996 foreach (weak IdlNode member
in node
.members
) {
997 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
998 current_type_func_map
.set (member
.name
, (IdlNodeFunction
) member
);
1000 if (member
.type
== IdlNodeTypeId
.VFUNC
) {
1001 current_type_vfunc_map
.set (member
.name
, "1");
1005 foreach (weak IdlNode member
in node
.members
) {
1006 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1007 // Ignore if vfunc (handled below)
1008 if (!current_type_vfunc_map
.contains (member
.name
)) {
1009 var m
= parse_function ((IdlNodeFunction
) member
);
1014 } else if (member
.type
== IdlNodeTypeId
.VFUNC
) {
1015 var m
= parse_virtual ((IdlNodeVFunc
) member
, current_type_func_map
.get (member
.name
));
1019 } else if (member
.type
== IdlNodeTypeId
.PROPERTY
) {
1020 var prop
= parse_property ((IdlNodeProperty
) member
);
1022 cl
.add_property (prop
);
1024 } else if (member
.type
== IdlNodeTypeId
.SIGNAL
) {
1025 var sig
= parse_signal ((IdlNodeSignal
) member
);
1027 cl
.add_signal (sig
);
1032 foreach (weak IdlNode member
in node
.members
) {
1033 if (member
.type
== IdlNodeTypeId
.FIELD
) {
1034 if (!current_type_symbol_set
.contains (member
.name
)) {
1035 var f
= parse_field ((IdlNodeField
) member
);
1043 foreach (Property prop
in cl
.get_properties ()) {
1044 var getter
= "get_%s".printf (prop
.name
);
1046 if (prop
.get_accessor
!= null && !current_type_symbol_set
.contains (getter
)) {
1047 prop
.no_accessor_method
= true;
1050 var setter
= "set_%s".printf (prop
.name
);
1052 if (prop
.set_accessor
!= null && prop
.set_accessor
.writable
1053 && !current_type_symbol_set
.contains (setter
)) {
1054 prop
.no_accessor_method
= true;
1057 if (prop
.no_accessor_method
&& prop
.get_accessor
!= null) {
1058 prop
.get_accessor
.value_type
.value_owned
= true;
1062 handle_async_methods (cl
);
1064 current_data_type
= null;
1065 current_type_symbol_set
= null;
1068 private void parse_interface (IdlNodeInterface node
, Namespace ns
, IdlModule module
) {
1069 string name
= fix_type_name (node
.gtype_name
, ns
);
1071 var iface
= ns
.scope
.lookup (name
) as Interface
;
1072 if (iface
== null) {
1073 iface
= new
Interface (name
, current_source_reference
);
1074 iface
.access
= SymbolAccessibility
.PUBLIC
;
1076 var attributes
= get_attributes (node
.gtype_name
);
1077 if (attributes
!= null) {
1078 foreach (string attr
in attributes
) {
1079 var nv
= attr
.split ("=", 2);
1080 if (nv
[0] == "cheader_filename") {
1081 iface
.add_cheader_filename (eval (nv
[1]));
1082 } else if (nv
[0] == "lower_case_csuffix") {
1083 iface
.set_lower_case_csuffix (eval (nv
[1]));
1088 foreach (string prereq_name
in node
.prerequisites
) {
1089 var prereq
= parse_type_string (prereq_name
);
1090 iface
.add_prerequisite (prereq
);
1093 ns
.add_interface (iface
);
1094 current_source_file
.add_node (iface
);
1097 current_data_type
= iface
;
1099 var current_type_func_map
= new HashMap
<string,weak IdlNodeFunction
> (str_hash
, str_equal
);
1100 var current_type_vfunc_map
= new HashMap
<string,string> (str_hash
, str_equal
);
1102 foreach (weak IdlNode member
in node
.members
) {
1103 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1104 current_type_func_map
.set (member
.name
, (IdlNodeFunction
) member
);
1106 if (member
.type
== IdlNodeTypeId
.VFUNC
) {
1107 current_type_vfunc_map
.set (member
.name
, "1");
1111 foreach (weak IdlNode member
in node
.members
) {
1112 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1113 // Ignore if vfunc (handled below)
1114 if (!current_type_vfunc_map
.contains (member
.name
)) {
1115 var m
= parse_function ((IdlNodeFunction
) member
, true);
1117 iface
.add_method (m
);
1120 } else if (member
.type
== IdlNodeTypeId
.VFUNC
) {
1121 var m
= parse_virtual ((IdlNodeVFunc
) member
, current_type_func_map
.get (member
.name
), true);
1123 iface
.add_method (m
);
1125 } else if (member
.type
== IdlNodeTypeId
.PROPERTY
) {
1126 var prop
= parse_property ((IdlNodeProperty
) member
);
1128 iface
.add_property (prop
);
1130 } else if (member
.type
== IdlNodeTypeId
.SIGNAL
) {
1131 var sig
= parse_signal ((IdlNodeSignal
) member
);
1133 iface
.add_signal (sig
);
1138 handle_async_methods (iface
);
1140 current_data_type
= null;
1143 void handle_async_methods (ObjectTypeSymbol type_symbol
) {
1144 foreach (Method m
in type_symbol
.get_methods ()) {
1146 var finish_method
= type_symbol
.scope
.lookup (m
.name
.substring (0, m
.name
.length
- "_async".length
) + "_finish") as Method
;
1147 if (finish_method
!= null) {
1148 m
.return_type
= finish_method
.return_type
.copy ();
1149 foreach (var param
in finish_method
.get_parameters ()) {
1150 if (param
.direction
== ParameterDirection
.OUT
) {
1151 var async_param
= param
.copy ();
1152 if (m
.scope
.lookup (param
.name
) != null) {
1153 // parameter name conflict
1154 async_param
.name
+= "_out";
1156 m
.add_parameter (async_param
);
1159 foreach (DataType error_type
in finish_method
.get_error_types ()) {
1160 m
.add_error_type (error_type
.copy ());
1167 private DataType?
parse_type (IdlNodeType type_node
, out ParameterDirection direction
= null) {
1168 ParameterDirection dir
= ParameterDirection
.IN
;
1170 var type
= new
UnresolvedType ();
1171 if (type_node
.tag
== TypeTag
.VOID
) {
1172 if (type_node
.is_pointer
) {
1173 return new
PointerType (new
VoidType ());
1175 return new
VoidType ();
1177 } else if (type_node
.tag
== TypeTag
.BOOLEAN
) {
1178 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "bool");
1179 } else if (type_node
.tag
== TypeTag
.INT8
) {
1180 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "char");
1181 } else if (type_node
.tag
== TypeTag
.UINT8
) {
1182 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uchar");
1183 } else if (type_node
.tag
== TypeTag
.INT16
) {
1184 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int16");
1185 } else if (type_node
.tag
== TypeTag
.UINT16
) {
1186 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint16");
1187 } else if (type_node
.tag
== TypeTag
.INT32
) {
1188 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int32");
1189 } else if (type_node
.tag
== TypeTag
.UINT32
) {
1190 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint32");
1191 } else if (type_node
.tag
== TypeTag
.INT64
) {
1192 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int64");
1193 } else if (type_node
.tag
== TypeTag
.UINT64
) {
1194 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint64");
1195 } else if (type_node
.tag
== TypeTag
.INT
) {
1196 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int");
1197 } else if (type_node
.tag
== TypeTag
.UINT
) {
1198 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint");
1199 } else if (type_node
.tag
== TypeTag
.LONG
) {
1200 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "long");
1201 } else if (type_node
.tag
== TypeTag
.ULONG
) {
1202 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ulong");
1203 } else if (type_node
.tag
== TypeTag
.SSIZE
) {
1204 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ssize_t");
1205 } else if (type_node
.tag
== TypeTag
.SIZE
) {
1206 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "size_t");
1207 } else if (type_node
.tag
== TypeTag
.FLOAT
) {
1208 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "float");
1209 } else if (type_node
.tag
== TypeTag
.DOUBLE
) {
1210 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "double");
1211 } else if (type_node
.tag
== TypeTag
.UTF8
) {
1212 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1213 } else if (type_node
.tag
== TypeTag
.FILENAME
) {
1214 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1215 } else if (type_node
.tag
== TypeTag
.ARRAY
) {
1216 var element_type
= parse_type (type_node
.parameter_type1
);
1217 type
= element_type as UnresolvedType
;
1219 return element_type
;
1221 return new
ArrayType (element_type
, 1, element_type
.source_reference
);
1222 } else if (type_node
.tag
== TypeTag
.LIST
) {
1223 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "List");
1224 } else if (type_node
.tag
== TypeTag
.SLIST
) {
1225 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "SList");
1226 } else if (type_node
.tag
== TypeTag
.HASH
) {
1227 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "HashTable");
1228 } else if (type_node
.tag
== TypeTag
.ERROR
) {
1229 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "Error");
1230 } else if (type_node
.is_interface
) {
1231 var n
= type_node
.@
interface;
1237 if (n
.has_prefix ("const-")) {
1238 n
= n
.offset ("const-".len ());
1241 if (type_node
.is_pointer
&&
1242 (n
== "gchar" || n
== "char")) {
1243 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1244 if (type_node
.unparsed
.has_suffix ("**")) {
1245 dir
= ParameterDirection
.OUT
;
1247 } else if (n
== "gunichar") {
1248 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "unichar");
1249 } else if (n
== "gchar") {
1250 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "char");
1251 } else if (n
== "guchar" || n
== "guint8") {
1252 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uchar");
1253 if (type_node
.is_pointer
) {
1254 return new
ArrayType (type
, 1, type
.source_reference
);
1256 } else if (n
== "gushort") {
1257 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ushort");
1258 } else if (n
== "gshort") {
1259 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "short");
1260 } else if (n
== "gconstpointer" || n
== "void") {
1261 return new
PointerType (new
VoidType ());
1262 } else if (n
== "goffset" || n
== "off_t") {
1263 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int64");
1264 } else if (n
== "value_array") {
1265 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "ValueArray");
1266 } else if (n
== "time_t") {
1267 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ulong");
1268 } else if (n
== "socklen_t") {
1269 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint32");
1270 } else if (n
== "mode_t") {
1271 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint");
1272 } else if (n
== "gint" || n
== "pid_t") {
1273 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int");
1274 } else if (n
== "unsigned" || n
== "unsigned-int") {
1275 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint");
1276 } else if (n
== "FILE") {
1277 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "FileStream");
1278 } else if (n
== "struct") {
1279 return new
PointerType (new
VoidType ());
1280 } else if (n
== "iconv_t") {
1281 return new
PointerType (new
VoidType ());
1282 } else if (n
== "GType") {
1283 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "Type");
1284 if (type_node
.is_pointer
) {
1285 return new
ArrayType (type
, 1, type
.source_reference
);
1287 } else if (n
== "GStrv") {
1288 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1289 return new
ArrayType (type
, 1, type
.source_reference
);
1291 var named_type
= parse_type_string (n
);
1292 type
= named_type as UnresolvedType
;
1296 if (is_simple_type (n
)) {
1297 if (type_node
.is_pointer
) {
1298 dir
= ParameterDirection
.OUT
;
1300 } else if (type_node
.unparsed
.has_suffix ("**")) {
1301 dir
= ParameterDirection
.OUT
;
1305 stdout
.printf ("%d\n", type_node
.tag
);
1307 if (&direction
!= null) {
1313 private bool is_simple_type (string type_name
) {
1314 var st
= cname_type_map
[type_name
] as Struct
;
1315 if (st
!= null && st
.is_simple_type ()) {
1322 private DataType
parse_type_string (string n
) {
1323 if (n
== "va_list") {
1325 return new
PointerType (new
VoidType ());
1328 var type
= new
UnresolvedType ();
1330 var dt
= cname_type_map
[n
];
1332 UnresolvedSymbol parent_symbol
= null;
1333 if (dt
.parent_symbol
.name
!= null) {
1334 parent_symbol
= new
UnresolvedSymbol (null, dt
.parent_symbol
.name
);
1336 type
.unresolved_symbol
= new
UnresolvedSymbol (parent_symbol
, dt
.name
);
1340 var type_attributes
= get_attributes (n
);
1342 string ns_name
= null;
1344 if (null != type_attributes
) {
1345 foreach (string attr
in type_attributes
) {
1346 var nv
= attr
.split ("=", 2);
1348 if (nv
[0] == "cprefix") {
1349 type
.unresolved_symbol
= new
UnresolvedSymbol (null, n
.offset (eval (nv
[1]).len ()));
1350 } else if (nv
[0] == "name") {
1351 type
.unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1352 } else if (nv
[0] == "namespace") {
1353 ns_name
= eval (nv
[1]);
1354 } else if (nv
[0] == "rename_to") {
1355 type
.unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1360 if (type
.unresolved_symbol
!= null) {
1361 if (type
.unresolved_symbol
.name
== "pointer") {
1362 return new
PointerType (new
VoidType ());
1364 if (ns_name
!= null) {
1365 type
.unresolved_symbol
.inner
= new
UnresolvedSymbol (null, ns_name
);
1370 if (n
.has_prefix (current_namespace
.name
)) {
1371 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, current_namespace
.name
), n
.offset (current_namespace
.name
.len ()));
1372 } else if (n
.has_prefix ("G")) {
1373 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), n
.offset (1));
1375 var name_parts
= n
.split (".", 2);
1376 if (name_parts
[1] == null) {
1377 type
.unresolved_symbol
= new
UnresolvedSymbol (null, name_parts
[0]);
1379 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, name_parts
[0]), name_parts
[1]);
1386 private DataType?
parse_param (IdlNodeParam param
, out ParameterDirection direction
= null) {
1387 var type
= parse_type (param
.type
, out direction
);
1389 // disable for now as null_ok not yet correctly set
1390 // type.non_null = !param.null_ok;
1395 private Method?
create_method (string name
, string symbol
, IdlNodeParam? res
, GLib
.List
<IdlNodeParam
>? parameters
, bool is_constructor
, bool is_interface
) {
1396 DataType return_type
= null;
1398 return_type
= parse_param (res
);
1402 if (!is_interface
&& (is_constructor
|| name
.has_prefix ("new"))) {
1403 m
= new
CreationMethod (null, name
, current_source_reference
);
1404 m
.has_construct_function
= false;
1405 if (m
.name
== "new") {
1407 } else if (m
.name
.has_prefix ("new_")) {
1408 m
.name
= m
.name
.offset ("new_".len ());
1410 // For classes, check whether a creation method return type equals to the
1411 // type of the class created. If the types do not match (e.g. in most
1412 // gtk widgets) add an attribute to the creation method indicating the used
1414 if (current_data_type is Class
&& res
!= null) {
1415 if ("%s*".printf (current_data_type
.get_cname()) != res
.type
.unparsed
) {
1416 ((CreationMethod
)m
).custom_return_type_cname
= res
.type
.unparsed
;
1420 m
= new
Method (name
, return_type
, current_source_reference
);
1422 m
.access
= SymbolAccessibility
.PUBLIC
;
1424 if (current_type_symbol_set
!= null) {
1425 current_type_symbol_set
.add (name
);
1428 if (current_data_type
!= null) {
1429 var sig_attributes
= get_attributes ("%s::%s".printf (current_data_type
.get_cname (), name
));
1430 if (sig_attributes
!= null) {
1431 foreach (string attr
in sig_attributes
) {
1432 var nv
= attr
.split ("=", 2);
1433 if (nv
[0] == "has_emitter" && eval (nv
[1]) == "1") {
1440 bool add_ellipsis
= false;
1441 bool suppress_throws
= false;
1443 var attributes
= get_attributes (symbol
);
1444 if (attributes
!= null) {
1445 foreach (string attr
in attributes
) {
1446 var nv
= attr
.split ("=", 2);
1447 if (nv
[0] == "name") {
1448 m
.set_cname (m
.name
);
1449 m
.name
= eval (nv
[1]);
1450 } else if (nv
[0] == "hidden") {
1451 if (eval (nv
[1]) == "1") {
1454 } else if (nv
[0] == "ellipsis") {
1455 if (eval (nv
[1]) == "1") {
1456 add_ellipsis
= true;
1458 } else if (nv
[0] == "printf_format") {
1459 if (eval (nv
[1]) == "1") {
1460 m
.printf_format
= true;
1462 } else if (nv
[0] == "transfer_ownership") {
1463 if (eval (nv
[1]) == "1") {
1464 return_type
.value_owned
= true;
1466 } else if (nv
[0] == "nullable") {
1467 if (eval (nv
[1]) == "1") {
1468 return_type
.nullable
= true;
1470 } else if (nv
[0] == "sentinel") {
1471 m
.sentinel
= eval (nv
[1]);
1472 } else if (nv
[0] == "is_array") {
1473 if (eval (nv
[1]) == "1") {
1474 return_type
= new
ArrayType (return_type
, 1, return_type
.source_reference
);
1475 m
.return_type
= return_type
;
1477 } else if (nv
[0] == "throws") {
1478 if (eval (nv
[1]) == "0") {
1479 suppress_throws
= true;
1481 } else if (nv
[0] == "no_array_length") {
1482 if (eval (nv
[1]) == "1") {
1483 m
.no_array_length
= true;
1485 } else if (nv
[0] == "array_null_terminated") {
1486 if (eval (nv
[1]) == "1") {
1487 m
.no_array_length
= true;
1488 m
.array_null_terminated
= true;
1490 } else if (nv
[0] == "type_name") {
1491 var sym
= new
UnresolvedSymbol (null, eval (nv
[1]));
1492 if (return_type is UnresolvedType
) {
1493 ((UnresolvedType
) return_type
).unresolved_symbol
= sym
;
1495 // Overwrite old return_type, so "type_name" must be before any
1496 // other return type modifying metadata
1497 m
.return_type
= return_type
= new UnresolvedType
.from_symbol (sym
, return_type
.source_reference
);
1499 } else if (nv
[0] == "type_arguments") {
1500 var type_args
= eval (nv
[1]).split (",");
1501 foreach (string type_arg
in type_args
) {
1502 var arg_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, type_arg
));
1503 arg_type
.value_owned
= true;
1504 return_type
.add_type_argument (arg_type
);
1506 } else if (nv
[0] == "cheader_filename") {
1507 m
.add_cheader_filename (eval (nv
[1]));
1508 } else if (nv
[0] == "abstract") {
1509 if (eval (nv
[1]) == "1") {
1510 m
.is_abstract
= true;
1512 } else if (nv
[0] == "virtual") {
1513 if (eval (nv
[1]) == "1") {
1514 m
.is_virtual
= true;
1516 } else if (nv
[0] == "vfunc_name") {
1517 m
.vfunc_name
= eval (nv
[1]);
1522 m
.set_cname (symbol
);
1525 FormalParameter last_param
= null;
1526 DataType last_param_type
= null;
1527 foreach (weak IdlNodeParam param
in parameters
) {
1528 weak IdlNode param_node
= (IdlNode
) param
;
1532 if (!(m is CreationMethod
) &&
1533 current_data_type
!= null &&
1534 param
.type
.is_interface
&&
1535 (param_node
.name
== "self" ||
1536 param
.type
.@
interface.has_suffix (current_data_type
.get_cname ()))) {
1539 } else if (!(m is CreationMethod
) &&
1540 current_data_type
!= null &&
1541 param
.type
.is_interface
&&
1542 (param_node
.name
== "klass" ||
1543 param
.type
.@
interface.has_suffix ("%sClass".printf(current_data_type
.get_cname ())))) {
1545 m
.binding
= MemberBinding
.CLASS
;
1546 if (m
.name
.has_prefix ("class_")) {
1547 m
.name
= m
.name
.substring ("class_".len (), m
.name
.len () - "class_".len ());
1552 m
.binding
= MemberBinding
.STATIC
;
1556 if (param
.type
.@
interface == "GAsyncReadyCallback" && symbol
.has_suffix ("_async")) {
1562 if (suppress_throws
== false && param_is_exception (param
)) {
1563 m
.add_error_type (parse_type (param
.type
));
1567 string param_name
= param_node
.name
;
1568 if (param_name
== "result") {
1569 // avoid conflict with generated result variable
1570 param_name
= "_result";
1571 } else if (param_name
== "string") {
1572 // avoid conflict with string type
1575 ParameterDirection direction
;
1576 var param_type
= parse_param (param
, out direction
);
1577 var p
= new
FormalParameter (param_name
, param_type
);
1578 p
.direction
= direction
;
1580 bool hide_param
= false;
1581 bool show_param
= false;
1582 bool set_array_length_pos
= false;
1583 double array_length_pos
= 0;
1584 bool set_delegate_target_pos
= false;
1585 double delegate_target_pos
= 0;
1586 bool array_requested
= false;
1587 attributes
= get_attributes ("%s.%s".printf (symbol
, param_node
.name
));
1588 if (attributes
!= null) {
1589 foreach (string attr
in attributes
) {
1590 var nv
= attr
.split ("=", 2);
1591 if (nv
[0] == "is_array") {
1592 if (eval (nv
[1]) == "1") {
1593 param_type
= new
ArrayType (param_type
, 1, param_type
.source_reference
);
1594 p
.parameter_type
= param_type
;
1595 p
.direction
= ParameterDirection
.IN
;
1596 array_requested
= true;
1598 } else if (nv
[0] == "is_out") {
1599 if (eval (nv
[1]) == "1") {
1600 p
.direction
= ParameterDirection
.OUT
;
1601 if (!array_requested
&& param_type is ArrayType
) {
1602 var array_type
= (ArrayType
) param_type
;
1603 param_type
= array_type
.element_type
;
1604 p
.parameter_type
= param_type
;
1607 } else if (nv
[0] == "is_ref") {
1608 if (eval (nv
[1]) == "1") {
1609 p
.direction
= ParameterDirection
.REF
;
1610 if (!array_requested
&& param_type is ArrayType
) {
1611 var array_type
= (ArrayType
) param_type
;
1612 param_type
= array_type
.element_type
;
1613 p
.parameter_type
= param_type
;
1616 } else if (nv
[0] == "nullable") {
1617 if (eval (nv
[1]) == "1") {
1618 param_type
.nullable
= true;
1620 } else if (nv
[0] == "transfer_ownership") {
1621 if (eval (nv
[1]) == "1") {
1622 param_type
.value_owned
= true;
1624 } else if (nv
[0] == "takes_ownership") {
1625 if (eval (nv
[1]) == "1") {
1626 param_type
.value_owned
= true;
1628 } else if (nv
[0] == "value_owned") {
1629 if (eval (nv
[1]) == "0") {
1630 param_type
.value_owned
= false;
1631 } else if (eval (nv
[1]) == "1") {
1632 param_type
.value_owned
= true;
1634 } else if (nv
[0] == "hidden") {
1635 if (eval (nv
[1]) == "1") {
1637 } else if (eval (nv
[1]) == "0") {
1640 } else if (nv
[0] == "no_array_length") {
1641 if (eval (nv
[1]) == "1") {
1642 p
.no_array_length
= true;
1644 } else if (nv
[0] == "array_null_terminated") {
1645 if (eval (nv
[1]) == "1") {
1646 p
.no_array_length
= true;
1647 p
.array_null_terminated
= true;
1649 } else if (nv
[0] == "array_length_pos") {
1650 set_array_length_pos
= true;
1651 array_length_pos
= eval (nv
[1]).to_double ();
1652 } else if (nv
[0] == "delegate_target_pos") {
1653 set_delegate_target_pos
= true;
1654 delegate_target_pos
= eval (nv
[1]).to_double ();
1655 } else if (nv
[0] == "type_name") {
1656 ((UnresolvedType
) param_type
).unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1657 } else if (nv
[0] == "ctype") {
1658 p
.ctype
= eval (nv
[1]);
1659 } else if (nv
[0] == "type_arguments") {
1660 var type_args
= eval (nv
[1]).split (",");
1661 foreach (string type_arg
in type_args
) {
1662 var arg_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, type_arg
));
1663 arg_type
.value_owned
= true;
1664 param_type
.add_type_argument (arg_type
);
1670 if (last_param
!= null && p
.name
== "n_" + last_param
.name
) {
1671 if (!(last_param_type is ArrayType
)) {
1672 // last_param is array, p is array length
1673 last_param_type
= new
ArrayType (last_param_type
, 1, last_param_type
.source_reference
);
1674 last_param
.parameter_type
= last_param_type
;
1675 last_param
.direction
= ParameterDirection
.IN
;
1678 // hide array length param
1680 } else if (last_param
!= null && p
.name
== "user_data") {
1681 // last_param is delegate
1683 // hide deleate target param
1687 if (show_param
|| !hide_param
) {
1688 m
.add_parameter (p
);
1689 if (set_array_length_pos
) {
1690 p
.carray_length_parameter_position
= array_length_pos
;
1692 if (set_delegate_target_pos
) {
1693 p
.cdelegate_target_parameter_position
= delegate_target_pos
;
1698 last_param_type
= param_type
;
1702 // no parameters => static method
1703 m
.binding
= MemberBinding
.STATIC
;
1706 if (last_param
!= null && last_param
.name
.has_prefix ("first_")) {
1707 last_param
.ellipsis
= true;
1708 } else if (add_ellipsis
) {
1709 m
.add_parameter (new FormalParameter
.with_ellipsis ());
1715 private bool param_is_exception (IdlNodeParam param
) {
1716 if (!param
.type
.is_error
) {
1719 var s
= param
.type
.unparsed
.chomp ();
1720 if (s
.has_suffix ("**")) {
1726 private Method?
parse_function (IdlNodeFunction f
, bool is_interface
= false) {
1727 weak IdlNode node
= (IdlNode
) f
;
1733 return create_method (node
.name
, f
.symbol
, f
.result
, f
.parameters
, f
.is_constructor
, is_interface
);
1736 private Method
parse_virtual (IdlNodeVFunc v
, IdlNodeFunction? func
, bool is_interface
= false) {
1737 weak IdlNode node
= (IdlNode
) v
;
1738 string symbol
= "%s%s".printf (current_data_type
.get_lower_case_cprefix(), node
.name
);
1741 symbol
= func
.symbol
;
1744 Method m
= create_method (node
.name
, symbol
, v
.result
, func
!= null ? func
.parameters
: v
.parameters
, false, is_interface
);
1746 m
.binding
= MemberBinding
.INSTANCE
;
1747 m
.is_virtual
= !(m
.is_abstract
|| is_interface
);
1748 m
.is_abstract
= m
.is_abstract
|| is_interface
;
1750 var attributes
= get_attributes (symbol
);
1751 if (attributes
!= null) {
1752 foreach (string attr
in attributes
) {
1753 var nv
= attr
.split ("=", 2);
1754 if (nv
[0] == "virtual") {
1755 if (eval (nv
[1]) == "0") {
1756 m
.is_virtual
= false;
1757 m
.is_abstract
= false;
1764 m
.attributes
.append (new
Attribute ("NoWrapper", null));
1771 private string fix_prop_name (string name
) {
1772 var str
= new
StringBuilder ();
1776 while (i
.len () > 0) {
1777 unichar c
= i
.get_char ();
1781 str
.append_unichar (c
);
1790 private Property?
parse_property (IdlNodeProperty prop_node
) {
1791 weak IdlNode node
= (IdlNode
) prop_node
;
1793 if (prop_node
.deprecated
) {
1797 if (!prop_node
.readable
&& !prop_node
.writable
) {
1798 // buggy GIDL definition
1799 prop_node
.readable
= true;
1800 prop_node
.writable
= true;
1803 var prop
= new
Property (fix_prop_name (node
.name
), parse_type (prop_node
.type
), null, null, current_source_reference
);
1804 prop
.access
= SymbolAccessibility
.PUBLIC
;
1805 prop
.interface_only
= true;
1807 if (prop_node
.type
.is_interface
&& prop_node
.type
.interface == "GStrv") {
1808 prop
.no_array_length
= true;
1809 prop
.array_null_terminated
= true;
1812 if (prop_node
.readable
) {
1813 prop
.get_accessor
= new
PropertyAccessor (true, false, false, prop
.property_type
.copy (), null, null);
1815 if (prop_node
.writable
) {
1816 prop
.set_accessor
= new
PropertyAccessor (false, false, false, prop
.property_type
.copy (), null, null);
1817 if (prop_node
.construct_only
) {
1818 prop
.set_accessor
.construction
= true;
1820 prop
.set_accessor
.writable
= true;
1821 prop
.set_accessor
.construction
= prop_node
.@
construct;
1825 var attributes
= get_attributes ("%s:%s".printf (current_data_type
.get_cname (), node
.name
));
1826 if (attributes
!= null) {
1827 foreach (string attr
in attributes
) {
1828 var nv
= attr
.split ("=", 2);
1829 if (nv
[0] == "hidden") {
1830 if (eval (nv
[1]) == "1") {
1833 } else if (nv
[0] == "type_arguments") {
1834 var type_args
= eval (nv
[1]).split (",");
1835 foreach (string type_arg
in type_args
) {
1836 var arg_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, type_arg
));
1837 arg_type
.value_owned
= true;
1838 prop
.property_type
.add_type_argument (arg_type
);
1840 } else if (nv
[0] == "accessor_method") {
1841 if (eval (nv
[1]) == "0") {
1842 prop
.no_accessor_method
= true;
1844 } else if (nv
[0] == "owned_get") {
1845 if (eval (nv
[1]) == "1") {
1846 prop
.get_accessor
.value_type
.value_owned
= true;
1852 if (current_type_symbol_set
!= null) {
1853 current_type_symbol_set
.add (prop
.name
);
1859 private Constant?
parse_constant (IdlNodeConstant const_node
) {
1860 weak IdlNode node
= (IdlNode
) const_node
;
1862 var type
= parse_type (const_node
.type
);
1867 var c
= new
Constant (node
.name
, type
, null, current_source_reference
);
1870 string[] attributes
= get_attributes (node
.name
);
1871 if (attributes
!= null) {
1872 foreach (string attr
in attributes
) {
1873 var nv
= attr
.split ("=", 2);
1874 if (nv
[0] == "cheader_filename") {
1875 c
.add_cheader_filename (eval (nv
[1]));
1876 } else if (nv
[0] == "hidden") {
1877 if (eval (nv
[1]) == "1") {
1884 c
.access
= SymbolAccessibility
.PUBLIC
;
1889 private Field?
parse_field (IdlNodeField field_node
) {
1890 weak IdlNode node
= (IdlNode
) field_node
;
1891 bool unhidden
= false;
1893 var type
= parse_type (field_node
.type
);
1898 string cheader_filename
= null;
1899 string ctype
= null;
1900 bool array_null_terminated
= false;
1902 var attributes
= get_attributes ("%s.%s".printf (current_data_type
.get_cname (), node
.name
));
1903 if (attributes
!= null) {
1904 foreach (string attr
in attributes
) {
1905 var nv
= attr
.split ("=", 2);
1906 if (nv
[0] == "hidden") {
1907 if (eval (nv
[1]) == "1") {
1912 } else if (nv
[0] == "is_array") {
1913 if (eval (nv
[1]) == "1") {
1914 type
= new
ArrayType (type
, 1, type
.source_reference
);
1916 } else if (nv
[0] == "weak") {
1917 if (eval (nv
[1]) == "0") {
1918 type
.value_owned
= true;
1920 } else if (nv
[0] == "type_name") {
1921 ((UnresolvedType
) type
).unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1922 } else if (nv
[0] == "type_arguments") {
1923 var type_args
= eval (nv
[1]).split (",");
1924 foreach (string type_arg
in type_args
) {
1925 var arg_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, type_arg
));
1926 arg_type
.value_owned
= true;
1927 type
.add_type_argument (arg_type
);
1929 } else if (nv
[0] == "cheader_filename") {
1930 cheader_filename
= eval (nv
[1]);
1931 } else if (nv
[0] == "ctype") {
1932 ctype
= eval (nv
[1]);
1933 } else if (nv
[0] == "array_null_terminated") {
1934 if (eval (nv
[1]) == "1") {
1935 array_null_terminated
= true;
1941 if (node
.name
.has_prefix("_") && !unhidden
) {
1945 if (current_type_symbol_set
!= null) {
1946 current_type_symbol_set
.add (node
.name
);
1949 string field_name
= node
.name
;
1950 if (field_name
== "string") {
1951 // avoid conflict with string type
1955 var field
= new
Field (field_name
, type
, null, current_source_reference
);
1956 field
.access
= SymbolAccessibility
.PUBLIC
;
1958 if (field_name
!= node
.name
) {
1959 field
.set_cname (node
.name
);
1962 if (ctype
!= null) {
1963 field
.set_ctype (ctype
);
1966 if (cheader_filename
!= null) {
1967 field
.add_cheader_filename (cheader_filename
);
1970 field
.no_array_length
= true;
1971 if (array_null_terminated
) {
1972 field
.array_null_terminated
= true;
1978 private string[]?
get_attributes (string codenode
) {
1979 var attributes
= codenode_attributes_map
.get (codenode
);
1981 if (attributes
== null) {
1982 var dot_required
= (null != codenode
.chr (-1, '.'));
1983 var colon_required
= (null != codenode
.chr (-1, ':'));
1985 var pattern_specs
= codenode_attributes_patterns
.get_keys ();
1986 foreach (PatternSpec
* pattern
in pattern_specs
) {
1987 var pspec
= codenode_attributes_patterns
[pattern
];
1989 if ((dot_required
&& null == pspec
.chr (-1, '.')) ||
1990 (colon_required
&& null == pspec
.chr (-1, ':'))) {
1994 if (pattern
->match_string (codenode
)) {
1995 return get_attributes (pspec
);
2000 if (attributes
== null) {
2004 return attributes
.split (" ");
2007 private string eval (string s
) {
2008 return ((s
.size () >= 2) && s
.has_prefix ("\"") && s
.has_suffix ("\"")) ? s
.offset (1).ndup (s
.size () - 2) : s
;
2011 private Signal?
parse_signal (IdlNodeSignal sig_node
) {
2012 weak IdlNode node
= (IdlNode
) sig_node
;
2014 if (sig_node
.deprecated
|| sig_node
.result
== null) {
2018 var sig
= new
Signal (fix_prop_name (node
.name
), parse_param (sig_node
.result
), current_source_reference
);
2019 sig
.access
= SymbolAccessibility
.PUBLIC
;
2021 var attributes
= get_attributes ("%s::%s".printf (current_data_type
.get_cname (), sig
.name
));
2022 if (attributes
!= null) {
2023 foreach (string attr
in attributes
) {
2024 var nv
= attr
.split ("=", 2);
2025 if (nv
[0] == "name") {
2026 sig
.set_cname (sig
.name
);
2027 sig
.name
= eval (nv
[1]);
2028 } else if (nv
[0] == "has_emitter" && eval (nv
[1]) == "1") {
2029 sig
.has_emitter
= true;
2030 } else if (nv
[0] == "hidden") {
2031 if (eval (nv
[1]) == "1") {
2038 sig
.is_virtual
= true;
2042 foreach (weak IdlNodeParam param
in sig_node
.parameters
) {
2044 // ignore implicit first signal parameter (sender)
2049 weak IdlNode param_node
= (IdlNode
) param
;
2051 ParameterDirection direction
;
2052 var param_type
= parse_param (param
, out direction
);
2053 var p
= new
FormalParameter (param_node
.name
, param_type
);
2054 p
.direction
= direction
;
2055 sig
.add_parameter (p
);
2057 attributes
= get_attributes ("%s::%s.%s".printf (current_data_type
.get_cname (), sig
.name
, param_node
.name
));
2058 if (attributes
!= null) {
2059 string ns_name
= null;
2060 foreach (string attr
in attributes
) {
2061 var nv
= attr
.split ("=", 2);
2062 if (nv
[0] == "is_array") {
2063 if (eval (nv
[1]) == "1") {
2064 param_type
= new
ArrayType (param_type
, 1, param_type
.source_reference
);
2065 p
.parameter_type
= param_type
;
2066 p
.direction
= ParameterDirection
.IN
;
2068 } else if (nv
[0] == "is_out") {
2069 if (eval (nv
[1]) == "1") {
2070 p
.direction
= ParameterDirection
.OUT
;
2072 } else if (nv
[0] == "is_ref") {
2073 if (eval (nv
[1]) == "1") {
2074 p
.direction
= ParameterDirection
.REF
;
2076 } else if (nv
[0] == "nullable") {
2077 if (eval (nv
[1]) == "1") {
2078 param_type
.nullable
= true;
2080 } else if (nv
[0] == "transfer_ownership") {
2081 if (eval (nv
[1]) == "1") {
2082 param_type
.value_owned
= true;
2084 } else if (nv
[0] == "type_name") {
2085 ((UnresolvedType
) param_type
).unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
2086 } else if (nv
[0] == "namespace_name") {
2087 ns_name
= eval (nv
[1]);
2090 if (ns_name
!= null) {
2091 ((UnresolvedType
) param_type
).unresolved_symbol
.inner
= new
UnresolvedSymbol (null, ns_name
);