3 * Copyright (C) 2006-2008 Jürg Billeter, Raffaele Sandrini
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Jürg Billeter <j@bitron.ch>
21 * 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 Gee
.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 cb
= new
Delegate (node
.name
, parse_param (f_node
.result
), current_source_reference
);
295 cb
.access
= SymbolAccessibility
.PUBLIC
;
297 bool check_has_target
= true;
299 var attributes
= get_attributes (node
.name
);
300 if (attributes
!= null) {
301 foreach (string attr
in attributes
) {
302 var nv
= attr
.split ("=", 2);
303 if (nv
[0] == "hidden") {
304 if (eval (nv
[1]) == "1") {
307 } else if (nv
[0] == "cheader_filename") {
308 cb
.add_cheader_filename (eval (nv
[1]));
309 } else if (nv
[0] == "has_target") {
310 if (eval (nv
[1]) == "0") {
311 check_has_target
= false;
312 } else if (eval (nv
[1]) == "1") {
313 cb
.has_target
= true;
319 uint remaining_params
= f_node
.parameters
.length ();
320 foreach (weak IdlNodeParam param
in f_node
.parameters
) {
321 weak IdlNode param_node
= (IdlNode
) param
;
323 if (check_has_target
&& remaining_params
== 1 && (param_node
.name
== "user_data" || param_node
.name
== "data")) {
324 // hide user_data parameter for instance delegates
325 cb
.has_target
= true;
327 string param_name
= param_node
.name
;
328 if (param_name
== "string") {
329 // avoid conflict with string type
331 } else if (param_name
== "self") {
332 // avoid conflict with delegate target
333 param_name
= "_self";
336 ParameterDirection direction
;
337 var p
= new
FormalParameter (param_name
, parse_param (param
, out direction
));
338 p
.direction
= direction
;
340 bool hide_param
= false;
341 bool show_param
= false;
342 attributes
= get_attributes ("%s.%s".printf (node
.name
, param_node
.name
));
343 if (attributes
!= null) {
344 foreach (string attr
in attributes
) {
345 var nv
= attr
.split ("=", 2);
346 if (nv
[0] == "hidden") {
347 if (eval (nv
[1]) == "1") {
349 } else if (eval (nv
[1]) == "0") {
356 if (show_param
|| !hide_param
) {
357 cb
.add_parameter (p
);
367 private bool is_reference_type (string cname
) {
368 var st_attributes
= get_attributes (cname
);
369 if (st_attributes
!= null) {
370 foreach (string attr
in st_attributes
) {
371 var nv
= attr
.split ("=", 2);
372 if (nv
[0] == "is_value_type" && eval (nv
[1]) == "1") {
380 private void parse_struct (IdlNodeStruct st_node
, Namespace ns
, IdlModule module
) {
381 weak IdlNode node
= (IdlNode
) st_node
;
383 if (st_node
.deprecated
) {
387 string name
= fix_type_name (node
.name
, ns
);
389 if (!is_reference_type (node
.name
)) {
390 var st
= ns
.scope
.lookup (name
) as Struct
;
392 st
= new
Struct (name
, current_source_reference
);
393 st
.access
= SymbolAccessibility
.PUBLIC
;
395 var st_attributes
= get_attributes (node
.name
);
396 if (st_attributes
!= null) {
397 foreach (string attr
in st_attributes
) {
398 var nv
= attr
.split ("=", 2);
399 if (nv
[0] == "cheader_filename") {
400 st
.add_cheader_filename (eval (nv
[1]));
401 } else if (nv
[0] == "hidden") {
402 if (eval (nv
[1]) == "1") {
405 } else if (nv
[0] == "simple_type") {
406 if (eval (nv
[1]) == "1") {
407 st
.set_simple_type (true);
414 current_source_file
.add_node (st
);
417 current_data_type
= st
;
419 foreach (weak IdlNode member
in st_node
.members
) {
420 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
421 var m
= parse_function ((IdlNodeFunction
) member
);
425 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
426 var f
= parse_field ((IdlNodeField
) member
);
433 current_data_type
= null;
435 var cl
= ns
.scope
.lookup (name
) as Class
;
437 string base_class
= null;
439 cl
= new
Class (name
, current_source_reference
);
440 cl
.access
= SymbolAccessibility
.PUBLIC
;
441 cl
.is_compact
= true;
443 var cl_attributes
= get_attributes (node
.name
);
444 if (cl_attributes
!= null) {
445 foreach (string attr
in cl_attributes
) {
446 var nv
= attr
.split ("=", 2);
447 if (nv
[0] == "cheader_filename") {
448 cl
.add_cheader_filename (eval (nv
[1]));
449 } else if (nv
[0] == "base_class") {
450 base_class
= eval (nv
[1]);
451 } else if (nv
[0] == "hidden") {
452 if (eval (nv
[1]) == "1") {
455 } else if (nv
[0] == "is_immutable") {
456 if (eval (nv
[1]) == "1") {
457 cl
.is_immutable
= true;
459 } else if (nv
[0] == "is_fundamental") {
460 if (eval (nv
[1]) == "1") {
461 cl
.is_compact
= false;
463 } else if (nv
[0] == "abstract" && base_class
!= null) {
464 if (eval (nv
[1]) == "1") {
465 cl
.is_abstract
= true;
472 current_source_file
.add_node (cl
);
474 if (base_class
!= null) {
475 var parent
= parse_type_string (base_class
);
476 cl
.add_base_type (parent
);
480 current_data_type
= cl
;
482 string ref_function
= null;
483 string unref_function
= null;
484 string copy_function
= null;
485 string free_function
= null;
487 foreach (weak IdlNode member
in st_node
.members
) {
488 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
489 if (member
.name
== "ref") {
490 ref_function
= ((IdlNodeFunction
) member
).symbol
;
491 } else if (member
.name
== "unref") {
492 unref_function
= ((IdlNodeFunction
) member
).symbol
;
493 } else if (member
.name
== "free" || member
.name
== "destroy") {
494 free_function
= ((IdlNodeFunction
) member
).symbol
;
496 if (member
.name
== "copy") {
497 copy_function
= ((IdlNodeFunction
) member
).symbol
;
499 var m
= parse_function ((IdlNodeFunction
) member
);
504 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
505 var f
= parse_field ((IdlNodeField
) member
);
512 if (ref_function
!= null) {
513 cl
.set_ref_function (ref_function
);
515 if (copy_function
!= null) {
516 cl
.set_dup_function (copy_function
);
518 if (unref_function
!= null) {
519 cl
.set_unref_function (unref_function
);
520 } else if (free_function
!= null) {
521 cl
.set_free_function (free_function
);
524 current_data_type
= null;
528 private void parse_union (IdlNodeUnion un_node
, Namespace ns
, IdlModule module
) {
529 weak IdlNode node
= (IdlNode
) un_node
;
531 if (un_node
.deprecated
) {
535 string name
= fix_type_name (node
.name
, ns
);
537 if (!is_reference_type (node
.name
)) {
538 var st
= ns
.scope
.lookup (name
) as Struct
;
540 st
= new
Struct (name
, current_source_reference
);
541 st
.access
= SymbolAccessibility
.PUBLIC
;
543 var st_attributes
= get_attributes (node
.name
);
544 if (st_attributes
!= null) {
545 foreach (string attr
in st_attributes
) {
546 var nv
= attr
.split ("=", 2);
547 if (nv
[0] == "cheader_filename") {
548 st
.add_cheader_filename (eval (nv
[1]));
549 } else if (nv
[0] == "hidden") {
550 if (eval (nv
[1]) == "1") {
558 current_source_file
.add_node (st
);
561 current_data_type
= st
;
563 foreach (weak IdlNode member
in un_node
.members
) {
564 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
565 var m
= parse_function ((IdlNodeFunction
) member
);
569 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
570 var f
= parse_field ((IdlNodeField
) member
);
577 current_data_type
= null;
579 var cl
= ns
.scope
.lookup (name
) as Class
;
581 cl
= new
Class (name
, current_source_reference
);
582 cl
.access
= SymbolAccessibility
.PUBLIC
;
583 cl
.is_compact
= true;
585 var cl_attributes
= get_attributes (node
.name
);
586 if (cl_attributes
!= null) {
587 foreach (string attr
in cl_attributes
) {
588 var nv
= attr
.split ("=", 2);
589 if (nv
[0] == "cheader_filename") {
590 cl
.add_cheader_filename (eval (nv
[1]));
591 } else if (nv
[0] == "hidden") {
592 if (eval (nv
[1]) == "1") {
600 current_source_file
.add_node (cl
);
603 current_data_type
= cl
;
605 string ref_function
= null;
606 string unref_function
= null;
607 string copy_function
= null;
608 string free_function
= null;
610 foreach (weak IdlNode member
in un_node
.members
) {
611 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
612 if (member
.name
== "ref") {
613 ref_function
= ((IdlNodeFunction
) member
).symbol
;
614 } else if (member
.name
== "unref") {
615 unref_function
= ((IdlNodeFunction
) member
).symbol
;
616 } else if (member
.name
== "free" || member
.name
== "destroy") {
617 free_function
= ((IdlNodeFunction
) member
).symbol
;
619 if (member
.name
== "copy") {
620 copy_function
= ((IdlNodeFunction
) member
).symbol
;
622 var m
= parse_function ((IdlNodeFunction
) member
);
627 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
628 var f
= parse_field ((IdlNodeField
) member
);
635 if (ref_function
!= null) {
636 cl
.set_ref_function (ref_function
);
638 if (copy_function
!= null) {
639 cl
.set_dup_function (copy_function
);
641 if (unref_function
!= null) {
642 cl
.set_unref_function (unref_function
);
643 } else if (free_function
!= null) {
644 cl
.set_free_function (free_function
);
647 current_data_type
= null;
651 private void parse_boxed (IdlNodeBoxed boxed_node
, Namespace ns
, IdlModule module
) {
652 weak IdlNode node
= (IdlNode
) boxed_node
;
654 string name
= fix_type_name (node
.name
, ns
);
656 var node_attributes
= get_attributes (node
.name
);
657 if (node_attributes
!= null) {
658 foreach (string attr
in node_attributes
) {
659 var nv
= attr
.split ("=", 2);
660 if (nv
[0] == "hidden") {
666 if (!is_reference_type (node
.name
)) {
667 var st
= ns
.scope
.lookup (name
) as Struct
;
669 st
= new
Struct (name
, current_source_reference
);
670 st
.access
= SymbolAccessibility
.PUBLIC
;
672 var st_attributes
= get_attributes (node
.name
);
673 if (st_attributes
!= null) {
674 foreach (string attr
in st_attributes
) {
675 var nv
= attr
.split ("=", 2);
676 if (nv
[0] == "cheader_filename") {
677 st
.add_cheader_filename (eval (nv
[1]));
683 st
.set_type_id (st
.get_upper_case_cname ("TYPE_"));
684 current_source_file
.add_node (st
);
687 current_data_type
= st
;
689 foreach (weak IdlNode member
in boxed_node
.members
) {
690 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
691 var m
= parse_function ((IdlNodeFunction
) member
);
695 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
696 var f
= parse_field ((IdlNodeField
) member
);
703 current_data_type
= null;
705 var cl
= ns
.scope
.lookup (name
) as Class
;
707 cl
= new
Class (name
, current_source_reference
);
708 cl
.access
= SymbolAccessibility
.PUBLIC
;
709 cl
.is_compact
= true;
711 var cl_attributes
= get_attributes (node
.name
);
712 if (cl_attributes
!= null) {
713 foreach (string attr
in cl_attributes
) {
714 var nv
= attr
.split ("=", 2);
715 if (nv
[0] == "cheader_filename") {
716 cl
.add_cheader_filename (eval (nv
[1]));
717 } else if (nv
[0] == "is_immutable") {
718 if (eval (nv
[1]) == "1") {
719 cl
.is_immutable
= true;
726 cl
.set_type_id (cl
.get_upper_case_cname ("TYPE_"));
727 current_source_file
.add_node (cl
);
730 current_data_type
= cl
;
732 string ref_function
= null;
733 string unref_function
= null;
734 string copy_function
= null;
735 string free_function
= null;
737 foreach (weak IdlNode member
in boxed_node
.members
) {
738 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
739 if (member
.name
== "ref") {
740 ref_function
= ((IdlNodeFunction
) member
).symbol
;
741 } else if (member
.name
== "unref") {
742 unref_function
= ((IdlNodeFunction
) member
).symbol
;
743 } else if (member
.name
== "free" || member
.name
== "destroy") {
744 free_function
= ((IdlNodeFunction
) member
).symbol
;
746 if (member
.name
== "copy") {
747 copy_function
= ((IdlNodeFunction
) member
).symbol
;
749 var m
= parse_function ((IdlNodeFunction
) member
);
754 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
755 var f
= parse_field ((IdlNodeField
) member
);
762 if (ref_function
!= null) {
763 cl
.set_ref_function (ref_function
);
765 if (copy_function
!= null) {
766 cl
.set_dup_function (copy_function
);
768 if (unref_function
!= null) {
769 cl
.set_unref_function (unref_function
);
770 } else if (free_function
!= null) {
771 cl
.set_free_function (free_function
);
774 current_data_type
= null;
778 private TypeSymbol?
parse_enum (IdlNodeEnum en_node
) {
779 weak IdlNode node
= (IdlNode
) en_node
;
781 var en
= new
Enum (node
.name
, current_source_reference
);
782 en
.access
= SymbolAccessibility
.PUBLIC
;
783 en
.has_type_id
= (en_node
.gtype_name
!= null && en_node
.gtype_name
!= "");
785 string common_prefix
= null;
787 foreach (weak IdlNode value
in en_node
.values
) {
788 if (common_prefix
== null) {
789 common_prefix
= value
.name
;
790 while (common_prefix
.len () > 0 && !common_prefix
.has_suffix ("_")) {
791 // FIXME: could easily be made faster
792 common_prefix
= common_prefix
.ndup (common_prefix
.size () - 1);
795 while (!value
.name
.has_prefix (common_prefix
)) {
796 common_prefix
= common_prefix
.ndup (common_prefix
.size () - 1);
799 while (common_prefix
.len () > 0 && (!common_prefix
.has_suffix ("_") ||
800 (value
.name
.offset (common_prefix
.size ()).get_char ().isdigit ()) && (value
.name
.len () - common_prefix
.len ()) <= 1)) {
801 // enum values may not consist solely of digits
802 common_prefix
= common_prefix
.ndup (common_prefix
.size () - 1);
806 bool is_errordomain
= false;
808 var cheader_filenames
= new ArrayList
<string> ();
810 var en_attributes
= get_attributes (node
.name
);
811 if (en_attributes
!= null) {
812 foreach (string attr
in en_attributes
) {
813 var nv
= attr
.split ("=", 2);
814 if (nv
[0] == "common_prefix") {
815 common_prefix
= eval (nv
[1]);
816 } else if (nv
[0] == "cheader_filename") {
817 cheader_filenames
.add (eval (nv
[1]));
818 en
.add_cheader_filename (eval (nv
[1]));
819 } else if (nv
[0] == "hidden") {
820 if (eval (nv
[1]) == "1") {
823 } else if (nv
[0] == "rename_to") {
824 en
.name
= eval (nv
[1]);
825 } else if (nv
[0] == "errordomain") {
826 if (eval (nv
[1]) == "1") {
827 is_errordomain
= true;
833 en
.set_cprefix (common_prefix
);
835 foreach (weak IdlNode value2
in en_node
.values
) {
836 var ev
= new
EnumValue (value2
.name
.offset (common_prefix
.len ()));
840 if (is_errordomain
) {
841 var ed
= new
ErrorDomain (en
.name
, current_source_reference
);
842 ed
.access
= SymbolAccessibility
.PUBLIC
;
843 ed
.set_cprefix (common_prefix
);
845 foreach (string filename
in cheader_filenames
) {
846 ed
.add_cheader_filename (filename
);
849 foreach (EnumValue ev
in en
.get_values ()) {
850 ed
.add_code (new
ErrorCode (ev
.name
));
859 private void parse_object (IdlNodeInterface node
, Namespace ns
, IdlModule module
) {
860 string name
= fix_type_name (((IdlNode
) node
).name
, ns
);
862 string base_class
= null;
864 var cl
= ns
.scope
.lookup (name
) as Class
;
866 cl
= new
Class (name
, current_source_reference
);
867 cl
.access
= SymbolAccessibility
.PUBLIC
;
869 var attributes
= get_attributes (node
.gtype_name
);
870 if (attributes
!= null) {
871 foreach (string attr
in attributes
) {
872 var nv
= attr
.split ("=", 2);
873 if (nv
[0] == "cheader_filename") {
874 cl
.add_cheader_filename (eval (nv
[1]));
875 } else if (nv
[0] == "base_class") {
876 base_class
= eval (nv
[1]);
877 } else if (nv
[0] == "hidden") {
878 if (eval (nv
[1]) == "1") {
881 } else if (nv
[0] == "type_check_function") {
882 cl
.type_check_function
= eval (nv
[1]);
883 } else if (nv
[0] == "abstract") {
884 if (eval (nv
[1]) == "1") {
885 cl
.is_abstract
= true;
892 current_source_file
.add_node (cl
);
895 if (base_class
!= null) {
896 var parent
= parse_type_string (base_class
);
897 cl
.add_base_type (parent
);
898 } else if (node
.parent
!= null) {
899 var parent
= parse_type_string (node
.parent
);
900 cl
.add_base_type (parent
);
902 var gobject_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "Object");
903 cl
.add_base_type (new UnresolvedType
.from_symbol (gobject_symbol
));
906 foreach (string iface_name
in node
.interfaces
) {
907 var iface
= parse_type_string (iface_name
);
908 cl
.add_base_type (iface
);
911 current_data_type
= cl
;
913 current_type_symbol_set
= new HashSet
<string> (str_hash
, str_equal
);
914 var current_type_func_map
= new HashMap
<string,weak IdlNodeFunction
> (str_hash
, str_equal
);
915 var current_type_vfunc_map
= new HashMap
<string,string> (str_hash
, str_equal
);
917 foreach (weak IdlNode member
in node
.members
) {
918 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
919 current_type_func_map
.set (member
.name
, (IdlNodeFunction
) member
);
921 if (member
.type
== IdlNodeTypeId
.VFUNC
) {
922 current_type_vfunc_map
.set (member
.name
, "1");
926 foreach (weak IdlNode member
in node
.members
) {
927 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
928 // Ignore if vfunc (handled below)
929 if (!current_type_vfunc_map
.contains (member
.name
)) {
930 var m
= parse_function ((IdlNodeFunction
) member
);
935 } else if (member
.type
== IdlNodeTypeId
.VFUNC
) {
936 var m
= parse_virtual ((IdlNodeVFunc
) member
, current_type_func_map
.get (member
.name
));
940 } else if (member
.type
== IdlNodeTypeId
.PROPERTY
) {
941 var prop
= parse_property ((IdlNodeProperty
) member
);
943 cl
.add_property (prop
);
945 } else if (member
.type
== IdlNodeTypeId
.SIGNAL
) {
946 var sig
= parse_signal ((IdlNodeSignal
) member
);
953 foreach (weak IdlNode member
in node
.members
) {
954 if (member
.type
== IdlNodeTypeId
.FIELD
) {
955 if (!current_type_symbol_set
.contains (member
.name
)) {
956 var f
= parse_field ((IdlNodeField
) member
);
964 foreach (Property prop
in cl
.get_properties ()) {
965 var getter
= "get_%s".printf (prop
.name
);
967 if (prop
.get_accessor
!= null && !current_type_symbol_set
.contains (getter
)) {
968 prop
.no_accessor_method
= true;
971 var setter
= "set_%s".printf (prop
.name
);
973 if (prop
.set_accessor
!= null && !current_type_symbol_set
.contains (setter
)) {
974 prop
.no_accessor_method
= true;
978 current_data_type
= null;
979 current_type_symbol_set
= null;
982 private void parse_interface (IdlNodeInterface node
, Namespace ns
, IdlModule module
) {
983 string name
= fix_type_name (node
.gtype_name
, ns
);
985 var iface
= ns
.scope
.lookup (name
) as Interface
;
987 iface
= new
Interface (name
, current_source_reference
);
988 iface
.access
= SymbolAccessibility
.PUBLIC
;
990 var attributes
= get_attributes (node
.gtype_name
);
991 if (attributes
!= null) {
992 foreach (string attr
in attributes
) {
993 var nv
= attr
.split ("=", 2);
994 if (nv
[0] == "cheader_filename") {
995 iface
.add_cheader_filename (eval (nv
[1]));
996 } else if (nv
[0] == "lower_case_csuffix") {
997 iface
.set_lower_case_csuffix (eval (nv
[1]));
1002 foreach (string prereq_name
in node
.prerequisites
) {
1003 var prereq
= parse_type_string (prereq_name
);
1004 iface
.add_prerequisite (prereq
);
1007 ns
.add_interface (iface
);
1008 current_source_file
.add_node (iface
);
1011 current_data_type
= iface
;
1013 var current_type_func_map
= new HashMap
<string,weak IdlNodeFunction
> (str_hash
, str_equal
);
1014 var current_type_vfunc_map
= new HashMap
<string,string> (str_hash
, str_equal
);
1016 foreach (weak IdlNode member
in node
.members
) {
1017 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1018 current_type_func_map
.set (member
.name
, (IdlNodeFunction
) member
);
1020 if (member
.type
== IdlNodeTypeId
.VFUNC
) {
1021 current_type_vfunc_map
.set (member
.name
, "1");
1025 foreach (weak IdlNode member
in node
.members
) {
1026 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1027 // Ignore if vfunc (handled below)
1028 if (!current_type_vfunc_map
.contains (member
.name
)) {
1029 var m
= parse_function ((IdlNodeFunction
) member
, true);
1031 iface
.add_method (m
);
1034 } else if (member
.type
== IdlNodeTypeId
.VFUNC
) {
1035 var m
= parse_virtual ((IdlNodeVFunc
) member
, current_type_func_map
.get (member
.name
), true);
1037 iface
.add_method (m
);
1039 } else if (member
.type
== IdlNodeTypeId
.PROPERTY
) {
1040 var prop
= parse_property ((IdlNodeProperty
) member
);
1042 iface
.add_property (prop
);
1044 } else if (member
.type
== IdlNodeTypeId
.SIGNAL
) {
1045 var sig
= parse_signal ((IdlNodeSignal
) member
);
1047 iface
.add_signal (sig
);
1052 current_data_type
= null;
1055 private DataType?
parse_type (IdlNodeType type_node
, out ParameterDirection direction
= null) {
1056 ParameterDirection dir
= ParameterDirection
.IN
;
1058 var type
= new
UnresolvedType ();
1059 if (type_node
.tag
== TypeTag
.VOID
) {
1060 if (type_node
.is_pointer
) {
1061 return new
PointerType (new
VoidType ());
1063 return new
VoidType ();
1065 } else if (type_node
.tag
== TypeTag
.BOOLEAN
) {
1066 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "bool");
1067 } else if (type_node
.tag
== TypeTag
.INT8
) {
1068 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "char");
1069 } else if (type_node
.tag
== TypeTag
.UINT8
) {
1070 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uchar");
1071 } else if (type_node
.tag
== TypeTag
.INT16
) {
1072 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int16");
1073 } else if (type_node
.tag
== TypeTag
.UINT16
) {
1074 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint16");
1075 } else if (type_node
.tag
== TypeTag
.INT32
) {
1076 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int32");
1077 } else if (type_node
.tag
== TypeTag
.UINT32
) {
1078 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint32");
1079 } else if (type_node
.tag
== TypeTag
.INT64
) {
1080 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int64");
1081 } else if (type_node
.tag
== TypeTag
.UINT64
) {
1082 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint64");
1083 } else if (type_node
.tag
== TypeTag
.INT
) {
1084 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int");
1085 } else if (type_node
.tag
== TypeTag
.UINT
) {
1086 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint");
1087 } else if (type_node
.tag
== TypeTag
.LONG
) {
1088 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "long");
1089 } else if (type_node
.tag
== TypeTag
.ULONG
) {
1090 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ulong");
1091 } else if (type_node
.tag
== TypeTag
.SSIZE
) {
1092 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ssize_t");
1093 } else if (type_node
.tag
== TypeTag
.SIZE
) {
1094 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "size_t");
1095 } else if (type_node
.tag
== TypeTag
.FLOAT
) {
1096 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "float");
1097 } else if (type_node
.tag
== TypeTag
.DOUBLE
) {
1098 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "double");
1099 } else if (type_node
.tag
== TypeTag
.UTF8
) {
1100 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1101 } else if (type_node
.tag
== TypeTag
.FILENAME
) {
1102 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1103 } else if (type_node
.tag
== TypeTag
.ARRAY
) {
1104 var element_type
= parse_type (type_node
.parameter_type1
);
1105 type
= element_type as UnresolvedType
;
1107 return element_type
;
1109 return new
ArrayType (element_type
, 1, element_type
.source_reference
);
1110 } else if (type_node
.tag
== TypeTag
.LIST
) {
1111 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "List");
1112 } else if (type_node
.tag
== TypeTag
.SLIST
) {
1113 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "SList");
1114 } else if (type_node
.tag
== TypeTag
.HASH
) {
1115 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "HashTable");
1116 } else if (type_node
.tag
== TypeTag
.ERROR
) {
1117 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "Error");
1118 } else if (type_node
.is_interface
) {
1119 var n
= type_node
.@
interface;
1125 if (n
.has_prefix ("const-")) {
1126 n
= n
.offset ("const-".len ());
1129 if (type_node
.is_pointer
&&
1130 (n
== "gchar" || n
== "char")) {
1131 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1132 if (type_node
.unparsed
.has_suffix ("**")) {
1133 dir
= ParameterDirection
.OUT
;
1135 } else if (n
== "gunichar") {
1136 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "unichar");
1137 } else if (n
== "gchar") {
1138 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "char");
1139 } else if (n
== "guchar" || n
== "guint8") {
1140 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uchar");
1141 if (type_node
.is_pointer
) {
1142 return new
ArrayType (type
, 1, type
.source_reference
);
1144 } else if (n
== "gushort") {
1145 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ushort");
1146 } else if (n
== "gshort") {
1147 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "short");
1148 } else if (n
== "gconstpointer" || n
== "void") {
1149 return new
PointerType (new
VoidType ());
1150 } else if (n
== "goffset" || n
== "off_t") {
1151 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int64");
1152 } else if (n
== "value_array") {
1153 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "ValueArray");
1154 } else if (n
== "time_t") {
1155 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ulong");
1156 } else if (n
== "socklen_t") {
1157 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint32");
1158 } else if (n
== "mode_t") {
1159 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint");
1160 } else if (n
== "gint" || n
== "pid_t") {
1161 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int");
1162 } else if (n
== "unsigned" || n
== "unsigned-int") {
1163 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint");
1164 } else if (n
== "FILE") {
1165 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "FileStream");
1166 } else if (n
== "struct") {
1167 return new
PointerType (new
VoidType ());
1168 } else if (n
== "iconv_t") {
1169 return new
PointerType (new
VoidType ());
1170 } else if (n
== "GType") {
1171 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "Type");
1172 if (type_node
.is_pointer
) {
1173 return new
ArrayType (type
, 1, type
.source_reference
);
1175 } else if (n
== "GStrv") {
1176 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1177 return new
ArrayType (type
, 1, type
.source_reference
);
1179 var named_type
= parse_type_string (n
);
1180 type
= named_type as UnresolvedType
;
1184 if (is_simple_type (n
)) {
1185 if (type_node
.is_pointer
) {
1186 dir
= ParameterDirection
.OUT
;
1188 } else if (type_node
.unparsed
.has_suffix ("**")) {
1189 dir
= ParameterDirection
.OUT
;
1193 stdout
.printf ("%d\n", type_node
.tag
);
1195 if (&direction
!= null) {
1201 private bool is_simple_type (string type_name
) {
1202 var st
= cname_type_map
[type_name
] as Struct
;
1203 if (st
!= null && st
.is_simple_type ()) {
1210 private DataType
parse_type_string (string n
) {
1211 if (n
== "va_list") {
1213 return new
PointerType (new
VoidType ());
1216 var type
= new
UnresolvedType ();
1218 var dt
= cname_type_map
[n
];
1220 UnresolvedSymbol parent_symbol
= null;
1221 if (dt
.parent_symbol
.name
!= null) {
1222 parent_symbol
= new
UnresolvedSymbol (null, dt
.parent_symbol
.name
);
1224 type
.unresolved_symbol
= new
UnresolvedSymbol (parent_symbol
, dt
.name
);
1228 var type_attributes
= get_attributes (n
);
1230 string ns_name
= null;
1232 if (null != type_attributes
) {
1233 foreach (string attr
in type_attributes
) {
1234 var nv
= attr
.split ("=", 2);
1236 if (nv
[0] == "cprefix") {
1237 type
.unresolved_symbol
= new
UnresolvedSymbol (null, n
.offset (eval (nv
[1]).len ()));
1238 } else if (nv
[0] == "name") {
1239 type
.unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1240 } else if (nv
[0] == "namespace") {
1241 ns_name
= eval (nv
[1]);
1242 } else if (nv
[0] == "rename_to") {
1243 type
.unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1248 if (type
.unresolved_symbol
!= null) {
1249 if (type
.unresolved_symbol
.name
== "pointer") {
1250 return new
PointerType (new
VoidType ());
1252 if (ns_name
!= null) {
1253 type
.unresolved_symbol
.inner
= new
UnresolvedSymbol (null, ns_name
);
1258 if (n
.has_prefix (current_namespace
.name
)) {
1259 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, current_namespace
.name
), n
.offset (current_namespace
.name
.len ()));
1260 } else if (n
.has_prefix ("G")) {
1261 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), n
.offset (1));
1263 var name_parts
= n
.split (".", 2);
1264 if (name_parts
[1] == null) {
1265 type
.unresolved_symbol
= new
UnresolvedSymbol (null, name_parts
[0]);
1267 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, name_parts
[0]), name_parts
[1]);
1274 private DataType?
parse_param (IdlNodeParam param
, out ParameterDirection direction
= null) {
1275 var type
= parse_type (param
.type
, out direction
);
1277 // disable for now as null_ok not yet correctly set
1278 // type.non_null = !param.null_ok;
1283 private Method?
create_method (string name
, string symbol
, IdlNodeParam? res
, GLib
.List
<IdlNodeParam
>? parameters
, bool is_constructor
, bool is_interface
) {
1284 DataType return_type
= null;
1286 return_type
= parse_param (res
);
1290 if (!is_interface
&& (is_constructor
|| name
.has_prefix ("new"))) {
1291 m
= new
CreationMethod (null, name
, current_source_reference
);
1292 m
.has_construct_function
= false;
1293 if (m
.name
== "new") {
1295 } else if (m
.name
.has_prefix ("new_")) {
1296 m
.name
= m
.name
.offset ("new_".len ());
1298 // For classes, check whether a creation method return type equals to the
1299 // type of the class created. If the types do not match (e.g. in most
1300 // gtk widgets) add an attribute to the creation method indicating the used
1302 if (current_data_type is Class
&& res
!= null) {
1303 if ("%s*".printf (current_data_type
.get_cname()) != res
.type
.unparsed
) {
1304 ((CreationMethod
)m
).custom_return_type_cname
= res
.type
.unparsed
;
1308 m
= new
Method (name
, return_type
, current_source_reference
);
1310 m
.access
= SymbolAccessibility
.PUBLIC
;
1312 if (current_type_symbol_set
!= null) {
1313 current_type_symbol_set
.add (name
);
1316 if (current_data_type
!= null) {
1317 var sig_attributes
= get_attributes ("%s::%s".printf (current_data_type
.get_cname (), name
));
1318 if (sig_attributes
!= null) {
1319 foreach (string attr
in sig_attributes
) {
1320 var nv
= attr
.split ("=", 2);
1321 if (nv
[0] == "has_emitter" && eval (nv
[1]) == "1") {
1328 bool add_ellipsis
= false;
1329 bool suppress_throws
= false;
1331 var attributes
= get_attributes (symbol
);
1332 if (attributes
!= null) {
1333 foreach (string attr
in attributes
) {
1334 var nv
= attr
.split ("=", 2);
1335 if (nv
[0] == "name") {
1336 m
.set_cname (m
.name
);
1337 m
.name
= eval (nv
[1]);
1338 } else if (nv
[0] == "hidden") {
1339 if (eval (nv
[1]) == "1") {
1342 } else if (nv
[0] == "ellipsis") {
1343 if (eval (nv
[1]) == "1") {
1344 add_ellipsis
= true;
1346 } else if (nv
[0] == "transfer_ownership") {
1347 if (eval (nv
[1]) == "1") {
1348 return_type
.value_owned
= true;
1350 } else if (nv
[0] == "nullable") {
1351 if (eval (nv
[1]) == "1") {
1352 return_type
.nullable
= true;
1354 } else if (nv
[0] == "sentinel") {
1355 m
.sentinel
= eval (nv
[1]);
1356 } else if (nv
[0] == "is_array") {
1357 if (eval (nv
[1]) == "1") {
1358 return_type
= new
ArrayType (return_type
, 1, return_type
.source_reference
);
1359 m
.return_type
= return_type
;
1361 } else if (nv
[0] == "throws") {
1362 if (eval (nv
[1]) == "0") {
1363 suppress_throws
= true;
1365 } else if (nv
[0] == "no_array_length") {
1366 if (eval (nv
[1]) == "1") {
1367 m
.no_array_length
= true;
1369 } else if (nv
[0] == "type_name") {
1370 var sym
= new
UnresolvedSymbol (null, eval (nv
[1]));
1371 if (return_type is UnresolvedType
) {
1372 ((UnresolvedType
) return_type
).unresolved_symbol
= sym
;
1374 // Overwrite old return_type, so "type_name" must be before any
1375 // other return type modifying metadata
1376 m
.return_type
= return_type
= new UnresolvedType
.from_symbol (sym
, return_type
.source_reference
);
1378 } else if (nv
[0] == "type_arguments") {
1379 var type_args
= eval (nv
[1]).split (",");
1380 foreach (string type_arg
in type_args
) {
1381 var arg_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, type_arg
));
1382 arg_type
.value_owned
= true;
1383 return_type
.add_type_argument (arg_type
);
1385 } else if (nv
[0] == "cheader_filename") {
1386 m
.add_cheader_filename (eval (nv
[1]));
1387 } else if (nv
[0] == "abstract") {
1388 if (eval (nv
[1]) == "1") {
1389 m
.is_abstract
= true;
1391 } else if (nv
[0] == "virtual") {
1392 if (eval (nv
[1]) == "1") {
1393 m
.is_virtual
= true;
1400 m
.set_cname (symbol
);
1403 FormalParameter last_param
= null;
1404 DataType last_param_type
= null;
1405 foreach (weak IdlNodeParam param
in parameters
) {
1406 weak IdlNode param_node
= (IdlNode
) param
;
1410 if (!(m is CreationMethod
) &&
1411 current_data_type
!= null &&
1412 param
.type
.is_interface
&&
1413 (param_node
.name
== "self" ||
1414 param
.type
.@
interface.has_suffix (current_data_type
.get_cname ()))) {
1417 } else if (!(m is CreationMethod
) &&
1418 current_data_type
!= null &&
1419 param
.type
.is_interface
&&
1420 (param_node
.name
== "klass" ||
1421 param
.type
.@
interface.has_suffix ("%sClass".printf(current_data_type
.get_cname ())))) {
1423 m
.binding
= MemberBinding
.CLASS
;
1424 if (m
.name
.has_prefix ("class_")) {
1425 m
.name
= m
.name
.substring ("class_".len (), m
.name
.len () - "class_".len ());
1430 m
.binding
= MemberBinding
.STATIC
;
1434 if (suppress_throws
== false && param_is_exception (param
)) {
1435 m
.add_error_type (parse_type (param
.type
));
1439 string param_name
= param_node
.name
;
1440 if (param_name
== "result") {
1441 // avoid conflict with generated result variable
1442 param_name
= "_result";
1443 } else if (param_name
== "string") {
1444 // avoid conflict with string type
1447 ParameterDirection direction
;
1448 var param_type
= parse_param (param
, out direction
);
1449 var p
= new
FormalParameter (param_name
, param_type
);
1450 p
.direction
= direction
;
1452 bool hide_param
= false;
1453 bool show_param
= false;
1454 bool set_array_length_pos
= false;
1455 double array_length_pos
= 0;
1456 bool set_delegate_target_pos
= false;
1457 double delegate_target_pos
= 0;
1458 bool array_requested
= false;
1459 attributes
= get_attributes ("%s.%s".printf (symbol
, param_node
.name
));
1460 if (attributes
!= null) {
1461 foreach (string attr
in attributes
) {
1462 var nv
= attr
.split ("=", 2);
1463 if (nv
[0] == "is_array") {
1464 if (eval (nv
[1]) == "1") {
1465 param_type
= new
ArrayType (param_type
, 1, param_type
.source_reference
);
1466 p
.parameter_type
= param_type
;
1467 p
.direction
= ParameterDirection
.IN
;
1468 array_requested
= true;
1470 } else if (nv
[0] == "is_out") {
1471 if (eval (nv
[1]) == "1") {
1472 p
.direction
= ParameterDirection
.OUT
;
1473 if (!array_requested
&& param_type is ArrayType
) {
1474 var array_type
= (ArrayType
) param_type
;
1475 param_type
= array_type
.element_type
;
1476 p
.parameter_type
= param_type
;
1479 } else if (nv
[0] == "is_ref") {
1480 if (eval (nv
[1]) == "1") {
1481 p
.direction
= ParameterDirection
.REF
;
1482 if (!array_requested
&& param_type is ArrayType
) {
1483 var array_type
= (ArrayType
) param_type
;
1484 param_type
= array_type
.element_type
;
1485 p
.parameter_type
= param_type
;
1488 } else if (nv
[0] == "nullable") {
1489 if (eval (nv
[1]) == "1") {
1490 param_type
.nullable
= true;
1492 } else if (nv
[0] == "transfer_ownership") {
1493 if (eval (nv
[1]) == "1") {
1494 param_type
.value_owned
= true;
1496 } else if (nv
[0] == "takes_ownership") {
1497 if (eval (nv
[1]) == "1") {
1498 param_type
.value_owned
= true;
1500 } else if (nv
[0] == "value_owned") {
1501 if (eval (nv
[1]) == "0") {
1502 param_type
.value_owned
= false;
1503 } else if (eval (nv
[1]) == "1") {
1504 param_type
.value_owned
= true;
1506 } else if (nv
[0] == "hidden") {
1507 if (eval (nv
[1]) == "1") {
1509 } else if (eval (nv
[1]) == "0") {
1512 } else if (nv
[0] == "array_length_pos") {
1513 set_array_length_pos
= true;
1514 array_length_pos
= eval (nv
[1]).to_double ();
1515 } else if (nv
[0] == "delegate_target_pos") {
1516 set_delegate_target_pos
= true;
1517 delegate_target_pos
= eval (nv
[1]).to_double ();
1518 } else if (nv
[0] == "type_name") {
1519 ((UnresolvedType
) param_type
).unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1520 } else if (nv
[0] == "ctype") {
1521 p
.ctype
= eval (nv
[1]);
1522 } else if (nv
[0] == "type_arguments") {
1523 var type_args
= eval (nv
[1]).split (",");
1524 foreach (string type_arg
in type_args
) {
1525 var arg_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, type_arg
));
1526 arg_type
.value_owned
= true;
1527 param_type
.add_type_argument (arg_type
);
1533 if (last_param
!= null && p
.name
== "n_" + last_param
.name
) {
1534 // last_param is array, p is array length
1535 last_param_type
= new
ArrayType (last_param_type
, 1, last_param_type
.source_reference
);
1536 last_param
.parameter_type
= last_param_type
;
1537 last_param
.direction
= ParameterDirection
.IN
;
1539 // hide array length param
1541 } else if (last_param
!= null && p
.name
== "user_data") {
1542 // last_param is delegate
1544 // hide deleate target param
1548 if (show_param
|| !hide_param
) {
1549 m
.add_parameter (p
);
1550 if (set_array_length_pos
) {
1551 p
.carray_length_parameter_position
= array_length_pos
;
1553 if (set_delegate_target_pos
) {
1554 p
.cdelegate_target_parameter_position
= delegate_target_pos
;
1559 last_param_type
= param_type
;
1563 // no parameters => static method
1564 m
.binding
= MemberBinding
.STATIC
;
1567 if (last_param
!= null && last_param
.name
.has_prefix ("first_")) {
1568 last_param
.ellipsis
= true;
1569 } else if (add_ellipsis
) {
1570 m
.add_parameter (new FormalParameter
.with_ellipsis ());
1576 private bool param_is_exception (IdlNodeParam param
) {
1577 if (!param
.type
.is_error
) {
1580 var s
= param
.type
.unparsed
.chomp ();
1581 if (s
.has_suffix ("**")) {
1587 private Method?
parse_function (IdlNodeFunction f
, bool is_interface
= false) {
1588 weak IdlNode node
= (IdlNode
) f
;
1594 return create_method (node
.name
, f
.symbol
, f
.result
, f
.parameters
, f
.is_constructor
, is_interface
);
1597 private Method
parse_virtual (IdlNodeVFunc v
, IdlNodeFunction? func
, bool is_interface
= false) {
1598 weak IdlNode node
= (IdlNode
) v
;
1599 string symbol
= "%s%s".printf (current_data_type
.get_lower_case_cprefix(), node
.name
);
1602 symbol
= func
.symbol
;
1605 Method m
= create_method (node
.name
, symbol
, v
.result
, func
!= null ? func
.parameters
: v
.parameters
, false, is_interface
);
1607 m
.binding
= MemberBinding
.INSTANCE
;
1608 m
.is_virtual
= !(m
.is_abstract
|| is_interface
);
1609 m
.is_abstract
= m
.is_abstract
|| is_interface
;
1612 m
.attributes
.append (new
Attribute ("NoWrapper", null));
1619 private string fix_prop_name (string name
) {
1620 var str
= new
StringBuilder ();
1624 while (i
.len () > 0) {
1625 unichar c
= i
.get_char ();
1629 str
.append_unichar (c
);
1638 private Property?
parse_property (IdlNodeProperty prop_node
) {
1639 weak IdlNode node
= (IdlNode
) prop_node
;
1641 if (prop_node
.deprecated
) {
1645 if (!prop_node
.readable
&& !prop_node
.writable
) {
1646 // buggy GIDL definition
1647 prop_node
.readable
= true;
1648 prop_node
.writable
= true;
1651 PropertyAccessor get_acc
= null;
1652 PropertyAccessor set_acc
= null;
1653 if (prop_node
.readable
) {
1654 get_acc
= new
PropertyAccessor (true, false, false, null, null);
1656 if (prop_node
.writable
) {
1657 set_acc
= new
PropertyAccessor (false, false, false, null, null);
1658 if (prop_node
.construct_only
) {
1659 set_acc
.construction
= true;
1661 set_acc
.writable
= true;
1662 set_acc
.construction
= prop_node
.@
construct;
1666 var prop
= new
Property (fix_prop_name (node
.name
), parse_type (prop_node
.type
), get_acc
, set_acc
, current_source_reference
);
1667 prop
.access
= SymbolAccessibility
.PUBLIC
;
1668 prop
.interface_only
= true;
1670 var attributes
= get_attributes ("%s:%s".printf (current_data_type
.get_cname (), node
.name
));
1671 if (attributes
!= null) {
1672 foreach (string attr
in attributes
) {
1673 var nv
= attr
.split ("=", 2);
1674 if (nv
[0] == "hidden") {
1675 if (eval (nv
[1]) == "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 prop
.property_type
.add_type_argument (arg_type
);
1689 if (current_type_symbol_set
!= null) {
1690 current_type_symbol_set
.add (prop
.name
);
1696 private Constant?
parse_constant (IdlNodeConstant const_node
) {
1697 weak IdlNode node
= (IdlNode
) const_node
;
1699 var type
= parse_type (const_node
.type
);
1704 var c
= new
Constant (node
.name
, type
, null, current_source_reference
);
1706 string[] attributes
= get_attributes (node
.name
);
1707 if (attributes
!= null) {
1708 foreach (string attr
in attributes
) {
1709 var nv
= attr
.split ("=", 2);
1710 if (nv
[0] == "cheader_filename") {
1711 c
.add_cheader_filename (eval (nv
[1]));
1712 } else if (nv
[0] == "hidden") {
1713 if (eval (nv
[1]) == "1") {
1720 c
.access
= SymbolAccessibility
.PUBLIC
;
1725 private Field?
parse_field (IdlNodeField field_node
) {
1726 weak IdlNode node
= (IdlNode
) field_node
;
1727 bool unhidden
= false;
1729 var type
= parse_type (field_node
.type
);
1734 string cheader_filename
= null;
1735 string ctype
= null;
1737 var attributes
= get_attributes ("%s.%s".printf (current_data_type
.get_cname (), node
.name
));
1738 if (attributes
!= null) {
1739 foreach (string attr
in attributes
) {
1740 var nv
= attr
.split ("=", 2);
1741 if (nv
[0] == "hidden") {
1742 if (eval (nv
[1]) == "1") {
1747 } else if (nv
[0] == "is_array") {
1748 if (eval (nv
[1]) == "1") {
1749 type
= new
ArrayType (type
, 1, type
.source_reference
);
1751 } else if (nv
[0] == "weak") {
1752 if (eval (nv
[1]) == "0") {
1753 type
.value_owned
= true;
1755 } else if (nv
[0] == "type_name") {
1756 ((UnresolvedType
) type
).unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1757 } else if (nv
[0] == "type_arguments") {
1758 var type_args
= eval (nv
[1]).split (",");
1759 foreach (string type_arg
in type_args
) {
1760 var arg_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, type_arg
));
1761 arg_type
.value_owned
= true;
1762 type
.add_type_argument (arg_type
);
1764 } else if (nv
[0] == "cheader_filename") {
1765 cheader_filename
= eval (nv
[1]);
1766 } else if (nv
[0] == "ctype") {
1767 ctype
= eval (nv
[1]);
1772 if (node
.name
.has_prefix("_") && !unhidden
) {
1776 if (current_type_symbol_set
!= null) {
1777 current_type_symbol_set
.add (node
.name
);
1780 string field_name
= node
.name
;
1781 if (field_name
== "string") {
1782 // avoid conflict with string type
1786 var field
= new
Field (field_name
, type
, null, current_source_reference
);
1787 field
.access
= SymbolAccessibility
.PUBLIC
;
1789 if (field_name
!= node
.name
) {
1790 field
.set_cname (node
.name
);
1793 if (ctype
!= null) {
1794 field
.set_ctype (ctype
);
1797 if (cheader_filename
!= null) {
1798 field
.add_cheader_filename (cheader_filename
);
1801 field
.no_array_length
= true;
1807 private string[]?
get_attributes (string codenode
) {
1808 var attributes
= codenode_attributes_map
.get (codenode
);
1810 if (attributes
== null) {
1811 var dot_required
= (null != codenode
.chr (-1, '.'));
1812 var colon_required
= (null != codenode
.chr (-1, ':'));
1814 var pattern_specs
= codenode_attributes_patterns
.get_keys ();
1815 foreach (PatternSpec
* pattern
in pattern_specs
) {
1816 var pspec
= codenode_attributes_patterns
[pattern
];
1818 if ((dot_required
&& null == pspec
.chr (-1, '.')) ||
1819 (colon_required
&& null == pspec
.chr (-1, ':'))) {
1823 if (pattern
->match_string (codenode
)) {
1824 return get_attributes (pspec
);
1829 if (attributes
== null) {
1833 return attributes
.split (" ");
1836 private string eval (string s
) {
1837 return s
.offset (1).ndup (s
.size () - 2);
1840 private Signal?
parse_signal (IdlNodeSignal sig_node
) {
1841 weak IdlNode node
= (IdlNode
) sig_node
;
1843 if (sig_node
.deprecated
|| sig_node
.result
== null) {
1847 var sig
= new
Signal (fix_prop_name (node
.name
), parse_param (sig_node
.result
), current_source_reference
);
1848 sig
.access
= SymbolAccessibility
.PUBLIC
;
1850 var attributes
= get_attributes ("%s::%s".printf (current_data_type
.get_cname (), sig
.name
));
1851 if (attributes
!= null) {
1852 foreach (string attr
in attributes
) {
1853 var nv
= attr
.split ("=", 2);
1854 if (nv
[0] == "name") {
1855 sig
.set_cname (sig
.name
);
1856 sig
.name
= eval (nv
[1]);
1857 } else if (nv
[0] == "has_emitter" && eval (nv
[1]) == "1") {
1858 sig
.has_emitter
= true;
1859 } else if (nv
[0] == "hidden") {
1860 if (eval (nv
[1]) == "1") {
1867 sig
.is_virtual
= true;
1871 foreach (weak IdlNodeParam param
in sig_node
.parameters
) {
1873 // ignore implicit first signal parameter (sender)
1878 weak IdlNode param_node
= (IdlNode
) param
;
1880 ParameterDirection direction
;
1881 var param_type
= parse_param (param
, out direction
);
1882 var p
= new
FormalParameter (param_node
.name
, param_type
);
1883 p
.direction
= direction
;
1884 sig
.add_parameter (p
);
1886 attributes
= get_attributes ("%s::%s.%s".printf (current_data_type
.get_cname (), sig
.name
, param_node
.name
));
1887 if (attributes
!= null) {
1888 string ns_name
= null;
1889 foreach (string attr
in attributes
) {
1890 var nv
= attr
.split ("=", 2);
1891 if (nv
[0] == "is_array") {
1892 if (eval (nv
[1]) == "1") {
1893 param_type
= new
ArrayType (param_type
, 1, param_type
.source_reference
);
1894 p
.parameter_type
= param_type
;
1895 p
.direction
= ParameterDirection
.IN
;
1897 } else if (nv
[0] == "is_out") {
1898 if (eval (nv
[1]) == "1") {
1899 p
.direction
= ParameterDirection
.OUT
;
1901 } else if (nv
[0] == "is_ref") {
1902 if (eval (nv
[1]) == "1") {
1903 p
.direction
= ParameterDirection
.REF
;
1905 } else if (nv
[0] == "nullable") {
1906 if (eval (nv
[1]) == "1") {
1907 param_type
.nullable
= true;
1909 } else if (nv
[0] == "type_name") {
1910 ((UnresolvedType
) param_type
).unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1911 } else if (nv
[0] == "namespace_name") {
1912 ns_name
= eval (nv
[1]);
1915 if (ns_name
!= null) {
1916 ((UnresolvedType
) param_type
).unresolved_symbol
.inner
= new
UnresolvedSymbol (null, ns_name
);