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 cb
= new
Delegate (node
.name
, parse_param (f_node
.result
), current_source_reference
);
296 cb
.access
= SymbolAccessibility
.PUBLIC
;
298 bool check_has_target
= true;
300 var attributes
= get_attributes (node
.name
);
301 if (attributes
!= null) {
302 foreach (string attr
in attributes
) {
303 var nv
= attr
.split ("=", 2);
304 if (nv
[0] == "hidden") {
305 if (eval (nv
[1]) == "1") {
308 } else if (nv
[0] == "cheader_filename") {
309 cb
.add_cheader_filename (eval (nv
[1]));
310 } else if (nv
[0] == "has_target") {
311 if (eval (nv
[1]) == "0") {
312 check_has_target
= false;
313 } else if (eval (nv
[1]) == "1") {
314 cb
.has_target
= true;
320 uint remaining_params
= f_node
.parameters
.length ();
321 foreach (weak IdlNodeParam param
in f_node
.parameters
) {
322 weak IdlNode param_node
= (IdlNode
) param
;
324 if (check_has_target
&& remaining_params
== 1 && (param_node
.name
== "user_data" || param_node
.name
== "data")) {
325 // hide user_data parameter for instance delegates
326 cb
.has_target
= true;
328 string param_name
= param_node
.name
;
329 if (param_name
== "string") {
330 // avoid conflict with string type
332 } else if (param_name
== "self") {
333 // avoid conflict with delegate target
334 param_name
= "_self";
337 ParameterDirection direction
;
338 var p
= new
FormalParameter (param_name
, parse_param (param
, out direction
));
339 p
.direction
= direction
;
341 bool hide_param
= false;
342 bool show_param
= false;
343 attributes
= get_attributes ("%s.%s".printf (node
.name
, param_node
.name
));
344 if (attributes
!= null) {
345 foreach (string attr
in attributes
) {
346 var nv
= attr
.split ("=", 2);
347 if (nv
[0] == "hidden") {
348 if (eval (nv
[1]) == "1") {
350 } else if (eval (nv
[1]) == "0") {
357 if (show_param
|| !hide_param
) {
358 cb
.add_parameter (p
);
368 private bool is_reference_type (string cname
) {
369 var st_attributes
= get_attributes (cname
);
370 if (st_attributes
!= null) {
371 foreach (string attr
in st_attributes
) {
372 var nv
= attr
.split ("=", 2);
373 if (nv
[0] == "is_value_type" && eval (nv
[1]) == "1") {
381 private void parse_struct (IdlNodeStruct st_node
, Namespace ns
, IdlModule module
) {
382 weak IdlNode node
= (IdlNode
) st_node
;
384 if (st_node
.deprecated
) {
388 string name
= fix_type_name (node
.name
, ns
);
390 if (!is_reference_type (node
.name
)) {
391 var st
= ns
.scope
.lookup (name
) as Struct
;
393 st
= new
Struct (name
, current_source_reference
);
394 st
.access
= SymbolAccessibility
.PUBLIC
;
396 var st_attributes
= get_attributes (node
.name
);
397 if (st_attributes
!= null) {
398 foreach (string attr
in st_attributes
) {
399 var nv
= attr
.split ("=", 2);
400 if (nv
[0] == "cheader_filename") {
401 st
.add_cheader_filename (eval (nv
[1]));
402 } else if (nv
[0] == "hidden") {
403 if (eval (nv
[1]) == "1") {
406 } else if (nv
[0] == "simple_type") {
407 if (eval (nv
[1]) == "1") {
408 st
.set_simple_type (true);
415 current_source_file
.add_node (st
);
418 current_data_type
= st
;
420 foreach (weak IdlNode member
in st_node
.members
) {
421 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
422 var m
= parse_function ((IdlNodeFunction
) member
);
426 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
427 var f
= parse_field ((IdlNodeField
) member
);
434 current_data_type
= null;
436 var cl
= ns
.scope
.lookup (name
) as Class
;
438 string base_class
= null;
440 cl
= new
Class (name
, current_source_reference
);
441 cl
.access
= SymbolAccessibility
.PUBLIC
;
442 cl
.is_compact
= true;
444 var cl_attributes
= get_attributes (node
.name
);
445 if (cl_attributes
!= null) {
446 foreach (string attr
in cl_attributes
) {
447 var nv
= attr
.split ("=", 2);
448 if (nv
[0] == "cheader_filename") {
449 cl
.add_cheader_filename (eval (nv
[1]));
450 } else if (nv
[0] == "base_class") {
451 base_class
= eval (nv
[1]);
452 } else if (nv
[0] == "hidden") {
453 if (eval (nv
[1]) == "1") {
456 } else if (nv
[0] == "is_immutable") {
457 if (eval (nv
[1]) == "1") {
458 cl
.is_immutable
= true;
460 } else if (nv
[0] == "is_fundamental") {
461 if (eval (nv
[1]) == "1") {
462 cl
.is_compact
= false;
464 } else if (nv
[0] == "abstract" && base_class
!= null) {
465 if (eval (nv
[1]) == "1") {
466 cl
.is_abstract
= true;
473 current_source_file
.add_node (cl
);
475 if (base_class
!= null) {
476 var parent
= parse_type_string (base_class
);
477 cl
.add_base_type (parent
);
481 current_data_type
= cl
;
483 string ref_function
= null;
484 string unref_function
= null;
485 string copy_function
= null;
486 string free_function
= null;
488 foreach (weak IdlNode member
in st_node
.members
) {
489 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
490 if (member
.name
== "ref") {
491 ref_function
= ((IdlNodeFunction
) member
).symbol
;
492 } else if (member
.name
== "unref") {
493 unref_function
= ((IdlNodeFunction
) member
).symbol
;
494 } else if (member
.name
== "free" || member
.name
== "destroy") {
495 free_function
= ((IdlNodeFunction
) member
).symbol
;
497 if (member
.name
== "copy") {
498 copy_function
= ((IdlNodeFunction
) member
).symbol
;
500 var m
= parse_function ((IdlNodeFunction
) member
);
505 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
506 var f
= parse_field ((IdlNodeField
) member
);
513 if (ref_function
!= null) {
514 cl
.set_ref_function (ref_function
);
516 if (copy_function
!= null) {
517 cl
.set_dup_function (copy_function
);
519 if (unref_function
!= null) {
520 cl
.set_unref_function (unref_function
);
521 } else if (free_function
!= null) {
522 cl
.set_free_function (free_function
);
525 current_data_type
= null;
529 private void parse_union (IdlNodeUnion un_node
, Namespace ns
, IdlModule module
) {
530 weak IdlNode node
= (IdlNode
) un_node
;
532 if (un_node
.deprecated
) {
536 string name
= fix_type_name (node
.name
, ns
);
538 if (!is_reference_type (node
.name
)) {
539 var st
= ns
.scope
.lookup (name
) as Struct
;
541 st
= new
Struct (name
, current_source_reference
);
542 st
.access
= SymbolAccessibility
.PUBLIC
;
544 var st_attributes
= get_attributes (node
.name
);
545 if (st_attributes
!= null) {
546 foreach (string attr
in st_attributes
) {
547 var nv
= attr
.split ("=", 2);
548 if (nv
[0] == "cheader_filename") {
549 st
.add_cheader_filename (eval (nv
[1]));
550 } else if (nv
[0] == "hidden") {
551 if (eval (nv
[1]) == "1") {
559 current_source_file
.add_node (st
);
562 current_data_type
= st
;
564 foreach (weak IdlNode member
in un_node
.members
) {
565 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
566 var m
= parse_function ((IdlNodeFunction
) member
);
570 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
571 var f
= parse_field ((IdlNodeField
) member
);
578 current_data_type
= null;
580 var cl
= ns
.scope
.lookup (name
) as Class
;
582 cl
= new
Class (name
, current_source_reference
);
583 cl
.access
= SymbolAccessibility
.PUBLIC
;
584 cl
.is_compact
= true;
586 var cl_attributes
= get_attributes (node
.name
);
587 if (cl_attributes
!= null) {
588 foreach (string attr
in cl_attributes
) {
589 var nv
= attr
.split ("=", 2);
590 if (nv
[0] == "cheader_filename") {
591 cl
.add_cheader_filename (eval (nv
[1]));
592 } else if (nv
[0] == "hidden") {
593 if (eval (nv
[1]) == "1") {
601 current_source_file
.add_node (cl
);
604 current_data_type
= cl
;
606 string ref_function
= null;
607 string unref_function
= null;
608 string copy_function
= null;
609 string free_function
= null;
611 foreach (weak IdlNode member
in un_node
.members
) {
612 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
613 if (member
.name
== "ref") {
614 ref_function
= ((IdlNodeFunction
) member
).symbol
;
615 } else if (member
.name
== "unref") {
616 unref_function
= ((IdlNodeFunction
) member
).symbol
;
617 } else if (member
.name
== "free" || member
.name
== "destroy") {
618 free_function
= ((IdlNodeFunction
) member
).symbol
;
620 if (member
.name
== "copy") {
621 copy_function
= ((IdlNodeFunction
) member
).symbol
;
623 var m
= parse_function ((IdlNodeFunction
) member
);
628 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
629 var f
= parse_field ((IdlNodeField
) member
);
636 if (ref_function
!= null) {
637 cl
.set_ref_function (ref_function
);
639 if (copy_function
!= null) {
640 cl
.set_dup_function (copy_function
);
642 if (unref_function
!= null) {
643 cl
.set_unref_function (unref_function
);
644 } else if (free_function
!= null) {
645 cl
.set_free_function (free_function
);
648 current_data_type
= null;
652 private void parse_boxed (IdlNodeBoxed boxed_node
, Namespace ns
, IdlModule module
) {
653 weak IdlNode node
= (IdlNode
) boxed_node
;
655 string name
= fix_type_name (node
.name
, ns
);
657 var node_attributes
= get_attributes (node
.name
);
658 if (node_attributes
!= null) {
659 foreach (string attr
in node_attributes
) {
660 var nv
= attr
.split ("=", 2);
661 if (nv
[0] == "hidden") {
667 if (!is_reference_type (node
.name
)) {
668 var st
= ns
.scope
.lookup (name
) as Struct
;
670 st
= new
Struct (name
, current_source_reference
);
671 st
.access
= SymbolAccessibility
.PUBLIC
;
673 var st_attributes
= get_attributes (node
.name
);
674 if (st_attributes
!= null) {
675 foreach (string attr
in st_attributes
) {
676 var nv
= attr
.split ("=", 2);
677 if (nv
[0] == "cheader_filename") {
678 st
.add_cheader_filename (eval (nv
[1]));
684 st
.set_type_id (st
.get_upper_case_cname ("TYPE_"));
685 current_source_file
.add_node (st
);
688 current_data_type
= st
;
690 foreach (weak IdlNode member
in boxed_node
.members
) {
691 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
692 var m
= parse_function ((IdlNodeFunction
) member
);
696 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
697 var f
= parse_field ((IdlNodeField
) member
);
704 current_data_type
= null;
706 var cl
= ns
.scope
.lookup (name
) as Class
;
708 cl
= new
Class (name
, current_source_reference
);
709 cl
.access
= SymbolAccessibility
.PUBLIC
;
710 cl
.is_compact
= true;
712 var cl_attributes
= get_attributes (node
.name
);
713 if (cl_attributes
!= null) {
714 foreach (string attr
in cl_attributes
) {
715 var nv
= attr
.split ("=", 2);
716 if (nv
[0] == "cheader_filename") {
717 cl
.add_cheader_filename (eval (nv
[1]));
718 } else if (nv
[0] == "is_immutable") {
719 if (eval (nv
[1]) == "1") {
720 cl
.is_immutable
= true;
727 cl
.set_type_id (cl
.get_upper_case_cname ("TYPE_"));
728 current_source_file
.add_node (cl
);
731 current_data_type
= cl
;
733 string ref_function
= null;
734 string unref_function
= null;
735 string copy_function
= null;
736 string free_function
= null;
738 foreach (weak IdlNode member
in boxed_node
.members
) {
739 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
740 if (member
.name
== "ref") {
741 ref_function
= ((IdlNodeFunction
) member
).symbol
;
742 } else if (member
.name
== "unref") {
743 unref_function
= ((IdlNodeFunction
) member
).symbol
;
744 } else if (member
.name
== "free" || member
.name
== "destroy") {
745 free_function
= ((IdlNodeFunction
) member
).symbol
;
747 if (member
.name
== "copy") {
748 copy_function
= ((IdlNodeFunction
) member
).symbol
;
750 var m
= parse_function ((IdlNodeFunction
) member
);
755 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
756 var f
= parse_field ((IdlNodeField
) member
);
763 if (ref_function
!= null) {
764 cl
.set_ref_function (ref_function
);
766 if (copy_function
!= null) {
767 cl
.set_dup_function (copy_function
);
769 if (unref_function
!= null) {
770 cl
.set_unref_function (unref_function
);
771 } else if (free_function
!= null) {
772 cl
.set_free_function (free_function
);
775 current_data_type
= null;
779 private TypeSymbol?
parse_enum (IdlNodeEnum en_node
) {
780 weak IdlNode node
= (IdlNode
) en_node
;
782 var en
= new
Enum (node
.name
, current_source_reference
);
783 en
.access
= SymbolAccessibility
.PUBLIC
;
784 en
.has_type_id
= (en_node
.gtype_name
!= null && en_node
.gtype_name
!= "");
786 string common_prefix
= null;
788 foreach (weak IdlNode value
in en_node
.values
) {
789 if (common_prefix
== null) {
790 common_prefix
= value
.name
;
791 while (common_prefix
.len () > 0 && !common_prefix
.has_suffix ("_")) {
792 // FIXME: could easily be made faster
793 common_prefix
= common_prefix
.ndup (common_prefix
.size () - 1);
796 while (!value
.name
.has_prefix (common_prefix
)) {
797 common_prefix
= common_prefix
.ndup (common_prefix
.size () - 1);
800 while (common_prefix
.len () > 0 && (!common_prefix
.has_suffix ("_") ||
801 (value
.name
.offset (common_prefix
.size ()).get_char ().isdigit ()) && (value
.name
.len () - common_prefix
.len ()) <= 1)) {
802 // enum values may not consist solely of digits
803 common_prefix
= common_prefix
.ndup (common_prefix
.size () - 1);
807 bool is_errordomain
= false;
809 var cheader_filenames
= new ArrayList
<string> ();
811 var en_attributes
= get_attributes (node
.name
);
812 if (en_attributes
!= null) {
813 foreach (string attr
in en_attributes
) {
814 var nv
= attr
.split ("=", 2);
815 if (nv
[0] == "common_prefix") {
816 common_prefix
= eval (nv
[1]);
817 } else if (nv
[0] == "cheader_filename") {
818 cheader_filenames
.add (eval (nv
[1]));
819 en
.add_cheader_filename (eval (nv
[1]));
820 } else if (nv
[0] == "hidden") {
821 if (eval (nv
[1]) == "1") {
824 } else if (nv
[0] == "rename_to") {
825 en
.name
= eval (nv
[1]);
826 } else if (nv
[0] == "errordomain") {
827 if (eval (nv
[1]) == "1") {
828 is_errordomain
= true;
834 en
.set_cprefix (common_prefix
);
836 foreach (weak IdlNode value2
in en_node
.values
) {
837 var ev
= new
EnumValue (value2
.name
.offset (common_prefix
.len ()));
841 if (is_errordomain
) {
842 var ed
= new
ErrorDomain (en
.name
, current_source_reference
);
843 ed
.access
= SymbolAccessibility
.PUBLIC
;
844 ed
.set_cprefix (common_prefix
);
846 foreach (string filename
in cheader_filenames
) {
847 ed
.add_cheader_filename (filename
);
850 foreach (EnumValue ev
in en
.get_values ()) {
851 ed
.add_code (new
ErrorCode (ev
.name
));
860 private void parse_object (IdlNodeInterface node
, Namespace ns
, IdlModule module
) {
861 string name
= fix_type_name (((IdlNode
) node
).name
, ns
);
863 string base_class
= null;
865 var cl
= ns
.scope
.lookup (name
) as Class
;
867 cl
= new
Class (name
, current_source_reference
);
868 cl
.access
= SymbolAccessibility
.PUBLIC
;
870 var attributes
= get_attributes (node
.gtype_name
);
871 if (attributes
!= null) {
872 foreach (string attr
in attributes
) {
873 var nv
= attr
.split ("=", 2);
874 if (nv
[0] == "cheader_filename") {
875 cl
.add_cheader_filename (eval (nv
[1]));
876 } else if (nv
[0] == "base_class") {
877 base_class
= eval (nv
[1]);
878 } else if (nv
[0] == "hidden") {
879 if (eval (nv
[1]) == "1") {
882 } else if (nv
[0] == "type_check_function") {
883 cl
.type_check_function
= eval (nv
[1]);
884 } else if (nv
[0] == "abstract") {
885 if (eval (nv
[1]) == "1") {
886 cl
.is_abstract
= true;
893 current_source_file
.add_node (cl
);
896 if (base_class
!= null) {
897 var parent
= parse_type_string (base_class
);
898 cl
.add_base_type (parent
);
899 } else if (node
.parent
!= null) {
900 var parent
= parse_type_string (node
.parent
);
901 cl
.add_base_type (parent
);
903 var gobject_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "Object");
904 cl
.add_base_type (new UnresolvedType
.from_symbol (gobject_symbol
));
907 foreach (string iface_name
in node
.interfaces
) {
908 var iface
= parse_type_string (iface_name
);
909 cl
.add_base_type (iface
);
912 current_data_type
= cl
;
914 current_type_symbol_set
= new HashSet
<string> (str_hash
, str_equal
);
915 var current_type_func_map
= new HashMap
<string,weak IdlNodeFunction
> (str_hash
, str_equal
);
916 var current_type_vfunc_map
= new HashMap
<string,string> (str_hash
, str_equal
);
918 foreach (weak IdlNode member
in node
.members
) {
919 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
920 current_type_func_map
.set (member
.name
, (IdlNodeFunction
) member
);
922 if (member
.type
== IdlNodeTypeId
.VFUNC
) {
923 current_type_vfunc_map
.set (member
.name
, "1");
927 foreach (weak IdlNode member
in node
.members
) {
928 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
929 // Ignore if vfunc (handled below)
930 if (!current_type_vfunc_map
.contains (member
.name
)) {
931 var m
= parse_function ((IdlNodeFunction
) member
);
936 } else if (member
.type
== IdlNodeTypeId
.VFUNC
) {
937 var m
= parse_virtual ((IdlNodeVFunc
) member
, current_type_func_map
.get (member
.name
));
941 } else if (member
.type
== IdlNodeTypeId
.PROPERTY
) {
942 var prop
= parse_property ((IdlNodeProperty
) member
);
944 cl
.add_property (prop
);
946 } else if (member
.type
== IdlNodeTypeId
.SIGNAL
) {
947 var sig
= parse_signal ((IdlNodeSignal
) member
);
954 foreach (weak IdlNode member
in node
.members
) {
955 if (member
.type
== IdlNodeTypeId
.FIELD
) {
956 if (!current_type_symbol_set
.contains (member
.name
)) {
957 var f
= parse_field ((IdlNodeField
) member
);
965 foreach (Property prop
in cl
.get_properties ()) {
966 var getter
= "get_%s".printf (prop
.name
);
968 if (prop
.get_accessor
!= null && !current_type_symbol_set
.contains (getter
)) {
969 prop
.no_accessor_method
= true;
970 prop
.get_accessor
.value_type
.value_owned
= true;
973 var setter
= "set_%s".printf (prop
.name
);
975 if (prop
.set_accessor
!= null && !current_type_symbol_set
.contains (setter
)) {
976 prop
.no_accessor_method
= true;
980 current_data_type
= null;
981 current_type_symbol_set
= null;
984 private void parse_interface (IdlNodeInterface node
, Namespace ns
, IdlModule module
) {
985 string name
= fix_type_name (node
.gtype_name
, ns
);
987 var iface
= ns
.scope
.lookup (name
) as Interface
;
989 iface
= new
Interface (name
, current_source_reference
);
990 iface
.access
= SymbolAccessibility
.PUBLIC
;
992 var attributes
= get_attributes (node
.gtype_name
);
993 if (attributes
!= null) {
994 foreach (string attr
in attributes
) {
995 var nv
= attr
.split ("=", 2);
996 if (nv
[0] == "cheader_filename") {
997 iface
.add_cheader_filename (eval (nv
[1]));
998 } else if (nv
[0] == "lower_case_csuffix") {
999 iface
.set_lower_case_csuffix (eval (nv
[1]));
1004 foreach (string prereq_name
in node
.prerequisites
) {
1005 var prereq
= parse_type_string (prereq_name
);
1006 iface
.add_prerequisite (prereq
);
1009 ns
.add_interface (iface
);
1010 current_source_file
.add_node (iface
);
1013 current_data_type
= iface
;
1015 var current_type_func_map
= new HashMap
<string,weak IdlNodeFunction
> (str_hash
, str_equal
);
1016 var current_type_vfunc_map
= new HashMap
<string,string> (str_hash
, str_equal
);
1018 foreach (weak IdlNode member
in node
.members
) {
1019 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1020 current_type_func_map
.set (member
.name
, (IdlNodeFunction
) member
);
1022 if (member
.type
== IdlNodeTypeId
.VFUNC
) {
1023 current_type_vfunc_map
.set (member
.name
, "1");
1027 foreach (weak IdlNode member
in node
.members
) {
1028 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1029 // Ignore if vfunc (handled below)
1030 if (!current_type_vfunc_map
.contains (member
.name
)) {
1031 var m
= parse_function ((IdlNodeFunction
) member
, true);
1033 iface
.add_method (m
);
1036 } else if (member
.type
== IdlNodeTypeId
.VFUNC
) {
1037 var m
= parse_virtual ((IdlNodeVFunc
) member
, current_type_func_map
.get (member
.name
), true);
1039 iface
.add_method (m
);
1041 } else if (member
.type
== IdlNodeTypeId
.PROPERTY
) {
1042 var prop
= parse_property ((IdlNodeProperty
) member
);
1044 iface
.add_property (prop
);
1046 } else if (member
.type
== IdlNodeTypeId
.SIGNAL
) {
1047 var sig
= parse_signal ((IdlNodeSignal
) member
);
1049 iface
.add_signal (sig
);
1054 current_data_type
= null;
1057 private DataType?
parse_type (IdlNodeType type_node
, out ParameterDirection direction
= null) {
1058 ParameterDirection dir
= ParameterDirection
.IN
;
1060 var type
= new
UnresolvedType ();
1061 if (type_node
.tag
== TypeTag
.VOID
) {
1062 if (type_node
.is_pointer
) {
1063 return new
PointerType (new
VoidType ());
1065 return new
VoidType ();
1067 } else if (type_node
.tag
== TypeTag
.BOOLEAN
) {
1068 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "bool");
1069 } else if (type_node
.tag
== TypeTag
.INT8
) {
1070 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "char");
1071 } else if (type_node
.tag
== TypeTag
.UINT8
) {
1072 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uchar");
1073 } else if (type_node
.tag
== TypeTag
.INT16
) {
1074 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int16");
1075 } else if (type_node
.tag
== TypeTag
.UINT16
) {
1076 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint16");
1077 } else if (type_node
.tag
== TypeTag
.INT32
) {
1078 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int32");
1079 } else if (type_node
.tag
== TypeTag
.UINT32
) {
1080 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint32");
1081 } else if (type_node
.tag
== TypeTag
.INT64
) {
1082 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int64");
1083 } else if (type_node
.tag
== TypeTag
.UINT64
) {
1084 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint64");
1085 } else if (type_node
.tag
== TypeTag
.INT
) {
1086 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int");
1087 } else if (type_node
.tag
== TypeTag
.UINT
) {
1088 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint");
1089 } else if (type_node
.tag
== TypeTag
.LONG
) {
1090 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "long");
1091 } else if (type_node
.tag
== TypeTag
.ULONG
) {
1092 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ulong");
1093 } else if (type_node
.tag
== TypeTag
.SSIZE
) {
1094 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ssize_t");
1095 } else if (type_node
.tag
== TypeTag
.SIZE
) {
1096 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "size_t");
1097 } else if (type_node
.tag
== TypeTag
.FLOAT
) {
1098 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "float");
1099 } else if (type_node
.tag
== TypeTag
.DOUBLE
) {
1100 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "double");
1101 } else if (type_node
.tag
== TypeTag
.UTF8
) {
1102 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1103 } else if (type_node
.tag
== TypeTag
.FILENAME
) {
1104 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1105 } else if (type_node
.tag
== TypeTag
.ARRAY
) {
1106 var element_type
= parse_type (type_node
.parameter_type1
);
1107 type
= element_type as UnresolvedType
;
1109 return element_type
;
1111 return new
ArrayType (element_type
, 1, element_type
.source_reference
);
1112 } else if (type_node
.tag
== TypeTag
.LIST
) {
1113 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "List");
1114 } else if (type_node
.tag
== TypeTag
.SLIST
) {
1115 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "SList");
1116 } else if (type_node
.tag
== TypeTag
.HASH
) {
1117 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "HashTable");
1118 } else if (type_node
.tag
== TypeTag
.ERROR
) {
1119 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "Error");
1120 } else if (type_node
.is_interface
) {
1121 var n
= type_node
.@
interface;
1127 if (n
.has_prefix ("const-")) {
1128 n
= n
.offset ("const-".len ());
1131 if (type_node
.is_pointer
&&
1132 (n
== "gchar" || n
== "char")) {
1133 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1134 if (type_node
.unparsed
.has_suffix ("**")) {
1135 dir
= ParameterDirection
.OUT
;
1137 } else if (n
== "gunichar") {
1138 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "unichar");
1139 } else if (n
== "gchar") {
1140 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "char");
1141 } else if (n
== "guchar" || n
== "guint8") {
1142 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uchar");
1143 if (type_node
.is_pointer
) {
1144 return new
ArrayType (type
, 1, type
.source_reference
);
1146 } else if (n
== "gushort") {
1147 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ushort");
1148 } else if (n
== "gshort") {
1149 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "short");
1150 } else if (n
== "gconstpointer" || n
== "void") {
1151 return new
PointerType (new
VoidType ());
1152 } else if (n
== "goffset" || n
== "off_t") {
1153 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int64");
1154 } else if (n
== "value_array") {
1155 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "ValueArray");
1156 } else if (n
== "time_t") {
1157 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ulong");
1158 } else if (n
== "socklen_t") {
1159 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint32");
1160 } else if (n
== "mode_t") {
1161 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint");
1162 } else if (n
== "gint" || n
== "pid_t") {
1163 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int");
1164 } else if (n
== "unsigned" || n
== "unsigned-int") {
1165 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint");
1166 } else if (n
== "FILE") {
1167 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "FileStream");
1168 } else if (n
== "struct") {
1169 return new
PointerType (new
VoidType ());
1170 } else if (n
== "iconv_t") {
1171 return new
PointerType (new
VoidType ());
1172 } else if (n
== "GType") {
1173 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "Type");
1174 if (type_node
.is_pointer
) {
1175 return new
ArrayType (type
, 1, type
.source_reference
);
1177 } else if (n
== "GStrv") {
1178 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1179 return new
ArrayType (type
, 1, type
.source_reference
);
1181 var named_type
= parse_type_string (n
);
1182 type
= named_type as UnresolvedType
;
1186 if (is_simple_type (n
)) {
1187 if (type_node
.is_pointer
) {
1188 dir
= ParameterDirection
.OUT
;
1190 } else if (type_node
.unparsed
.has_suffix ("**")) {
1191 dir
= ParameterDirection
.OUT
;
1195 stdout
.printf ("%d\n", type_node
.tag
);
1197 if (&direction
!= null) {
1203 private bool is_simple_type (string type_name
) {
1204 var st
= cname_type_map
[type_name
] as Struct
;
1205 if (st
!= null && st
.is_simple_type ()) {
1212 private DataType
parse_type_string (string n
) {
1213 if (n
== "va_list") {
1215 return new
PointerType (new
VoidType ());
1218 var type
= new
UnresolvedType ();
1220 var dt
= cname_type_map
[n
];
1222 UnresolvedSymbol parent_symbol
= null;
1223 if (dt
.parent_symbol
.name
!= null) {
1224 parent_symbol
= new
UnresolvedSymbol (null, dt
.parent_symbol
.name
);
1226 type
.unresolved_symbol
= new
UnresolvedSymbol (parent_symbol
, dt
.name
);
1230 var type_attributes
= get_attributes (n
);
1232 string ns_name
= null;
1234 if (null != type_attributes
) {
1235 foreach (string attr
in type_attributes
) {
1236 var nv
= attr
.split ("=", 2);
1238 if (nv
[0] == "cprefix") {
1239 type
.unresolved_symbol
= new
UnresolvedSymbol (null, n
.offset (eval (nv
[1]).len ()));
1240 } else if (nv
[0] == "name") {
1241 type
.unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1242 } else if (nv
[0] == "namespace") {
1243 ns_name
= eval (nv
[1]);
1244 } else if (nv
[0] == "rename_to") {
1245 type
.unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1250 if (type
.unresolved_symbol
!= null) {
1251 if (type
.unresolved_symbol
.name
== "pointer") {
1252 return new
PointerType (new
VoidType ());
1254 if (ns_name
!= null) {
1255 type
.unresolved_symbol
.inner
= new
UnresolvedSymbol (null, ns_name
);
1260 if (n
.has_prefix (current_namespace
.name
)) {
1261 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, current_namespace
.name
), n
.offset (current_namespace
.name
.len ()));
1262 } else if (n
.has_prefix ("G")) {
1263 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), n
.offset (1));
1265 var name_parts
= n
.split (".", 2);
1266 if (name_parts
[1] == null) {
1267 type
.unresolved_symbol
= new
UnresolvedSymbol (null, name_parts
[0]);
1269 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, name_parts
[0]), name_parts
[1]);
1276 private DataType?
parse_param (IdlNodeParam param
, out ParameterDirection direction
= null) {
1277 var type
= parse_type (param
.type
, out direction
);
1279 // disable for now as null_ok not yet correctly set
1280 // type.non_null = !param.null_ok;
1285 private Method?
create_method (string name
, string symbol
, IdlNodeParam? res
, GLib
.List
<IdlNodeParam
>? parameters
, bool is_constructor
, bool is_interface
) {
1286 DataType return_type
= null;
1288 return_type
= parse_param (res
);
1292 if (!is_interface
&& (is_constructor
|| name
.has_prefix ("new"))) {
1293 m
= new
CreationMethod (null, name
, current_source_reference
);
1294 m
.has_construct_function
= false;
1295 if (m
.name
== "new") {
1297 } else if (m
.name
.has_prefix ("new_")) {
1298 m
.name
= m
.name
.offset ("new_".len ());
1300 // For classes, check whether a creation method return type equals to the
1301 // type of the class created. If the types do not match (e.g. in most
1302 // gtk widgets) add an attribute to the creation method indicating the used
1304 if (current_data_type is Class
&& res
!= null) {
1305 if ("%s*".printf (current_data_type
.get_cname()) != res
.type
.unparsed
) {
1306 ((CreationMethod
)m
).custom_return_type_cname
= res
.type
.unparsed
;
1310 m
= new
Method (name
, return_type
, current_source_reference
);
1312 m
.access
= SymbolAccessibility
.PUBLIC
;
1314 if (current_type_symbol_set
!= null) {
1315 current_type_symbol_set
.add (name
);
1318 if (current_data_type
!= null) {
1319 var sig_attributes
= get_attributes ("%s::%s".printf (current_data_type
.get_cname (), name
));
1320 if (sig_attributes
!= null) {
1321 foreach (string attr
in sig_attributes
) {
1322 var nv
= attr
.split ("=", 2);
1323 if (nv
[0] == "has_emitter" && eval (nv
[1]) == "1") {
1330 bool add_ellipsis
= false;
1331 bool suppress_throws
= false;
1333 var attributes
= get_attributes (symbol
);
1334 if (attributes
!= null) {
1335 foreach (string attr
in attributes
) {
1336 var nv
= attr
.split ("=", 2);
1337 if (nv
[0] == "name") {
1338 m
.set_cname (m
.name
);
1339 m
.name
= eval (nv
[1]);
1340 } else if (nv
[0] == "hidden") {
1341 if (eval (nv
[1]) == "1") {
1344 } else if (nv
[0] == "ellipsis") {
1345 if (eval (nv
[1]) == "1") {
1346 add_ellipsis
= true;
1348 } else if (nv
[0] == "transfer_ownership") {
1349 if (eval (nv
[1]) == "1") {
1350 return_type
.value_owned
= true;
1352 } else if (nv
[0] == "nullable") {
1353 if (eval (nv
[1]) == "1") {
1354 return_type
.nullable
= true;
1356 } else if (nv
[0] == "sentinel") {
1357 m
.sentinel
= eval (nv
[1]);
1358 } else if (nv
[0] == "is_array") {
1359 if (eval (nv
[1]) == "1") {
1360 return_type
= new
ArrayType (return_type
, 1, return_type
.source_reference
);
1361 m
.return_type
= return_type
;
1363 } else if (nv
[0] == "throws") {
1364 if (eval (nv
[1]) == "0") {
1365 suppress_throws
= true;
1367 } else if (nv
[0] == "no_array_length") {
1368 if (eval (nv
[1]) == "1") {
1369 m
.no_array_length
= true;
1371 } else if (nv
[0] == "array_null_terminated") {
1372 if (eval (nv
[1]) == "1") {
1373 m
.no_array_length
= true;
1374 m
.array_null_terminated
= true;
1376 } else if (nv
[0] == "type_name") {
1377 var sym
= new
UnresolvedSymbol (null, eval (nv
[1]));
1378 if (return_type is UnresolvedType
) {
1379 ((UnresolvedType
) return_type
).unresolved_symbol
= sym
;
1381 // Overwrite old return_type, so "type_name" must be before any
1382 // other return type modifying metadata
1383 m
.return_type
= return_type
= new UnresolvedType
.from_symbol (sym
, return_type
.source_reference
);
1385 } else if (nv
[0] == "type_arguments") {
1386 var type_args
= eval (nv
[1]).split (",");
1387 foreach (string type_arg
in type_args
) {
1388 var arg_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, type_arg
));
1389 arg_type
.value_owned
= true;
1390 return_type
.add_type_argument (arg_type
);
1392 } else if (nv
[0] == "cheader_filename") {
1393 m
.add_cheader_filename (eval (nv
[1]));
1394 } else if (nv
[0] == "abstract") {
1395 if (eval (nv
[1]) == "1") {
1396 m
.is_abstract
= true;
1398 } else if (nv
[0] == "virtual") {
1399 if (eval (nv
[1]) == "1") {
1400 m
.is_virtual
= true;
1407 m
.set_cname (symbol
);
1410 FormalParameter last_param
= null;
1411 DataType last_param_type
= null;
1412 foreach (weak IdlNodeParam param
in parameters
) {
1413 weak IdlNode param_node
= (IdlNode
) param
;
1417 if (!(m is CreationMethod
) &&
1418 current_data_type
!= null &&
1419 param
.type
.is_interface
&&
1420 (param_node
.name
== "self" ||
1421 param
.type
.@
interface.has_suffix (current_data_type
.get_cname ()))) {
1424 } else if (!(m is CreationMethod
) &&
1425 current_data_type
!= null &&
1426 param
.type
.is_interface
&&
1427 (param_node
.name
== "klass" ||
1428 param
.type
.@
interface.has_suffix ("%sClass".printf(current_data_type
.get_cname ())))) {
1430 m
.binding
= MemberBinding
.CLASS
;
1431 if (m
.name
.has_prefix ("class_")) {
1432 m
.name
= m
.name
.substring ("class_".len (), m
.name
.len () - "class_".len ());
1437 m
.binding
= MemberBinding
.STATIC
;
1441 if (suppress_throws
== false && param_is_exception (param
)) {
1442 m
.add_error_type (parse_type (param
.type
));
1446 string param_name
= param_node
.name
;
1447 if (param_name
== "result") {
1448 // avoid conflict with generated result variable
1449 param_name
= "_result";
1450 } else if (param_name
== "string") {
1451 // avoid conflict with string type
1454 ParameterDirection direction
;
1455 var param_type
= parse_param (param
, out direction
);
1456 var p
= new
FormalParameter (param_name
, param_type
);
1457 p
.direction
= direction
;
1459 bool hide_param
= false;
1460 bool show_param
= false;
1461 bool set_array_length_pos
= false;
1462 double array_length_pos
= 0;
1463 bool set_delegate_target_pos
= false;
1464 double delegate_target_pos
= 0;
1465 bool array_requested
= false;
1466 attributes
= get_attributes ("%s.%s".printf (symbol
, param_node
.name
));
1467 if (attributes
!= null) {
1468 foreach (string attr
in attributes
) {
1469 var nv
= attr
.split ("=", 2);
1470 if (nv
[0] == "is_array") {
1471 if (eval (nv
[1]) == "1") {
1472 param_type
= new
ArrayType (param_type
, 1, param_type
.source_reference
);
1473 p
.parameter_type
= param_type
;
1474 p
.direction
= ParameterDirection
.IN
;
1475 array_requested
= true;
1477 } else if (nv
[0] == "is_out") {
1478 if (eval (nv
[1]) == "1") {
1479 p
.direction
= ParameterDirection
.OUT
;
1480 if (!array_requested
&& param_type is ArrayType
) {
1481 var array_type
= (ArrayType
) param_type
;
1482 param_type
= array_type
.element_type
;
1483 p
.parameter_type
= param_type
;
1486 } else if (nv
[0] == "is_ref") {
1487 if (eval (nv
[1]) == "1") {
1488 p
.direction
= ParameterDirection
.REF
;
1489 if (!array_requested
&& param_type is ArrayType
) {
1490 var array_type
= (ArrayType
) param_type
;
1491 param_type
= array_type
.element_type
;
1492 p
.parameter_type
= param_type
;
1495 } else if (nv
[0] == "nullable") {
1496 if (eval (nv
[1]) == "1") {
1497 param_type
.nullable
= true;
1499 } else if (nv
[0] == "transfer_ownership") {
1500 if (eval (nv
[1]) == "1") {
1501 param_type
.value_owned
= true;
1503 } else if (nv
[0] == "takes_ownership") {
1504 if (eval (nv
[1]) == "1") {
1505 param_type
.value_owned
= true;
1507 } else if (nv
[0] == "value_owned") {
1508 if (eval (nv
[1]) == "0") {
1509 param_type
.value_owned
= false;
1510 } else if (eval (nv
[1]) == "1") {
1511 param_type
.value_owned
= true;
1513 } else if (nv
[0] == "hidden") {
1514 if (eval (nv
[1]) == "1") {
1516 } else if (eval (nv
[1]) == "0") {
1519 } else if (nv
[0] == "no_array_length") {
1520 if (eval (nv
[1]) == "1") {
1521 p
.no_array_length
= true;
1523 } else if (nv
[0] == "array_null_terminated") {
1524 if (eval (nv
[1]) == "1") {
1525 p
.no_array_length
= true;
1526 p
.array_null_terminated
= true;
1528 } else if (nv
[0] == "array_length_pos") {
1529 set_array_length_pos
= true;
1530 array_length_pos
= eval (nv
[1]).to_double ();
1531 } else if (nv
[0] == "delegate_target_pos") {
1532 set_delegate_target_pos
= true;
1533 delegate_target_pos
= eval (nv
[1]).to_double ();
1534 } else if (nv
[0] == "type_name") {
1535 ((UnresolvedType
) param_type
).unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1536 } else if (nv
[0] == "ctype") {
1537 p
.ctype
= eval (nv
[1]);
1538 } else if (nv
[0] == "type_arguments") {
1539 var type_args
= eval (nv
[1]).split (",");
1540 foreach (string type_arg
in type_args
) {
1541 var arg_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, type_arg
));
1542 arg_type
.value_owned
= true;
1543 param_type
.add_type_argument (arg_type
);
1549 if (last_param
!= null && p
.name
== "n_" + last_param
.name
) {
1550 if (!(last_param_type is ArrayType
)) {
1551 // last_param is array, p is array length
1552 last_param_type
= new
ArrayType (last_param_type
, 1, last_param_type
.source_reference
);
1553 last_param
.parameter_type
= last_param_type
;
1554 last_param
.direction
= ParameterDirection
.IN
;
1557 // hide array length param
1559 } else if (last_param
!= null && p
.name
== "user_data") {
1560 // last_param is delegate
1562 // hide deleate target param
1566 if (show_param
|| !hide_param
) {
1567 m
.add_parameter (p
);
1568 if (set_array_length_pos
) {
1569 p
.carray_length_parameter_position
= array_length_pos
;
1571 if (set_delegate_target_pos
) {
1572 p
.cdelegate_target_parameter_position
= delegate_target_pos
;
1577 last_param_type
= param_type
;
1581 // no parameters => static method
1582 m
.binding
= MemberBinding
.STATIC
;
1585 if (last_param
!= null && last_param
.name
.has_prefix ("first_")) {
1586 last_param
.ellipsis
= true;
1587 } else if (add_ellipsis
) {
1588 m
.add_parameter (new FormalParameter
.with_ellipsis ());
1594 private bool param_is_exception (IdlNodeParam param
) {
1595 if (!param
.type
.is_error
) {
1598 var s
= param
.type
.unparsed
.chomp ();
1599 if (s
.has_suffix ("**")) {
1605 private Method?
parse_function (IdlNodeFunction f
, bool is_interface
= false) {
1606 weak IdlNode node
= (IdlNode
) f
;
1612 return create_method (node
.name
, f
.symbol
, f
.result
, f
.parameters
, f
.is_constructor
, is_interface
);
1615 private Method
parse_virtual (IdlNodeVFunc v
, IdlNodeFunction? func
, bool is_interface
= false) {
1616 weak IdlNode node
= (IdlNode
) v
;
1617 string symbol
= "%s%s".printf (current_data_type
.get_lower_case_cprefix(), node
.name
);
1620 symbol
= func
.symbol
;
1623 Method m
= create_method (node
.name
, symbol
, v
.result
, func
!= null ? func
.parameters
: v
.parameters
, false, is_interface
);
1625 m
.binding
= MemberBinding
.INSTANCE
;
1626 m
.is_virtual
= !(m
.is_abstract
|| is_interface
);
1627 m
.is_abstract
= m
.is_abstract
|| is_interface
;
1630 m
.attributes
.append (new
Attribute ("NoWrapper", null));
1637 private string fix_prop_name (string name
) {
1638 var str
= new
StringBuilder ();
1642 while (i
.len () > 0) {
1643 unichar c
= i
.get_char ();
1647 str
.append_unichar (c
);
1656 private Property?
parse_property (IdlNodeProperty prop_node
) {
1657 weak IdlNode node
= (IdlNode
) prop_node
;
1659 if (prop_node
.deprecated
) {
1663 if (!prop_node
.readable
&& !prop_node
.writable
) {
1664 // buggy GIDL definition
1665 prop_node
.readable
= true;
1666 prop_node
.writable
= true;
1669 var prop
= new
Property (fix_prop_name (node
.name
), parse_type (prop_node
.type
), null, null, current_source_reference
);
1670 prop
.access
= SymbolAccessibility
.PUBLIC
;
1671 prop
.interface_only
= true;
1673 if (prop_node
.readable
) {
1674 prop
.get_accessor
= new
PropertyAccessor (true, false, false, prop
.property_type
.copy (), null, null);
1676 if (prop_node
.writable
) {
1677 prop
.set_accessor
= new
PropertyAccessor (false, false, false, prop
.property_type
.copy (), null, null);
1678 if (prop_node
.construct_only
) {
1679 prop
.set_accessor
.construction
= true;
1681 prop
.set_accessor
.writable
= true;
1682 prop
.set_accessor
.construction
= prop_node
.@
construct;
1686 var attributes
= get_attributes ("%s:%s".printf (current_data_type
.get_cname (), node
.name
));
1687 if (attributes
!= null) {
1688 foreach (string attr
in attributes
) {
1689 var nv
= attr
.split ("=", 2);
1690 if (nv
[0] == "hidden") {
1691 if (eval (nv
[1]) == "1") {
1694 } else if (nv
[0] == "type_arguments") {
1695 var type_args
= eval (nv
[1]).split (",");
1696 foreach (string type_arg
in type_args
) {
1697 var arg_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, type_arg
));
1698 arg_type
.value_owned
= true;
1699 prop
.property_type
.add_type_argument (arg_type
);
1705 if (current_type_symbol_set
!= null) {
1706 current_type_symbol_set
.add (prop
.name
);
1712 private Constant?
parse_constant (IdlNodeConstant const_node
) {
1713 weak IdlNode node
= (IdlNode
) const_node
;
1715 var type
= parse_type (const_node
.type
);
1720 var c
= new
Constant (node
.name
, type
, null, current_source_reference
);
1722 string[] attributes
= get_attributes (node
.name
);
1723 if (attributes
!= null) {
1724 foreach (string attr
in attributes
) {
1725 var nv
= attr
.split ("=", 2);
1726 if (nv
[0] == "cheader_filename") {
1727 c
.add_cheader_filename (eval (nv
[1]));
1728 } else if (nv
[0] == "hidden") {
1729 if (eval (nv
[1]) == "1") {
1736 c
.access
= SymbolAccessibility
.PUBLIC
;
1741 private Field?
parse_field (IdlNodeField field_node
) {
1742 weak IdlNode node
= (IdlNode
) field_node
;
1743 bool unhidden
= false;
1745 var type
= parse_type (field_node
.type
);
1750 string cheader_filename
= null;
1751 string ctype
= null;
1753 var attributes
= get_attributes ("%s.%s".printf (current_data_type
.get_cname (), node
.name
));
1754 if (attributes
!= null) {
1755 foreach (string attr
in attributes
) {
1756 var nv
= attr
.split ("=", 2);
1757 if (nv
[0] == "hidden") {
1758 if (eval (nv
[1]) == "1") {
1763 } else if (nv
[0] == "is_array") {
1764 if (eval (nv
[1]) == "1") {
1765 type
= new
ArrayType (type
, 1, type
.source_reference
);
1767 } else if (nv
[0] == "weak") {
1768 if (eval (nv
[1]) == "0") {
1769 type
.value_owned
= true;
1771 } else if (nv
[0] == "type_name") {
1772 ((UnresolvedType
) type
).unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1773 } else if (nv
[0] == "type_arguments") {
1774 var type_args
= eval (nv
[1]).split (",");
1775 foreach (string type_arg
in type_args
) {
1776 var arg_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, type_arg
));
1777 arg_type
.value_owned
= true;
1778 type
.add_type_argument (arg_type
);
1780 } else if (nv
[0] == "cheader_filename") {
1781 cheader_filename
= eval (nv
[1]);
1782 } else if (nv
[0] == "ctype") {
1783 ctype
= eval (nv
[1]);
1788 if (node
.name
.has_prefix("_") && !unhidden
) {
1792 if (current_type_symbol_set
!= null) {
1793 current_type_symbol_set
.add (node
.name
);
1796 string field_name
= node
.name
;
1797 if (field_name
== "string") {
1798 // avoid conflict with string type
1802 var field
= new
Field (field_name
, type
, null, current_source_reference
);
1803 field
.access
= SymbolAccessibility
.PUBLIC
;
1805 if (field_name
!= node
.name
) {
1806 field
.set_cname (node
.name
);
1809 if (ctype
!= null) {
1810 field
.set_ctype (ctype
);
1813 if (cheader_filename
!= null) {
1814 field
.add_cheader_filename (cheader_filename
);
1817 field
.no_array_length
= true;
1822 private string[]?
get_attributes (string codenode
) {
1823 var attributes
= codenode_attributes_map
.get (codenode
);
1825 if (attributes
== null) {
1826 var dot_required
= (null != codenode
.chr (-1, '.'));
1827 var colon_required
= (null != codenode
.chr (-1, ':'));
1829 var pattern_specs
= codenode_attributes_patterns
.get_keys ();
1830 foreach (PatternSpec
* pattern
in pattern_specs
) {
1831 var pspec
= codenode_attributes_patterns
[pattern
];
1833 if ((dot_required
&& null == pspec
.chr (-1, '.')) ||
1834 (colon_required
&& null == pspec
.chr (-1, ':'))) {
1838 if (pattern
->match_string (codenode
)) {
1839 return get_attributes (pspec
);
1844 if (attributes
== null) {
1848 return attributes
.split (" ");
1851 private string eval (string s
) {
1852 return s
.offset (1).ndup (s
.size () - 2);
1855 private Signal?
parse_signal (IdlNodeSignal sig_node
) {
1856 weak IdlNode node
= (IdlNode
) sig_node
;
1858 if (sig_node
.deprecated
|| sig_node
.result
== null) {
1862 var sig
= new
Signal (fix_prop_name (node
.name
), parse_param (sig_node
.result
), current_source_reference
);
1863 sig
.access
= SymbolAccessibility
.PUBLIC
;
1865 var attributes
= get_attributes ("%s::%s".printf (current_data_type
.get_cname (), sig
.name
));
1866 if (attributes
!= null) {
1867 foreach (string attr
in attributes
) {
1868 var nv
= attr
.split ("=", 2);
1869 if (nv
[0] == "name") {
1870 sig
.set_cname (sig
.name
);
1871 sig
.name
= eval (nv
[1]);
1872 } else if (nv
[0] == "has_emitter" && eval (nv
[1]) == "1") {
1873 sig
.has_emitter
= true;
1874 } else if (nv
[0] == "hidden") {
1875 if (eval (nv
[1]) == "1") {
1882 sig
.is_virtual
= true;
1886 foreach (weak IdlNodeParam param
in sig_node
.parameters
) {
1888 // ignore implicit first signal parameter (sender)
1893 weak IdlNode param_node
= (IdlNode
) param
;
1895 ParameterDirection direction
;
1896 var param_type
= parse_param (param
, out direction
);
1897 var p
= new
FormalParameter (param_node
.name
, param_type
);
1898 p
.direction
= direction
;
1899 sig
.add_parameter (p
);
1901 attributes
= get_attributes ("%s::%s.%s".printf (current_data_type
.get_cname (), sig
.name
, param_node
.name
));
1902 if (attributes
!= null) {
1903 string ns_name
= null;
1904 foreach (string attr
in attributes
) {
1905 var nv
= attr
.split ("=", 2);
1906 if (nv
[0] == "is_array") {
1907 if (eval (nv
[1]) == "1") {
1908 param_type
= new
ArrayType (param_type
, 1, param_type
.source_reference
);
1909 p
.parameter_type
= param_type
;
1910 p
.direction
= ParameterDirection
.IN
;
1912 } else if (nv
[0] == "is_out") {
1913 if (eval (nv
[1]) == "1") {
1914 p
.direction
= ParameterDirection
.OUT
;
1916 } else if (nv
[0] == "is_ref") {
1917 if (eval (nv
[1]) == "1") {
1918 p
.direction
= ParameterDirection
.REF
;
1920 } else if (nv
[0] == "nullable") {
1921 if (eval (nv
[1]) == "1") {
1922 param_type
.nullable
= true;
1924 } else if (nv
[0] == "type_name") {
1925 ((UnresolvedType
) param_type
).unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1926 } else if (nv
[0] == "namespace_name") {
1927 ns_name
= eval (nv
[1]);
1930 if (ns_name
!= null) {
1931 ((UnresolvedType
) param_type
).unresolved_symbol
.inner
= new
UnresolvedSymbol (null, ns_name
);