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>
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
;
46 * Parse all source files in the specified code context and build a
49 * @param context a code context
51 public void parse (CodeContext context
) {
52 cname_type_map
= new HashMap
<string,TypeSymbol
> (str_hash
, str_equal
);
54 this
.context
= context
;
55 context
.accept (this
);
57 cname_type_map
= null;
60 public override void visit_namespace (Namespace ns
) {
61 ns
.accept_children (this
);
64 public override void visit_class (Class cl
) {
68 public override void visit_struct (Struct st
) {
72 public override void visit_interface (Interface iface
) {
76 public override void visit_enum (Enum en
) {
80 public override void visit_error_domain (ErrorDomain ed
) {
84 public override void visit_delegate (Delegate d
) {
88 private void visit_type (TypeSymbol t
) {
89 if (!cname_type_map
.contains (t
.get_cname ())) {
90 cname_type_map
[t
.get_cname ()] = t
;
94 public override void visit_source_file (SourceFile source_file
) {
95 if (source_file
.filename
.has_suffix (".gi")) {
96 parse_file (source_file
);
100 private void parse_file (SourceFile source_file
) {
101 string metadata_filename
= "%s.metadata".printf (source_file
.filename
.ndup (source_file
.filename
.size () - ".gi".size ()));
103 current_source_file
= source_file
;
105 codenode_attributes_map
= new HashMap
<string,string> (str_hash
, str_equal
);
106 codenode_attributes_patterns
= new HashMap
<PatternSpec
*,string> (direct_hash
, (EqualFunc
) PatternSpec
.equal
);
108 if (FileUtils
.test (metadata_filename
, FileTest
.EXISTS
)) {
111 FileUtils
.get_contents (metadata_filename
, out metadata
, null);
113 foreach (string line
in metadata
.split ("\n")) {
114 if (line
.has_prefix ("#")) {
115 // ignore comment lines
119 var tokens
= line
.split (" ", 2);
121 if (null == tokens
[0]) {
125 if (null != tokens
[0].chr (-1, '*')) {
126 PatternSpec
* pattern
= new
PatternSpec (tokens
[0]);
127 codenode_attributes_patterns
[pattern
] = tokens
[0];
130 codenode_attributes_map
[tokens
[0]] = tokens
[1];
132 } catch (FileError e
) {
133 Report
.error (null, "Unable to read metadata file: %s".printf (e
.message
));
138 var modules
= Idl
.parse_file (source_file
.filename
);
140 current_source_reference
= new
SourceReference (source_file
);
142 foreach (weak IdlModule module
in modules
) {
143 var ns
= parse_module (module
);
145 context
.root
.add_namespace (ns
);
148 } catch (MarkupError e
) {
149 stdout
.printf ("error parsing GIDL file: %s\n", e
.message
);
153 private string fix_type_name (string type_name
, Namespace ns
) {
154 var attributes
= get_attributes (type_name
);
155 if (attributes
!= null) {
156 foreach (string attr
in attributes
) {
157 var nv
= attr
.split ("=", 2);
158 if (nv
[0] == "name") {
164 if (type_name
.has_prefix (ns
.name
)) {
165 return type_name
.offset (ns
.name
.len ());
166 } else if (ns
.name
== "GLib" && type_name
.has_prefix ("G")) {
167 return type_name
.offset (1);
169 string best_match
= null;
170 foreach (string cprefix
in ns
.get_cprefixes ()) {
171 if (type_name
.has_prefix (cprefix
)) {
172 if (best_match
== null || cprefix
.len () > best_match
.len ())
173 best_match
= cprefix
;
177 if (best_match
!= null) {
178 return type_name
.offset (best_match
.len ());;
185 private string fix_const_name (string const_name
, Namespace ns
) {
186 if (const_name
.has_prefix (ns
.name
.up () + "_")) {
187 return const_name
.offset (ns
.name
.len () + 1);
188 } else if (ns
.name
== "GLib" && const_name
.has_prefix ("G_")) {
189 return const_name
.offset (2);
194 private Namespace?
parse_module (IdlModule module
) {
195 Symbol sym
= context
.root
.scope
.lookup (module
.name
);
197 if (sym is Namespace
) {
198 ns
= (Namespace
) sym
;
199 if (ns
.external_package
) {
200 ns
.attributes
= null;
201 ns
.source_reference
= current_source_reference
;
204 ns
= new
Namespace (module
.name
, current_source_reference
);
207 current_namespace
= ns
;
209 var attributes
= get_attributes (ns
.name
);
210 if (attributes
!= null) {
211 foreach (string attr
in attributes
) {
212 var nv
= attr
.split ("=", 2);
213 if (nv
[0] == "cheader_filename") {
214 ns
.set_cheader_filename (eval (nv
[1]));
215 } else if (nv
[0] == "cprefix") {
216 var cprefixes
= eval (nv
[1]).split (",");
217 foreach(string name
in cprefixes
) {
218 ns
.add_cprefix (name
);
220 } else if (nv
[0] == "lower_case_cprefix") {
221 ns
.set_lower_case_cprefix (eval (nv
[1]));
226 foreach (weak IdlNode node
in module
.entries
) {
227 if (node
.type
== IdlNodeTypeId
.CALLBACK
) {
228 var cb
= parse_delegate ((IdlNodeFunction
) node
);
232 cb
.name
= fix_type_name (cb
.name
, ns
);
233 ns
.add_delegate (cb
);
234 current_source_file
.add_node (cb
);
235 } else if (node
.type
== IdlNodeTypeId
.STRUCT
) {
236 parse_struct ((IdlNodeStruct
) node
, ns
, module
);
237 } else if (node
.type
== IdlNodeTypeId
.UNION
) {
238 parse_union ((IdlNodeUnion
) node
, ns
, module
);
239 } else if (node
.type
== IdlNodeTypeId
.BOXED
) {
240 parse_boxed ((IdlNodeBoxed
) node
, ns
, module
);
241 } else if (node
.type
== IdlNodeTypeId
.ENUM
) {
242 var en
= parse_enum ((IdlNodeEnum
) node
);
246 en
.name
= fix_type_name (en
.name
, ns
);
247 if (en is ErrorDomain
) {
248 ns
.add_error_domain (en as ErrorDomain
);
250 ns
.add_enum (en as Enum
);
252 current_source_file
.add_node (en
);
253 } else if (node
.type
== IdlNodeTypeId
.FLAGS
) {
254 var en
= parse_enum ((IdlNodeEnum
) node
) as Enum
;
258 en
.name
= fix_type_name (en
.name
, ns
);
261 current_source_file
.add_node (en
);
262 } else if (node
.type
== IdlNodeTypeId
.OBJECT
) {
263 parse_object ((IdlNodeInterface
) node
, ns
, module
);
264 } else if (node
.type
== IdlNodeTypeId
.INTERFACE
) {
265 parse_interface ((IdlNodeInterface
) node
, ns
, module
);
266 } else if (node
.type
== IdlNodeTypeId
.CONSTANT
) {
267 var c
= parse_constant ((IdlNodeConstant
) node
);
269 c
.name
= fix_const_name (c
.name
, ns
);
271 current_source_file
.add_node (c
);
273 } else if (node
.type
== IdlNodeTypeId
.FUNCTION
) {
274 var m
= parse_function ((IdlNodeFunction
) node
);
276 m
.binding
= MemberBinding
.STATIC
;
278 current_source_file
.add_node (m
);
283 current_namespace
= null;
285 if (sym is Namespace
) {
291 private Delegate?
parse_delegate (IdlNodeFunction f_node
) {
292 weak IdlNode node
= (IdlNode
) f_node
;
294 var return_type
= parse_param (f_node
.result
);
296 var cb
= new
Delegate (node
.name
, return_type
, current_source_reference
);
297 cb
.access
= SymbolAccessibility
.PUBLIC
;
299 bool check_has_target
= true;
301 var attributes
= get_attributes (node
.name
);
302 if (attributes
!= null) {
303 foreach (string attr
in attributes
) {
304 var nv
= attr
.split ("=", 2);
305 if (nv
[0] == "hidden") {
306 if (eval (nv
[1]) == "1") {
309 } else if (nv
[0] == "cheader_filename") {
310 cb
.add_cheader_filename (eval (nv
[1]));
311 } else if (nv
[0] == "has_target") {
312 if (eval (nv
[1]) == "0") {
313 check_has_target
= false;
314 } else if (eval (nv
[1]) == "1") {
315 cb
.has_target
= true;
317 } else if (nv
[0] == "transfer_ownership") {
318 if (eval (nv
[1]) == "1") {
319 return_type
.value_owned
= true;
325 uint remaining_params
= f_node
.parameters
.length ();
326 foreach (weak IdlNodeParam param
in f_node
.parameters
) {
327 weak IdlNode param_node
= (IdlNode
) param
;
329 if (check_has_target
&& remaining_params
== 1 && (param_node
.name
== "user_data" || param_node
.name
== "data")) {
330 // hide user_data parameter for instance delegates
331 cb
.has_target
= true;
333 string param_name
= param_node
.name
;
334 if (param_name
== "string") {
335 // avoid conflict with string type
337 } else if (param_name
== "self") {
338 // avoid conflict with delegate target
339 param_name
= "_self";
342 ParameterDirection direction
;
343 var param_type
= parse_param (param
, out direction
);
344 var p
= new
FormalParameter (param_name
, param_type
);
345 p
.direction
= direction
;
347 bool hide_param
= false;
348 bool show_param
= false;
349 attributes
= get_attributes ("%s.%s".printf (node
.name
, param_node
.name
));
350 if (attributes
!= null) {
351 foreach (string attr
in attributes
) {
352 var nv
= attr
.split ("=", 2);
353 if (nv
[0] == "hidden") {
354 if (eval (nv
[1]) == "1") {
356 } else if (eval (nv
[1]) == "0") {
359 } else if (nv
[0] == "is_out") {
360 if (eval (nv
[1]) == "1") {
361 p
.direction
= ParameterDirection
.OUT
;
363 } else if (nv
[0] == "is_ref") {
364 if (eval (nv
[1]) == "1") {
365 p
.direction
= ParameterDirection
.REF
;
367 } else if (nv
[0] == "takes_ownership") {
368 if (eval (nv
[1]) == "1") {
369 param_type
.value_owned
= true;
371 } else if (nv
[0] == "nullable") {
372 if (eval (nv
[1]) == "1") {
373 param_type
.nullable
= true;
379 if (show_param
|| !hide_param
) {
380 cb
.add_parameter (p
);
390 private bool is_reference_type (string cname
) {
391 var st_attributes
= get_attributes (cname
);
392 if (st_attributes
!= null) {
393 foreach (string attr
in st_attributes
) {
394 var nv
= attr
.split ("=", 2);
395 if (nv
[0] == "is_value_type" && eval (nv
[1]) == "1") {
403 private void parse_struct (IdlNodeStruct st_node
, Namespace ns
, IdlModule module
) {
404 weak IdlNode node
= (IdlNode
) st_node
;
406 if (st_node
.deprecated
) {
410 string name
= fix_type_name (node
.name
, ns
);
412 if (!is_reference_type (node
.name
)) {
413 var st
= ns
.scope
.lookup (name
) as Struct
;
415 st
= new
Struct (name
, current_source_reference
);
416 st
.access
= SymbolAccessibility
.PUBLIC
;
418 var st_attributes
= get_attributes (node
.name
);
419 if (st_attributes
!= null) {
420 foreach (string attr
in st_attributes
) {
421 var nv
= attr
.split ("=", 2);
422 if (nv
[0] == "cheader_filename") {
423 st
.add_cheader_filename (eval (nv
[1]));
424 } else if (nv
[0] == "hidden") {
425 if (eval (nv
[1]) == "1") {
428 } else if (nv
[0] == "simple_type") {
429 if (eval (nv
[1]) == "1") {
430 st
.set_simple_type (true);
432 } else if (nv
[0] == "immutable") {
433 if (eval (nv
[1]) == "1") {
434 st
.is_immutable
= true;
436 } else if (nv
[0] == "has_type_id") {
437 if (eval (nv
[1]) == "0") {
438 st
.has_type_id
= false;
440 } else if (nv
[0] == "type_id") {
441 st
.set_type_id (eval (nv
[1]));
442 } else if (nv
[0] == "has_copy_function") {
443 if (eval (nv
[1]) == "0") {
444 st
.has_copy_function
= false;
446 } else if (nv
[0] == "has_destroy_function") {
447 if (eval (nv
[1]) == "0") {
448 st
.has_destroy_function
= false;
455 current_source_file
.add_node (st
);
458 current_data_type
= st
;
460 foreach (weak IdlNode member
in st_node
.members
) {
461 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
462 var m
= parse_function ((IdlNodeFunction
) member
);
466 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
467 var f
= parse_field ((IdlNodeField
) member
);
474 current_data_type
= null;
476 bool ref_function_void
= false;
477 string ref_function
= null;
478 string unref_function
= null;
479 string copy_function
= null;
480 string free_function
= null;
482 var cl
= ns
.scope
.lookup (name
) as Class
;
484 string base_class
= null;
486 cl
= new
Class (name
, current_source_reference
);
487 cl
.access
= SymbolAccessibility
.PUBLIC
;
488 cl
.is_compact
= true;
490 var cl_attributes
= get_attributes (node
.name
);
491 if (cl_attributes
!= null) {
492 foreach (string attr
in cl_attributes
) {
493 var nv
= attr
.split ("=", 2);
494 if (nv
[0] == "cheader_filename") {
495 cl
.add_cheader_filename (eval (nv
[1]));
496 } else if (nv
[0] == "base_class") {
497 base_class
= eval (nv
[1]);
498 } else if (nv
[0] == "hidden") {
499 if (eval (nv
[1]) == "1") {
502 } else if (nv
[0] == "is_immutable") {
503 if (eval (nv
[1]) == "1") {
504 cl
.is_immutable
= true;
506 } else if (nv
[0] == "const_cname") {
507 cl
.const_cname
= eval (nv
[1]);
508 } else if (nv
[0] == "is_fundamental") {
509 if (eval (nv
[1]) == "1") {
510 cl
.is_compact
= false;
512 } else if (nv
[0] == "abstract" && base_class
!= null) {
513 if (eval (nv
[1]) == "1") {
514 cl
.is_abstract
= true;
516 } else if (nv
[0] == "free_function") {
517 free_function
= eval (nv
[1]);
518 } else if (nv
[0] == "ref_function") {
519 ref_function
= eval (nv
[1]);
520 } else if (nv
[0] == "unref_function") {
521 unref_function
= eval (nv
[1]);
522 } else if (nv
[0] == "copy_function") {
523 copy_function
= eval (nv
[1]);
524 } else if (nv
[0] == "ref_function_void") {
525 if (eval (nv
[1]) == "1") {
526 ref_function_void
= true;
533 current_source_file
.add_node (cl
);
535 if (base_class
!= null) {
536 var parent
= parse_type_string (base_class
);
537 cl
.add_base_type (parent
);
541 current_data_type
= cl
;
543 foreach (weak IdlNode member
in st_node
.members
) {
544 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
545 if ((ref_function
== null) && (member
.name
== "ref")) {
546 ref_function
= ((IdlNodeFunction
) member
).symbol
;
547 ref_function_void
= (parse_type (((IdlNodeFunction
) member
).result
.type
) is VoidType
);
548 } else if ((unref_function
== null) && (member
.name
== "unref")) {
549 unref_function
= ((IdlNodeFunction
) member
).symbol
;
550 } else if ((free_function
== null) && (member
.name
== "free" || member
.name
== "destroy")) {
551 free_function
= ((IdlNodeFunction
) member
).symbol
;
553 if ((copy_function
== null) && (member
.name
== "copy")) {
554 copy_function
= ((IdlNodeFunction
) member
).symbol
;
556 var m
= parse_function ((IdlNodeFunction
) member
);
561 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
562 var f
= parse_field ((IdlNodeField
) member
);
569 if (ref_function
!= null) {
570 cl
.set_ref_function (ref_function
);
571 cl
.ref_function_void
= ref_function_void
;
573 if (copy_function
!= null) {
574 cl
.set_dup_function (copy_function
);
576 if (unref_function
!= null) {
577 cl
.set_unref_function (unref_function
);
578 } else if (free_function
!= null) {
579 cl
.set_free_function (free_function
);
582 current_data_type
= null;
586 private void parse_union (IdlNodeUnion un_node
, Namespace ns
, IdlModule module
) {
587 weak IdlNode node
= (IdlNode
) un_node
;
589 if (un_node
.deprecated
) {
593 string name
= fix_type_name (node
.name
, ns
);
595 if (!is_reference_type (node
.name
)) {
596 var st
= ns
.scope
.lookup (name
) as Struct
;
598 st
= new
Struct (name
, current_source_reference
);
599 st
.access
= SymbolAccessibility
.PUBLIC
;
601 var st_attributes
= get_attributes (node
.name
);
602 if (st_attributes
!= null) {
603 foreach (string attr
in st_attributes
) {
604 var nv
= attr
.split ("=", 2);
605 if (nv
[0] == "cheader_filename") {
606 st
.add_cheader_filename (eval (nv
[1]));
607 } else if (nv
[0] == "hidden") {
608 if (eval (nv
[1]) == "1") {
616 current_source_file
.add_node (st
);
619 current_data_type
= st
;
621 foreach (weak IdlNode member
in un_node
.members
) {
622 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
623 var m
= parse_function ((IdlNodeFunction
) member
);
627 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
628 var f
= parse_field ((IdlNodeField
) member
);
635 current_data_type
= null;
637 var cl
= ns
.scope
.lookup (name
) as Class
;
639 cl
= new
Class (name
, current_source_reference
);
640 cl
.access
= SymbolAccessibility
.PUBLIC
;
641 cl
.is_compact
= true;
643 var cl_attributes
= get_attributes (node
.name
);
644 if (cl_attributes
!= null) {
645 foreach (string attr
in cl_attributes
) {
646 var nv
= attr
.split ("=", 2);
647 if (nv
[0] == "cheader_filename") {
648 cl
.add_cheader_filename (eval (nv
[1]));
649 } else if (nv
[0] == "hidden") {
650 if (eval (nv
[1]) == "1") {
658 current_source_file
.add_node (cl
);
661 current_data_type
= cl
;
663 bool ref_function_void
= false;
664 string ref_function
= null;
665 string unref_function
= null;
666 string copy_function
= null;
667 string free_function
= null;
669 foreach (weak IdlNode member
in un_node
.members
) {
670 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
671 if (member
.name
== "ref") {
672 ref_function
= ((IdlNodeFunction
) member
).symbol
;
673 ref_function_void
= (parse_type (((IdlNodeFunction
) member
).result
.type
) is VoidType
);
674 } else if (member
.name
== "unref") {
675 unref_function
= ((IdlNodeFunction
) member
).symbol
;
676 } else if (member
.name
== "free" || member
.name
== "destroy") {
677 free_function
= ((IdlNodeFunction
) member
).symbol
;
679 if (member
.name
== "copy") {
680 copy_function
= ((IdlNodeFunction
) member
).symbol
;
682 var m
= parse_function ((IdlNodeFunction
) member
);
687 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
688 var f
= parse_field ((IdlNodeField
) member
);
695 if (ref_function
!= null) {
696 cl
.set_ref_function (ref_function
);
697 cl
.ref_function_void
= ref_function_void
;
699 if (copy_function
!= null) {
700 cl
.set_dup_function (copy_function
);
702 if (unref_function
!= null) {
703 cl
.set_unref_function (unref_function
);
704 } else if (free_function
!= null) {
705 cl
.set_free_function (free_function
);
708 current_data_type
= null;
712 private void parse_boxed (IdlNodeBoxed boxed_node
, Namespace ns
, IdlModule module
) {
713 weak IdlNode node
= (IdlNode
) boxed_node
;
715 string name
= fix_type_name (node
.name
, ns
);
717 var node_attributes
= get_attributes (node
.name
);
718 if (node_attributes
!= null) {
719 foreach (string attr
in node_attributes
) {
720 var nv
= attr
.split ("=", 2);
721 if (nv
[0] == "hidden") {
727 if (!is_reference_type (node
.name
)) {
728 var st
= ns
.scope
.lookup (name
) as Struct
;
730 st
= new
Struct (name
, current_source_reference
);
731 st
.access
= SymbolAccessibility
.PUBLIC
;
733 var st_attributes
= get_attributes (node
.name
);
734 if (st_attributes
!= null) {
735 foreach (string attr
in st_attributes
) {
736 var nv
= attr
.split ("=", 2);
737 if (nv
[0] == "cheader_filename") {
738 st
.add_cheader_filename (eval (nv
[1]));
739 } else if (nv
[0] == "immutable") {
740 if (eval (nv
[1]) == "1") {
741 st
.is_immutable
= true;
743 } else if (nv
[0] == "has_copy_function") {
744 if (eval (nv
[1]) == "0") {
745 st
.has_copy_function
= false;
747 } else if (nv
[0] == "has_destroy_function") {
748 if (eval (nv
[1]) == "0") {
749 st
.has_destroy_function
= false;
756 st
.set_type_id (st
.get_upper_case_cname ("TYPE_"));
757 current_source_file
.add_node (st
);
760 current_data_type
= st
;
762 foreach (weak IdlNode member
in boxed_node
.members
) {
763 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
764 var m
= parse_function ((IdlNodeFunction
) member
);
768 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
769 var f
= parse_field ((IdlNodeField
) member
);
776 current_data_type
= null;
778 var cl
= ns
.scope
.lookup (name
) as Class
;
780 cl
= new
Class (name
, current_source_reference
);
781 cl
.access
= SymbolAccessibility
.PUBLIC
;
782 cl
.is_compact
= true;
784 var cl_attributes
= get_attributes (node
.name
);
785 if (cl_attributes
!= null) {
786 foreach (string attr
in cl_attributes
) {
787 var nv
= attr
.split ("=", 2);
788 if (nv
[0] == "cheader_filename") {
789 cl
.add_cheader_filename (eval (nv
[1]));
790 } else if (nv
[0] == "is_immutable") {
791 if (eval (nv
[1]) == "1") {
792 cl
.is_immutable
= true;
794 } else if (nv
[0] == "const_cname") {
795 cl
.const_cname
= eval (nv
[1]);
801 cl
.set_type_id (cl
.get_upper_case_cname ("TYPE_"));
802 current_source_file
.add_node (cl
);
805 current_data_type
= cl
;
807 bool ref_function_void
= false;
808 string ref_function
= null;
809 string unref_function
= null;
810 string copy_function
= null;
811 string free_function
= null;
813 foreach (weak IdlNode member
in boxed_node
.members
) {
814 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
815 if (member
.name
== "ref") {
816 ref_function
= ((IdlNodeFunction
) member
).symbol
;
817 ref_function_void
= (parse_type (((IdlNodeFunction
) member
).result
.type
) is VoidType
);
818 } else if (member
.name
== "unref") {
819 unref_function
= ((IdlNodeFunction
) member
).symbol
;
820 } else if (member
.name
== "free" || member
.name
== "destroy") {
821 free_function
= ((IdlNodeFunction
) member
).symbol
;
823 if (member
.name
== "copy") {
824 copy_function
= ((IdlNodeFunction
) member
).symbol
;
826 var m
= parse_function ((IdlNodeFunction
) member
);
831 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
832 var f
= parse_field ((IdlNodeField
) member
);
839 if (ref_function
!= null) {
840 cl
.set_ref_function (ref_function
);
841 cl
.ref_function_void
= ref_function_void
;
843 if (copy_function
!= null) {
844 cl
.set_dup_function (copy_function
);
846 if (unref_function
!= null) {
847 cl
.set_unref_function (unref_function
);
848 } else if (free_function
!= null) {
849 cl
.set_free_function (free_function
);
852 current_data_type
= null;
856 private TypeSymbol?
parse_enum (IdlNodeEnum en_node
) {
857 weak IdlNode node
= (IdlNode
) en_node
;
859 var en
= new
Enum (node
.name
, current_source_reference
);
860 en
.access
= SymbolAccessibility
.PUBLIC
;
861 en
.has_type_id
= (en_node
.gtype_name
!= null && en_node
.gtype_name
!= "");
863 string common_prefix
= null;
865 foreach (weak IdlNode value
in en_node
.values
) {
866 if (common_prefix
== null) {
867 common_prefix
= value
.name
;
868 while (common_prefix
.len () > 0 && !common_prefix
.has_suffix ("_")) {
869 // FIXME: could easily be made faster
870 common_prefix
= common_prefix
.ndup (common_prefix
.size () - 1);
873 while (!value
.name
.has_prefix (common_prefix
)) {
874 common_prefix
= common_prefix
.ndup (common_prefix
.size () - 1);
877 while (common_prefix
.len () > 0 && (!common_prefix
.has_suffix ("_") ||
878 (value
.name
.offset (common_prefix
.length
).get_char ().isdigit ()) && (value
.name
.len () - common_prefix
.len ()) <= 1)) {
879 // enum values may not consist solely of digits
880 common_prefix
= common_prefix
.ndup (common_prefix
.size () - 1);
884 bool is_errordomain
= false;
886 var cheader_filenames
= new ArrayList
<string> ();
888 var en_attributes
= get_attributes (node
.name
);
889 if (en_attributes
!= null) {
890 foreach (string attr
in en_attributes
) {
891 var nv
= attr
.split ("=", 2);
892 if (nv
[0] == "common_prefix") {
893 common_prefix
= eval (nv
[1]);
894 } else if (nv
[0] == "cheader_filename") {
895 cheader_filenames
.add (eval (nv
[1]));
896 en
.add_cheader_filename (eval (nv
[1]));
897 } else if (nv
[0] == "hidden") {
898 if (eval (nv
[1]) == "1") {
901 } else if (nv
[0] == "rename_to") {
902 en
.name
= eval (nv
[1]);
903 } else if (nv
[0] == "errordomain") {
904 if (eval (nv
[1]) == "1") {
905 is_errordomain
= true;
907 } else if (nv
[0] == "to_string") {
908 var return_type
= new
UnresolvedType ();
909 return_type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
910 return_type
.value_owned
= false;
911 var m
= new
Method ("to_string", return_type
, current_source_reference
);
912 m
.access
= SymbolAccessibility
.PUBLIC
;
913 m
.set_cname (eval(nv
[1]));
919 en
.set_cprefix (common_prefix
);
921 foreach (weak IdlNode value2
in en_node
.values
) {
922 var ev
= new
EnumValue (value2
.name
.offset (common_prefix
.len ()));
926 if (is_errordomain
) {
927 var ed
= new
ErrorDomain (en
.name
, current_source_reference
);
928 ed
.access
= SymbolAccessibility
.PUBLIC
;
929 ed
.set_cprefix (common_prefix
);
931 foreach (string filename
in cheader_filenames
) {
932 ed
.add_cheader_filename (filename
);
935 foreach (EnumValue ev
in en
.get_values ()) {
936 ed
.add_code (new
ErrorCode (ev
.name
));
945 private void parse_object (IdlNodeInterface node
, Namespace ns
, IdlModule module
) {
946 string name
= fix_type_name (((IdlNode
) node
).name
, ns
);
948 string base_class
= null;
950 var cl
= ns
.scope
.lookup (name
) as Class
;
952 cl
= new
Class (name
, current_source_reference
);
953 cl
.access
= SymbolAccessibility
.PUBLIC
;
955 var attributes
= get_attributes (node
.gtype_name
);
956 if (attributes
!= null) {
957 foreach (string attr
in attributes
) {
958 var nv
= attr
.split ("=", 2);
959 if (nv
[0] == "cheader_filename") {
960 cl
.add_cheader_filename (eval (nv
[1]));
961 } else if (nv
[0] == "base_class") {
962 base_class
= eval (nv
[1]);
963 } else if (nv
[0] == "hidden") {
964 if (eval (nv
[1]) == "1") {
967 } else if (nv
[0] == "type_check_function") {
968 cl
.type_check_function
= eval (nv
[1]);
969 } else if (nv
[0] == "abstract") {
970 if (eval (nv
[1]) == "1") {
971 cl
.is_abstract
= true;
978 current_source_file
.add_node (cl
);
981 if (base_class
!= null) {
982 var parent
= parse_type_string (base_class
);
983 cl
.add_base_type (parent
);
984 } else if (node
.parent
!= null) {
985 var parent
= parse_type_string (node
.parent
);
986 cl
.add_base_type (parent
);
988 var gobject_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "Object");
989 cl
.add_base_type (new UnresolvedType
.from_symbol (gobject_symbol
));
992 foreach (string iface_name
in node
.interfaces
) {
993 var iface
= parse_type_string (iface_name
);
994 cl
.add_base_type (iface
);
997 current_data_type
= cl
;
999 current_type_symbol_set
= new HashSet
<string> (str_hash
, str_equal
);
1000 var current_type_func_map
= new HashMap
<string,weak IdlNodeFunction
> (str_hash
, str_equal
);
1001 var current_type_vfunc_map
= new HashMap
<string,string> (str_hash
, str_equal
);
1003 foreach (weak IdlNode member
in node
.members
) {
1004 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1005 current_type_func_map
.set (member
.name
, (IdlNodeFunction
) member
);
1007 if (member
.type
== IdlNodeTypeId
.VFUNC
) {
1008 current_type_vfunc_map
.set (member
.name
, "1");
1012 foreach (weak IdlNode member
in node
.members
) {
1013 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1014 // Ignore if vfunc (handled below)
1015 if (!current_type_vfunc_map
.contains (member
.name
)) {
1016 var m
= parse_function ((IdlNodeFunction
) member
);
1021 } else if (member
.type
== IdlNodeTypeId
.VFUNC
) {
1022 var m
= parse_virtual ((IdlNodeVFunc
) member
, current_type_func_map
.get (member
.name
));
1026 } else if (member
.type
== IdlNodeTypeId
.PROPERTY
) {
1027 var prop
= parse_property ((IdlNodeProperty
) member
);
1029 cl
.add_property (prop
);
1031 } else if (member
.type
== IdlNodeTypeId
.SIGNAL
) {
1032 var sig
= parse_signal ((IdlNodeSignal
) member
);
1034 cl
.add_signal (sig
);
1039 foreach (weak IdlNode member
in node
.members
) {
1040 if (member
.type
== IdlNodeTypeId
.FIELD
) {
1041 if (!current_type_symbol_set
.contains (member
.name
)) {
1042 var f
= parse_field ((IdlNodeField
) member
);
1050 foreach (Property prop
in cl
.get_properties ()) {
1051 var getter
= "get_%s".printf (prop
.name
);
1053 if (prop
.get_accessor
!= null && !current_type_symbol_set
.contains (getter
)) {
1054 prop
.no_accessor_method
= true;
1057 var setter
= "set_%s".printf (prop
.name
);
1059 if (prop
.set_accessor
!= null && prop
.set_accessor
.writable
1060 && !current_type_symbol_set
.contains (setter
)) {
1061 prop
.no_accessor_method
= true;
1064 if (prop
.no_accessor_method
&& prop
.get_accessor
!= null) {
1065 prop
.get_accessor
.value_type
.value_owned
= true;
1069 handle_async_methods (cl
);
1071 current_data_type
= null;
1072 current_type_symbol_set
= null;
1075 private void parse_interface (IdlNodeInterface node
, Namespace ns
, IdlModule module
) {
1076 string name
= fix_type_name (node
.gtype_name
, ns
);
1078 var iface
= ns
.scope
.lookup (name
) as Interface
;
1079 if (iface
== null) {
1080 iface
= new
Interface (name
, current_source_reference
);
1081 iface
.access
= SymbolAccessibility
.PUBLIC
;
1083 var attributes
= get_attributes (node
.gtype_name
);
1084 if (attributes
!= null) {
1085 foreach (string attr
in attributes
) {
1086 var nv
= attr
.split ("=", 2);
1087 if (nv
[0] == "cheader_filename") {
1088 iface
.add_cheader_filename (eval (nv
[1]));
1089 } else if (nv
[0] == "lower_case_csuffix") {
1090 iface
.set_lower_case_csuffix (eval (nv
[1]));
1095 foreach (string prereq_name
in node
.prerequisites
) {
1096 var prereq
= parse_type_string (prereq_name
);
1097 iface
.add_prerequisite (prereq
);
1100 ns
.add_interface (iface
);
1101 current_source_file
.add_node (iface
);
1104 current_data_type
= iface
;
1106 var current_type_func_map
= new HashMap
<string,weak IdlNodeFunction
> (str_hash
, str_equal
);
1107 var current_type_vfunc_map
= new HashMap
<string,string> (str_hash
, str_equal
);
1109 foreach (weak IdlNode member
in node
.members
) {
1110 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1111 current_type_func_map
.set (member
.name
, (IdlNodeFunction
) member
);
1113 if (member
.type
== IdlNodeTypeId
.VFUNC
) {
1114 current_type_vfunc_map
.set (member
.name
, "1");
1118 foreach (weak IdlNode member
in node
.members
) {
1119 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1120 // Ignore if vfunc (handled below)
1121 if (!current_type_vfunc_map
.contains (member
.name
)) {
1122 var m
= parse_function ((IdlNodeFunction
) member
, true);
1124 iface
.add_method (m
);
1127 } else if (member
.type
== IdlNodeTypeId
.VFUNC
) {
1128 var m
= parse_virtual ((IdlNodeVFunc
) member
, current_type_func_map
.get (member
.name
), true);
1130 iface
.add_method (m
);
1132 } else if (member
.type
== IdlNodeTypeId
.PROPERTY
) {
1133 var prop
= parse_property ((IdlNodeProperty
) member
);
1135 iface
.add_property (prop
);
1137 } else if (member
.type
== IdlNodeTypeId
.SIGNAL
) {
1138 var sig
= parse_signal ((IdlNodeSignal
) member
);
1140 iface
.add_signal (sig
);
1141 sig
.is_virtual
= false;
1146 handle_async_methods (iface
);
1148 current_data_type
= null;
1151 void handle_async_methods (ObjectTypeSymbol type_symbol
) {
1152 foreach (Method m
in type_symbol
.get_methods ()) {
1154 string finish_method_base
;
1155 if (m
.name
.has_suffix ("_async")) {
1156 finish_method_base
= m
.name
.substring (0, m
.name
.length
- "_async".length
);
1158 finish_method_base
= m
.name
;
1160 var finish_method
= type_symbol
.scope
.lookup (finish_method_base
+ "_finish") as Method
;
1161 if (finish_method
!= null) {
1162 m
.return_type
= finish_method
.return_type
.copy ();
1163 foreach (var param
in finish_method
.get_parameters ()) {
1164 if (param
.direction
== ParameterDirection
.OUT
) {
1165 var async_param
= param
.copy ();
1166 if (m
.scope
.lookup (param
.name
) != null) {
1167 // parameter name conflict
1168 async_param
.name
+= "_out";
1170 m
.add_parameter (async_param
);
1173 foreach (DataType error_type
in finish_method
.get_error_types ()) {
1174 m
.add_error_type (error_type
.copy ());
1181 private DataType?
parse_type (IdlNodeType type_node
, out ParameterDirection direction
= null) {
1182 ParameterDirection dir
= ParameterDirection
.IN
;
1184 var type
= new
UnresolvedType ();
1185 if (type_node
.tag
== TypeTag
.VOID
) {
1186 if (type_node
.is_pointer
) {
1187 return new
PointerType (new
VoidType ());
1189 return new
VoidType ();
1191 } else if (type_node
.tag
== TypeTag
.BOOLEAN
) {
1192 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "bool");
1193 } else if (type_node
.tag
== TypeTag
.INT8
) {
1194 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "char");
1195 } else if (type_node
.tag
== TypeTag
.UINT8
) {
1196 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uchar");
1197 } else if (type_node
.tag
== TypeTag
.INT16
) {
1198 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int16");
1199 } else if (type_node
.tag
== TypeTag
.UINT16
) {
1200 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint16");
1201 } else if (type_node
.tag
== TypeTag
.INT32
) {
1202 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int32");
1203 } else if (type_node
.tag
== TypeTag
.UINT32
) {
1204 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint32");
1205 } else if (type_node
.tag
== TypeTag
.INT64
) {
1206 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int64");
1207 } else if (type_node
.tag
== TypeTag
.UINT64
) {
1208 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint64");
1209 } else if (type_node
.tag
== TypeTag
.INT
) {
1210 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int");
1211 } else if (type_node
.tag
== TypeTag
.UINT
) {
1212 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint");
1213 } else if (type_node
.tag
== TypeTag
.LONG
) {
1214 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "long");
1215 } else if (type_node
.tag
== TypeTag
.ULONG
) {
1216 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ulong");
1217 } else if (type_node
.tag
== TypeTag
.SSIZE
) {
1218 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ssize_t");
1219 } else if (type_node
.tag
== TypeTag
.SIZE
) {
1220 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "size_t");
1221 } else if (type_node
.tag
== TypeTag
.FLOAT
) {
1222 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "float");
1223 } else if (type_node
.tag
== TypeTag
.DOUBLE
) {
1224 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "double");
1225 } else if (type_node
.tag
== TypeTag
.UTF8
) {
1226 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1227 } else if (type_node
.tag
== TypeTag
.FILENAME
) {
1228 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1229 } else if (type_node
.tag
== TypeTag
.ARRAY
) {
1230 var element_type
= parse_type (type_node
.parameter_type1
);
1231 type
= element_type as UnresolvedType
;
1233 return element_type
;
1235 return new
ArrayType (element_type
, 1, element_type
.source_reference
);
1236 } else if (type_node
.tag
== TypeTag
.LIST
) {
1237 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "List");
1238 } else if (type_node
.tag
== TypeTag
.SLIST
) {
1239 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "SList");
1240 } else if (type_node
.tag
== TypeTag
.HASH
) {
1241 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "HashTable");
1242 } else if (type_node
.tag
== TypeTag
.ERROR
) {
1243 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "Error");
1244 } else if (type_node
.is_interface
) {
1245 var n
= type_node
.@
interface;
1251 if (n
.has_prefix ("const-")) {
1252 n
= n
.offset ("const-".len ());
1255 if (type_node
.is_pointer
&&
1256 (n
== "gchar" || n
== "char")) {
1257 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1258 if (type_node
.unparsed
.has_suffix ("**")) {
1259 dir
= ParameterDirection
.OUT
;
1261 } else if (n
== "gunichar") {
1262 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "unichar");
1263 } else if (n
== "gchar") {
1264 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "char");
1265 } else if (n
== "guchar" || n
== "guint8") {
1266 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uchar");
1267 if (type_node
.is_pointer
) {
1268 return new
ArrayType (type
, 1, type
.source_reference
);
1270 } else if (n
== "gushort") {
1271 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ushort");
1272 } else if (n
== "gshort") {
1273 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "short");
1274 } else if (n
== "gconstpointer" || n
== "void") {
1275 return new
PointerType (new
VoidType ());
1276 } else if (n
== "goffset" || n
== "off_t") {
1277 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int64");
1278 } else if (n
== "value_array") {
1279 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "ValueArray");
1280 } else if (n
== "time_t") {
1281 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ulong");
1282 } else if (n
== "socklen_t") {
1283 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint32");
1284 } else if (n
== "mode_t") {
1285 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint");
1286 } else if (n
== "gint" || n
== "pid_t") {
1287 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int");
1288 } else if (n
== "unsigned" || n
== "unsigned-int") {
1289 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint");
1290 } else if (n
== "FILE") {
1291 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "FileStream");
1292 } else if (n
== "struct") {
1293 return new
PointerType (new
VoidType ());
1294 } else if (n
== "iconv_t") {
1295 return new
PointerType (new
VoidType ());
1296 } else if (n
== "GType") {
1297 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "Type");
1298 if (type_node
.is_pointer
) {
1299 return new
ArrayType (type
, 1, type
.source_reference
);
1301 } else if (n
== "GStrv") {
1302 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1303 return new
ArrayType (type
, 1, type
.source_reference
);
1305 var named_type
= parse_type_string (n
);
1306 type
= named_type as UnresolvedType
;
1310 if (is_simple_type (n
)) {
1311 if (type_node
.is_pointer
) {
1312 dir
= ParameterDirection
.OUT
;
1314 } else if (type_node
.unparsed
.has_suffix ("**")) {
1315 dir
= ParameterDirection
.OUT
;
1319 stdout
.printf ("%d\n", type_node
.tag
);
1321 if (&direction
!= null) {
1327 private bool is_simple_type (string type_name
) {
1328 var st
= cname_type_map
[type_name
] as Struct
;
1329 if (st
!= null && st
.is_simple_type ()) {
1336 private DataType
parse_type_string (string n
) {
1337 if (n
== "va_list") {
1339 return new
PointerType (new
VoidType ());
1342 var type
= new
UnresolvedType ();
1344 var dt
= cname_type_map
[n
];
1346 UnresolvedSymbol parent_symbol
= null;
1347 if (dt
.parent_symbol
.name
!= null) {
1348 parent_symbol
= new
UnresolvedSymbol (null, dt
.parent_symbol
.name
);
1350 type
.unresolved_symbol
= new
UnresolvedSymbol (parent_symbol
, dt
.name
);
1354 var type_attributes
= get_attributes (n
);
1356 string ns_name
= null;
1358 if (null != type_attributes
) {
1359 foreach (string attr
in type_attributes
) {
1360 var nv
= attr
.split ("=", 2);
1362 if (nv
[0] == "cprefix") {
1363 type
.unresolved_symbol
= new
UnresolvedSymbol (null, n
.offset (eval (nv
[1]).len ()));
1364 } else if (nv
[0] == "name") {
1365 type
.unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1366 } else if (nv
[0] == "namespace") {
1367 ns_name
= eval (nv
[1]);
1368 } else if (nv
[0] == "rename_to") {
1369 type
.unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1374 if (type
.unresolved_symbol
!= null) {
1375 if (type
.unresolved_symbol
.name
== "pointer") {
1376 return new
PointerType (new
VoidType ());
1378 if (ns_name
!= null) {
1379 type
.unresolved_symbol
.inner
= new
UnresolvedSymbol (null, ns_name
);
1384 if (n
.has_prefix (current_namespace
.name
)) {
1385 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, current_namespace
.name
), n
.offset (current_namespace
.name
.len ()));
1386 } else if (n
.has_prefix ("G")) {
1387 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), n
.offset (1));
1389 var name_parts
= n
.split (".", 2);
1390 if (name_parts
[1] == null) {
1391 type
.unresolved_symbol
= new
UnresolvedSymbol (null, name_parts
[0]);
1393 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, name_parts
[0]), name_parts
[1]);
1400 private DataType?
parse_param (IdlNodeParam param
, out ParameterDirection direction
= null) {
1401 var type
= parse_type (param
.type
, out direction
);
1403 // disable for now as null_ok not yet correctly set
1404 // type.non_null = !param.null_ok;
1409 private Method?
create_method (string name
, string symbol
, IdlNodeParam? res
, GLib
.List
<IdlNodeParam
>? parameters
, bool is_constructor
, bool is_interface
) {
1410 DataType return_type
= null;
1412 return_type
= parse_param (res
);
1416 if (!is_interface
&& (is_constructor
|| name
.has_prefix ("new"))) {
1417 m
= new
CreationMethod (null, name
, current_source_reference
);
1418 m
.has_construct_function
= false;
1419 if (m
.name
== "new") {
1421 } else if (m
.name
.has_prefix ("new_")) {
1422 m
.name
= m
.name
.offset ("new_".len ());
1424 // For classes, check whether a creation method return type equals to the
1425 // type of the class created. If the types do not match (e.g. in most
1426 // gtk widgets) add an attribute to the creation method indicating the used
1428 if (current_data_type is Class
&& res
!= null) {
1429 if ("%s*".printf (current_data_type
.get_cname()) != res
.type
.unparsed
) {
1430 ((CreationMethod
)m
).custom_return_type_cname
= res
.type
.unparsed
;
1434 m
= new
Method (name
, return_type
, current_source_reference
);
1436 m
.access
= SymbolAccessibility
.PUBLIC
;
1438 if (current_type_symbol_set
!= null) {
1439 current_type_symbol_set
.add (name
);
1442 if (current_data_type
!= null) {
1443 var sig_attributes
= get_attributes ("%s::%s".printf (current_data_type
.get_cname (), name
));
1444 if (sig_attributes
!= null) {
1445 foreach (string attr
in sig_attributes
) {
1446 var nv
= attr
.split ("=", 2);
1447 if (nv
[0] == "has_emitter" && eval (nv
[1]) == "1") {
1454 bool add_ellipsis
= false;
1455 bool suppress_throws
= false;
1457 var attributes
= get_attributes (symbol
);
1458 if (attributes
!= null) {
1459 foreach (string attr
in attributes
) {
1460 var nv
= attr
.split ("=", 2);
1461 if (nv
[0] == "name") {
1462 m
.set_cname (m
.name
);
1463 m
.name
= eval (nv
[1]);
1464 } else if (nv
[0] == "hidden") {
1465 if (eval (nv
[1]) == "1") {
1468 } else if (nv
[0] == "ellipsis") {
1469 if (eval (nv
[1]) == "1") {
1470 add_ellipsis
= true;
1472 } else if (nv
[0] == "printf_format") {
1473 if (eval (nv
[1]) == "1") {
1474 m
.printf_format
= true;
1476 } else if (nv
[0] == "transfer_ownership") {
1477 if (eval (nv
[1]) == "1") {
1478 return_type
.value_owned
= true;
1480 } else if (nv
[0] == "nullable") {
1481 if (eval (nv
[1]) == "1") {
1482 return_type
.nullable
= true;
1484 } else if (nv
[0] == "sentinel") {
1485 m
.sentinel
= eval (nv
[1]);
1486 } else if (nv
[0] == "is_array") {
1487 if (eval (nv
[1]) == "1") {
1488 return_type
= new
ArrayType (return_type
, 1, return_type
.source_reference
);
1489 m
.return_type
= return_type
;
1491 } else if (nv
[0] == "throws") {
1492 if (eval (nv
[1]) == "0") {
1493 suppress_throws
= true;
1495 } else if (nv
[0] == "no_array_length") {
1496 if (eval (nv
[1]) == "1") {
1497 m
.no_array_length
= true;
1499 } else if (nv
[0] == "array_null_terminated") {
1500 if (eval (nv
[1]) == "1") {
1501 m
.no_array_length
= true;
1502 m
.array_null_terminated
= true;
1504 } else if (nv
[0] == "type_name") {
1505 var sym
= new
UnresolvedSymbol (null, eval (nv
[1]));
1506 if (return_type is UnresolvedType
) {
1507 ((UnresolvedType
) return_type
).unresolved_symbol
= sym
;
1509 // Overwrite old return_type, so "type_name" must be before any
1510 // other return type modifying metadata
1511 m
.return_type
= return_type
= new UnresolvedType
.from_symbol (sym
, return_type
.source_reference
);
1513 } else if (nv
[0] == "type_arguments") {
1514 var type_args
= eval (nv
[1]).split (",");
1515 foreach (string type_arg
in type_args
) {
1516 var arg_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, type_arg
));
1517 arg_type
.value_owned
= true;
1518 return_type
.add_type_argument (arg_type
);
1520 } else if (nv
[0] == "cheader_filename") {
1521 m
.add_cheader_filename (eval (nv
[1]));
1522 } else if (nv
[0] == "abstract") {
1523 if (eval (nv
[1]) == "1") {
1524 m
.is_abstract
= true;
1526 } else if (nv
[0] == "virtual") {
1527 if (eval (nv
[1]) == "1") {
1528 m
.is_virtual
= true;
1530 } else if (nv
[0] == "vfunc_name") {
1531 m
.vfunc_name
= eval (nv
[1]);
1532 } else if (nv
[0] == "async") {
1533 if (eval (nv
[1]) == "1") {
1534 // force async function, even if it doesn't end in _async
1541 m
.set_cname (symbol
);
1544 FormalParameter last_param
= null;
1545 DataType last_param_type
= null;
1546 foreach (weak IdlNodeParam param
in parameters
) {
1547 weak IdlNode param_node
= (IdlNode
) param
;
1551 if (!(m is CreationMethod
) &&
1552 current_data_type
!= null &&
1553 param
.type
.is_interface
&&
1554 (param_node
.name
== "self" ||
1555 param
.type
.@
interface.has_suffix (current_data_type
.get_cname ()))) {
1558 } else if (!(m is CreationMethod
) &&
1559 current_data_type
!= null &&
1560 param
.type
.is_interface
&&
1561 (param_node
.name
== "klass" ||
1562 param
.type
.@
interface.has_suffix ("%sClass".printf(current_data_type
.get_cname ())))) {
1564 m
.binding
= MemberBinding
.CLASS
;
1565 if (m
.name
.has_prefix ("class_")) {
1566 m
.name
= m
.name
.substring ("class_".len (), m
.name
.len () - "class_".len ());
1571 m
.binding
= MemberBinding
.STATIC
;
1575 if (param
.type
.@
interface == "GAsyncReadyCallback" && (symbol
.has_suffix ("_async") || m
.coroutine
)) {
1581 if (suppress_throws
== false && param_is_exception (param
)) {
1582 m
.add_error_type (parse_type (param
.type
));
1586 string param_name
= param_node
.name
;
1587 if (param_name
== "result") {
1588 // avoid conflict with generated result variable
1589 param_name
= "_result";
1590 } else if (param_name
== "string") {
1591 // avoid conflict with string type
1594 ParameterDirection direction
;
1595 var param_type
= parse_param (param
, out direction
);
1596 var p
= new
FormalParameter (param_name
, param_type
);
1597 p
.direction
= direction
;
1599 bool hide_param
= false;
1600 bool show_param
= false;
1601 bool set_array_length_pos
= false;
1602 double array_length_pos
= 0;
1603 bool set_delegate_target_pos
= false;
1604 double delegate_target_pos
= 0;
1605 bool array_requested
= false;
1606 attributes
= get_attributes ("%s.%s".printf (symbol
, param_node
.name
));
1607 if (attributes
!= null) {
1608 foreach (string attr
in attributes
) {
1609 var nv
= attr
.split ("=", 2);
1610 if (nv
[0] == "is_array") {
1611 if (eval (nv
[1]) == "1") {
1612 param_type
= new
ArrayType (param_type
, 1, param_type
.source_reference
);
1613 p
.parameter_type
= param_type
;
1614 p
.direction
= ParameterDirection
.IN
;
1615 array_requested
= true;
1617 } else if (nv
[0] == "is_out") {
1618 if (eval (nv
[1]) == "1") {
1619 p
.direction
= ParameterDirection
.OUT
;
1620 if (!array_requested
&& param_type is ArrayType
) {
1621 var array_type
= (ArrayType
) param_type
;
1622 param_type
= array_type
.element_type
;
1623 p
.parameter_type
= param_type
;
1626 } else if (nv
[0] == "is_ref") {
1627 if (eval (nv
[1]) == "1") {
1628 p
.direction
= ParameterDirection
.REF
;
1629 if (!array_requested
&& param_type is ArrayType
) {
1630 var array_type
= (ArrayType
) param_type
;
1631 param_type
= array_type
.element_type
;
1632 p
.parameter_type
= param_type
;
1635 } else if (nv
[0] == "nullable") {
1636 if (eval (nv
[1]) == "1") {
1637 param_type
.nullable
= true;
1639 } else if (nv
[0] == "transfer_ownership") {
1640 if (eval (nv
[1]) == "1") {
1641 param_type
.value_owned
= true;
1643 } else if (nv
[0] == "takes_ownership") {
1644 if (eval (nv
[1]) == "1") {
1645 param_type
.value_owned
= true;
1647 } else if (nv
[0] == "value_owned") {
1648 if (eval (nv
[1]) == "0") {
1649 param_type
.value_owned
= false;
1650 } else if (eval (nv
[1]) == "1") {
1651 param_type
.value_owned
= true;
1653 } else if (nv
[0] == "hidden") {
1654 if (eval (nv
[1]) == "1") {
1656 } else if (eval (nv
[1]) == "0") {
1659 } else if (nv
[0] == "no_array_length") {
1660 if (eval (nv
[1]) == "1") {
1661 p
.no_array_length
= true;
1663 } else if (nv
[0] == "array_null_terminated") {
1664 if (eval (nv
[1]) == "1") {
1665 p
.no_array_length
= true;
1666 p
.array_null_terminated
= true;
1668 } else if (nv
[0] == "array_length_pos") {
1669 set_array_length_pos
= true;
1670 array_length_pos
= eval (nv
[1]).to_double ();
1671 } else if (nv
[0] == "delegate_target_pos") {
1672 set_delegate_target_pos
= true;
1673 delegate_target_pos
= eval (nv
[1]).to_double ();
1674 } else if (nv
[0] == "type_name") {
1675 ((UnresolvedType
) param_type
).unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1676 } else if (nv
[0] == "ctype") {
1677 p
.ctype
= eval (nv
[1]);
1678 } else if (nv
[0] == "type_arguments") {
1679 var type_args
= eval (nv
[1]).split (",");
1680 foreach (string type_arg
in type_args
) {
1681 var arg_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, type_arg
));
1682 arg_type
.value_owned
= true;
1683 param_type
.add_type_argument (arg_type
);
1689 if (last_param
!= null && p
.name
== "n_" + last_param
.name
) {
1690 if (!(last_param_type is ArrayType
)) {
1691 // last_param is array, p is array length
1692 last_param_type
= new
ArrayType (last_param_type
, 1, last_param_type
.source_reference
);
1693 last_param
.parameter_type
= last_param_type
;
1694 last_param
.direction
= ParameterDirection
.IN
;
1697 // hide array length param
1699 } else if (last_param
!= null && p
.name
== "user_data") {
1700 // last_param is delegate
1702 // hide deleate target param
1706 if (show_param
|| !hide_param
) {
1707 m
.add_parameter (p
);
1708 if (set_array_length_pos
) {
1709 p
.carray_length_parameter_position
= array_length_pos
;
1711 if (set_delegate_target_pos
) {
1712 p
.cdelegate_target_parameter_position
= delegate_target_pos
;
1717 last_param_type
= param_type
;
1721 // no parameters => static method
1722 m
.binding
= MemberBinding
.STATIC
;
1725 if (last_param
!= null && last_param
.name
.has_prefix ("first_")) {
1726 last_param
.ellipsis
= true;
1727 } else if (add_ellipsis
) {
1728 m
.add_parameter (new FormalParameter
.with_ellipsis ());
1734 private bool param_is_exception (IdlNodeParam param
) {
1735 if (!param
.type
.is_error
) {
1738 var s
= param
.type
.unparsed
.chomp ();
1739 if (s
.has_suffix ("**")) {
1745 private Method?
parse_function (IdlNodeFunction f
, bool is_interface
= false) {
1746 weak IdlNode node
= (IdlNode
) f
;
1752 return create_method (node
.name
, f
.symbol
, f
.result
, f
.parameters
, f
.is_constructor
, is_interface
);
1755 private Method
parse_virtual (IdlNodeVFunc v
, IdlNodeFunction? func
, bool is_interface
= false) {
1756 weak IdlNode node
= (IdlNode
) v
;
1757 string symbol
= "%s%s".printf (current_data_type
.get_lower_case_cprefix(), node
.name
);
1760 symbol
= func
.symbol
;
1763 Method m
= create_method (node
.name
, symbol
, v
.result
, func
!= null ? func
.parameters
: v
.parameters
, false, is_interface
);
1765 m
.binding
= MemberBinding
.INSTANCE
;
1766 m
.is_virtual
= !(m
.is_abstract
|| is_interface
);
1767 m
.is_abstract
= m
.is_abstract
|| is_interface
;
1769 var attributes
= get_attributes (symbol
);
1770 if (attributes
!= null) {
1771 foreach (string attr
in attributes
) {
1772 var nv
= attr
.split ("=", 2);
1773 if (nv
[0] == "virtual") {
1774 if (eval (nv
[1]) == "0") {
1775 m
.is_virtual
= false;
1776 m
.is_abstract
= false;
1783 m
.attributes
.append (new
Attribute ("NoWrapper", null));
1790 private string fix_prop_name (string name
) {
1791 var str
= new
StringBuilder ();
1795 while (i
.len () > 0) {
1796 unichar c
= i
.get_char ();
1800 str
.append_unichar (c
);
1809 private Property?
parse_property (IdlNodeProperty prop_node
) {
1810 weak IdlNode node
= (IdlNode
) prop_node
;
1812 if (prop_node
.deprecated
) {
1816 if (!prop_node
.readable
&& !prop_node
.writable
) {
1817 // buggy GIDL definition
1818 prop_node
.readable
= true;
1819 prop_node
.writable
= true;
1822 var prop
= new
Property (fix_prop_name (node
.name
), parse_type (prop_node
.type
), null, null, current_source_reference
);
1823 prop
.access
= SymbolAccessibility
.PUBLIC
;
1824 prop
.interface_only
= true;
1826 if (prop_node
.type
.is_interface
&& prop_node
.type
.interface == "GStrv") {
1827 prop
.no_array_length
= true;
1828 prop
.array_null_terminated
= true;
1831 if (prop_node
.readable
) {
1832 prop
.get_accessor
= new
PropertyAccessor (true, false, false, prop
.property_type
.copy (), null, null);
1834 if (prop_node
.writable
) {
1835 prop
.set_accessor
= new
PropertyAccessor (false, false, false, prop
.property_type
.copy (), null, null);
1836 if (prop_node
.construct_only
) {
1837 prop
.set_accessor
.construction
= true;
1839 prop
.set_accessor
.writable
= true;
1840 prop
.set_accessor
.construction
= prop_node
.@
construct;
1844 var attributes
= get_attributes ("%s:%s".printf (current_data_type
.get_cname (), node
.name
));
1845 if (attributes
!= null) {
1846 foreach (string attr
in attributes
) {
1847 var nv
= attr
.split ("=", 2);
1848 if (nv
[0] == "hidden") {
1849 if (eval (nv
[1]) == "1") {
1852 } else if (nv
[0] == "type_arguments") {
1853 var type_args
= eval (nv
[1]).split (",");
1854 foreach (string type_arg
in type_args
) {
1855 var arg_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, type_arg
));
1856 arg_type
.value_owned
= true;
1857 prop
.property_type
.add_type_argument (arg_type
);
1859 } else if (nv
[0] == "accessor_method") {
1860 if (eval (nv
[1]) == "0") {
1861 prop
.no_accessor_method
= true;
1863 } else if (nv
[0] == "owned_get") {
1864 if (eval (nv
[1]) == "1") {
1865 prop
.get_accessor
.value_type
.value_owned
= true;
1871 if (current_type_symbol_set
!= null) {
1872 current_type_symbol_set
.add (prop
.name
);
1878 private Constant?
parse_constant (IdlNodeConstant const_node
) {
1879 weak IdlNode node
= (IdlNode
) const_node
;
1881 var type
= parse_type (const_node
.type
);
1886 var c
= new
Constant (node
.name
, type
, null, current_source_reference
);
1889 string[] attributes
= get_attributes (node
.name
);
1890 if (attributes
!= null) {
1891 foreach (string attr
in attributes
) {
1892 var nv
= attr
.split ("=", 2);
1893 if (nv
[0] == "cheader_filename") {
1894 c
.add_cheader_filename (eval (nv
[1]));
1895 } else if (nv
[0] == "hidden") {
1896 if (eval (nv
[1]) == "1") {
1903 c
.access
= SymbolAccessibility
.PUBLIC
;
1908 private Field?
parse_field (IdlNodeField field_node
) {
1909 weak IdlNode node
= (IdlNode
) field_node
;
1910 bool unhidden
= false;
1912 var type
= parse_type (field_node
.type
);
1917 string cheader_filename
= null;
1918 string ctype
= null;
1919 bool array_null_terminated
= false;
1921 var attributes
= get_attributes ("%s.%s".printf (current_data_type
.get_cname (), node
.name
));
1922 if (attributes
!= null) {
1923 foreach (string attr
in attributes
) {
1924 var nv
= attr
.split ("=", 2);
1925 if (nv
[0] == "hidden") {
1926 if (eval (nv
[1]) == "1") {
1931 } else if (nv
[0] == "is_array") {
1932 if (eval (nv
[1]) == "1") {
1933 type
= new
ArrayType (type
, 1, type
.source_reference
);
1935 } else if (nv
[0] == "weak") {
1936 if (eval (nv
[1]) == "0") {
1937 type
.value_owned
= true;
1939 } else if (nv
[0] == "type_name") {
1940 ((UnresolvedType
) type
).unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1941 } else if (nv
[0] == "type_arguments") {
1942 var type_args
= eval (nv
[1]).split (",");
1943 foreach (string type_arg
in type_args
) {
1944 var arg_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, type_arg
));
1945 arg_type
.value_owned
= true;
1946 type
.add_type_argument (arg_type
);
1948 } else if (nv
[0] == "cheader_filename") {
1949 cheader_filename
= eval (nv
[1]);
1950 } else if (nv
[0] == "ctype") {
1951 ctype
= eval (nv
[1]);
1952 } else if (nv
[0] == "array_null_terminated") {
1953 if (eval (nv
[1]) == "1") {
1954 array_null_terminated
= true;
1960 if (node
.name
.has_prefix("_") && !unhidden
) {
1964 if (current_type_symbol_set
!= null) {
1965 current_type_symbol_set
.add (node
.name
);
1968 string field_name
= node
.name
;
1969 if (field_name
== "string") {
1970 // avoid conflict with string type
1974 var field
= new
Field (field_name
, type
, null, current_source_reference
);
1975 field
.access
= SymbolAccessibility
.PUBLIC
;
1977 if (field_name
!= node
.name
) {
1978 field
.set_cname (node
.name
);
1981 if (ctype
!= null) {
1982 field
.set_ctype (ctype
);
1985 if (cheader_filename
!= null) {
1986 field
.add_cheader_filename (cheader_filename
);
1989 field
.no_array_length
= true;
1990 if (array_null_terminated
) {
1991 field
.array_null_terminated
= true;
1997 private string[]?
get_attributes (string codenode
) {
1998 var attributes
= codenode_attributes_map
.get (codenode
);
2000 if (attributes
== null) {
2001 var dot_required
= (null != codenode
.chr (-1, '.'));
2002 var colon_required
= (null != codenode
.chr (-1, ':'));
2004 var pattern_specs
= codenode_attributes_patterns
.get_keys ();
2005 foreach (PatternSpec
* pattern
in pattern_specs
) {
2006 var pspec
= codenode_attributes_patterns
[pattern
];
2008 if ((dot_required
&& null == pspec
.chr (-1, '.')) ||
2009 (colon_required
&& null == pspec
.chr (-1, ':'))) {
2013 if (pattern
->match_string (codenode
)) {
2014 return get_attributes (pspec
);
2019 if (attributes
== null) {
2023 return attributes
.split (" ");
2026 private string eval (string s
) {
2027 return ((s
.size () >= 2) && s
.has_prefix ("\"") && s
.has_suffix ("\"")) ? s
.offset (1).ndup (s
.size () - 2) : s
;
2030 private Signal?
parse_signal (IdlNodeSignal sig_node
) {
2031 weak IdlNode node
= (IdlNode
) sig_node
;
2033 if (sig_node
.deprecated
|| sig_node
.result
== null) {
2037 var sig
= new
Signal (fix_prop_name (node
.name
), parse_param (sig_node
.result
), current_source_reference
);
2038 sig
.access
= SymbolAccessibility
.PUBLIC
;
2040 var attributes
= get_attributes ("%s::%s".printf (current_data_type
.get_cname (), sig
.name
));
2041 if (attributes
!= null) {
2042 foreach (string attr
in attributes
) {
2043 var nv
= attr
.split ("=", 2);
2044 if (nv
[0] == "name") {
2045 sig
.set_cname (sig
.name
);
2046 sig
.name
= eval (nv
[1]);
2047 } else if (nv
[0] == "has_emitter" && eval (nv
[1]) == "1") {
2048 sig
.has_emitter
= true;
2049 } else if (nv
[0] == "hidden") {
2050 if (eval (nv
[1]) == "1") {
2057 sig
.is_virtual
= true;
2061 foreach (weak IdlNodeParam param
in sig_node
.parameters
) {
2063 // ignore implicit first signal parameter (sender)
2068 weak IdlNode param_node
= (IdlNode
) param
;
2070 ParameterDirection direction
;
2071 var param_type
= parse_param (param
, out direction
);
2072 var p
= new
FormalParameter (param_node
.name
, param_type
);
2073 p
.direction
= direction
;
2074 sig
.add_parameter (p
);
2076 attributes
= get_attributes ("%s::%s.%s".printf (current_data_type
.get_cname (), sig
.name
, param_node
.name
));
2077 if (attributes
!= null) {
2078 string ns_name
= null;
2079 foreach (string attr
in attributes
) {
2080 var nv
= attr
.split ("=", 2);
2081 if (nv
[0] == "is_array") {
2082 if (eval (nv
[1]) == "1") {
2083 param_type
= new
ArrayType (param_type
, 1, param_type
.source_reference
);
2084 p
.parameter_type
= param_type
;
2085 p
.direction
= ParameterDirection
.IN
;
2087 } else if (nv
[0] == "is_out") {
2088 if (eval (nv
[1]) == "1") {
2089 p
.direction
= ParameterDirection
.OUT
;
2091 } else if (nv
[0] == "is_ref") {
2092 if (eval (nv
[1]) == "1") {
2093 p
.direction
= ParameterDirection
.REF
;
2095 } else if (nv
[0] == "nullable") {
2096 if (eval (nv
[1]) == "1") {
2097 param_type
.nullable
= true;
2099 } else if (nv
[0] == "transfer_ownership") {
2100 if (eval (nv
[1]) == "1") {
2101 param_type
.value_owned
= true;
2103 } else if (nv
[0] == "type_name") {
2104 ((UnresolvedType
) param_type
).unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
2105 } else if (nv
[0] == "namespace_name") {
2106 ns_name
= eval (nv
[1]);
2109 if (ns_name
!= null) {
2110 ((UnresolvedType
) param_type
).unresolved_symbol
.inner
= new
UnresolvedSymbol (null, ns_name
);