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
)) {
112 FileUtils
.get_contents (metadata_filename
, out metadata
, out metadata_len
);
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
.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;
317 uint remaining_params
= f_node
.parameters
.length ();
318 foreach (weak IdlNodeParam param
in f_node
.parameters
) {
319 weak IdlNode param_node
= (IdlNode
) param
;
321 if (check_has_target
&& remaining_params
== 1 && (param_node
.name
== "user_data" || param_node
.name
== "data")) {
322 // hide user_data parameter for instance delegates
323 cb
.has_target
= true;
325 string param_name
= param_node
.name
;
326 if (param_name
== "string") {
327 // avoid conflict with string type
329 } else if (param_name
== "self") {
330 // avoid conflict with delegate target
331 param_name
= "_self";
334 ParameterDirection direction
;
335 var p
= new
FormalParameter (param_name
, parse_param (param
, out direction
));
336 p
.direction
= direction
;
337 cb
.add_parameter (p
);
346 private bool is_reference_type (string cname
) {
347 var st_attributes
= get_attributes (cname
);
348 if (st_attributes
!= null) {
349 foreach (string attr
in st_attributes
) {
350 var nv
= attr
.split ("=", 2);
351 if (nv
[0] == "is_value_type" && eval (nv
[1]) == "1") {
359 private void parse_struct (IdlNodeStruct st_node
, Namespace ns
, IdlModule module
) {
360 weak IdlNode node
= (IdlNode
) st_node
;
362 if (st_node
.deprecated
) {
366 string name
= fix_type_name (node
.name
, ns
);
368 if (!is_reference_type (node
.name
)) {
369 var st
= ns
.scope
.lookup (name
) as Struct
;
371 st
= new
Struct (name
, current_source_reference
);
372 st
.access
= SymbolAccessibility
.PUBLIC
;
374 var st_attributes
= get_attributes (node
.name
);
375 if (st_attributes
!= null) {
376 foreach (string attr
in st_attributes
) {
377 var nv
= attr
.split ("=", 2);
378 if (nv
[0] == "cheader_filename") {
379 st
.add_cheader_filename (eval (nv
[1]));
380 } else if (nv
[0] == "hidden") {
381 if (eval (nv
[1]) == "1") {
384 } else if (nv
[0] == "simple_type") {
385 if (eval (nv
[1]) == "1") {
386 st
.set_simple_type (true);
393 current_source_file
.add_node (st
);
396 current_data_type
= st
;
398 foreach (weak IdlNode member
in st_node
.members
) {
399 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
400 var m
= parse_function ((IdlNodeFunction
) member
);
404 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
405 var f
= parse_field ((IdlNodeField
) member
);
412 current_data_type
= null;
414 var cl
= ns
.scope
.lookup (name
) as Class
;
416 string base_class
= null;
418 cl
= new
Class (name
, current_source_reference
);
419 cl
.access
= SymbolAccessibility
.PUBLIC
;
420 cl
.is_compact
= true;
422 var cl_attributes
= get_attributes (node
.name
);
423 if (cl_attributes
!= null) {
424 foreach (string attr
in cl_attributes
) {
425 var nv
= attr
.split ("=", 2);
426 if (nv
[0] == "cheader_filename") {
427 cl
.add_cheader_filename (eval (nv
[1]));
428 } else if (nv
[0] == "base_class") {
429 base_class
= eval (nv
[1]);
430 } else if (nv
[0] == "hidden") {
431 if (eval (nv
[1]) == "1") {
434 } else if (nv
[0] == "is_immutable") {
435 if (eval (nv
[1]) == "1") {
436 cl
.is_immutable
= true;
438 } else if (nv
[0] == "is_fundamental") {
439 if (eval (nv
[1]) == "1") {
440 cl
.is_compact
= false;
442 } else if (nv
[0] == "abstract" && base_class
!= null) {
443 if (eval (nv
[1]) == "1") {
444 cl
.is_abstract
= true;
451 current_source_file
.add_node (cl
);
453 if (base_class
!= null) {
454 var parent
= parse_type_string (base_class
);
455 cl
.add_base_type (parent
);
459 current_data_type
= cl
;
461 string ref_function
= null;
462 string unref_function
= null;
463 string copy_function
= null;
464 string free_function
= null;
466 foreach (weak IdlNode member
in st_node
.members
) {
467 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
468 if (member
.name
== "ref") {
469 ref_function
= ((IdlNodeFunction
) member
).symbol
;
470 } else if (member
.name
== "unref") {
471 unref_function
= ((IdlNodeFunction
) member
).symbol
;
472 } else if (member
.name
== "free" || member
.name
== "destroy") {
473 free_function
= ((IdlNodeFunction
) member
).symbol
;
475 if (member
.name
== "copy") {
476 copy_function
= ((IdlNodeFunction
) member
).symbol
;
478 var m
= parse_function ((IdlNodeFunction
) member
);
483 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
484 var f
= parse_field ((IdlNodeField
) member
);
491 if (ref_function
!= null) {
492 cl
.set_ref_function (ref_function
);
494 if (copy_function
!= null) {
495 cl
.set_dup_function (copy_function
);
497 if (unref_function
!= null) {
498 cl
.set_unref_function (unref_function
);
499 } else if (free_function
!= null) {
500 cl
.set_free_function (free_function
);
503 current_data_type
= null;
507 private void parse_union (IdlNodeUnion un_node
, Namespace ns
, IdlModule module
) {
508 weak IdlNode node
= (IdlNode
) un_node
;
510 if (un_node
.deprecated
) {
514 string name
= fix_type_name (node
.name
, ns
);
516 if (!is_reference_type (node
.name
)) {
517 var st
= ns
.scope
.lookup (name
) as Struct
;
519 st
= new
Struct (name
, current_source_reference
);
520 st
.access
= SymbolAccessibility
.PUBLIC
;
522 var st_attributes
= get_attributes (node
.name
);
523 if (st_attributes
!= null) {
524 foreach (string attr
in st_attributes
) {
525 var nv
= attr
.split ("=", 2);
526 if (nv
[0] == "cheader_filename") {
527 st
.add_cheader_filename (eval (nv
[1]));
528 } else if (nv
[0] == "hidden") {
529 if (eval (nv
[1]) == "1") {
537 current_source_file
.add_node (st
);
540 current_data_type
= st
;
542 foreach (weak IdlNode member
in un_node
.members
) {
543 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
544 var m
= parse_function ((IdlNodeFunction
) member
);
548 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
549 var f
= parse_field ((IdlNodeField
) member
);
556 current_data_type
= null;
558 var cl
= ns
.scope
.lookup (name
) as Class
;
560 cl
= new
Class (name
, current_source_reference
);
561 cl
.access
= SymbolAccessibility
.PUBLIC
;
562 cl
.is_compact
= true;
564 var cl_attributes
= get_attributes (node
.name
);
565 if (cl_attributes
!= null) {
566 foreach (string attr
in cl_attributes
) {
567 var nv
= attr
.split ("=", 2);
568 if (nv
[0] == "cheader_filename") {
569 cl
.add_cheader_filename (eval (nv
[1]));
570 } else if (nv
[0] == "hidden") {
571 if (eval (nv
[1]) == "1") {
579 current_source_file
.add_node (cl
);
582 current_data_type
= cl
;
584 string ref_function
= null;
585 string unref_function
= null;
586 string copy_function
= null;
587 string free_function
= null;
589 foreach (weak IdlNode member
in un_node
.members
) {
590 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
591 if (member
.name
== "ref") {
592 ref_function
= ((IdlNodeFunction
) member
).symbol
;
593 } else if (member
.name
== "unref") {
594 unref_function
= ((IdlNodeFunction
) member
).symbol
;
595 } else if (member
.name
== "free" || member
.name
== "destroy") {
596 free_function
= ((IdlNodeFunction
) member
).symbol
;
598 if (member
.name
== "copy") {
599 copy_function
= ((IdlNodeFunction
) member
).symbol
;
601 var m
= parse_function ((IdlNodeFunction
) member
);
606 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
607 var f
= parse_field ((IdlNodeField
) member
);
614 if (ref_function
!= null) {
615 cl
.set_ref_function (ref_function
);
617 if (copy_function
!= null) {
618 cl
.set_dup_function (copy_function
);
620 if (unref_function
!= null) {
621 cl
.set_unref_function (unref_function
);
622 } else if (free_function
!= null) {
623 cl
.set_free_function (free_function
);
626 current_data_type
= null;
630 private void parse_boxed (IdlNodeBoxed boxed_node
, Namespace ns
, IdlModule module
) {
631 weak IdlNode node
= (IdlNode
) boxed_node
;
633 string name
= fix_type_name (node
.name
, ns
);
635 var node_attributes
= get_attributes (node
.name
);
636 if (node_attributes
!= null) {
637 foreach (string attr
in node_attributes
) {
638 var nv
= attr
.split ("=", 2);
639 if (nv
[0] == "hidden") {
645 if (!is_reference_type (node
.name
)) {
646 var st
= ns
.scope
.lookup (name
) as Struct
;
648 st
= new
Struct (name
, current_source_reference
);
649 st
.access
= SymbolAccessibility
.PUBLIC
;
651 var st_attributes
= get_attributes (node
.name
);
652 if (st_attributes
!= null) {
653 foreach (string attr
in st_attributes
) {
654 var nv
= attr
.split ("=", 2);
655 if (nv
[0] == "cheader_filename") {
656 st
.add_cheader_filename (eval (nv
[1]));
662 st
.set_type_id (st
.get_upper_case_cname ("TYPE_"));
663 current_source_file
.add_node (st
);
666 current_data_type
= st
;
668 foreach (weak IdlNode member
in boxed_node
.members
) {
669 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
670 var m
= parse_function ((IdlNodeFunction
) member
);
674 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
675 var f
= parse_field ((IdlNodeField
) member
);
682 current_data_type
= null;
684 var cl
= ns
.scope
.lookup (name
) as Class
;
686 cl
= new
Class (name
, current_source_reference
);
687 cl
.access
= SymbolAccessibility
.PUBLIC
;
688 cl
.is_compact
= true;
690 var cl_attributes
= get_attributes (node
.name
);
691 if (cl_attributes
!= null) {
692 foreach (string attr
in cl_attributes
) {
693 var nv
= attr
.split ("=", 2);
694 if (nv
[0] == "cheader_filename") {
695 cl
.add_cheader_filename (eval (nv
[1]));
696 } else if (nv
[0] == "is_immutable") {
697 if (eval (nv
[1]) == "1") {
698 cl
.is_immutable
= true;
705 cl
.set_type_id (cl
.get_upper_case_cname ("TYPE_"));
706 current_source_file
.add_node (cl
);
709 current_data_type
= cl
;
711 string ref_function
= null;
712 string unref_function
= null;
713 string copy_function
= null;
714 string free_function
= null;
716 foreach (weak IdlNode member
in boxed_node
.members
) {
717 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
718 if (member
.name
== "ref") {
719 ref_function
= ((IdlNodeFunction
) member
).symbol
;
720 } else if (member
.name
== "unref") {
721 unref_function
= ((IdlNodeFunction
) member
).symbol
;
722 } else if (member
.name
== "free" || member
.name
== "destroy") {
723 free_function
= ((IdlNodeFunction
) member
).symbol
;
725 if (member
.name
== "copy") {
726 copy_function
= ((IdlNodeFunction
) member
).symbol
;
728 var m
= parse_function ((IdlNodeFunction
) member
);
733 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
734 var f
= parse_field ((IdlNodeField
) member
);
741 if (ref_function
!= null) {
742 cl
.set_ref_function (ref_function
);
744 if (copy_function
!= null) {
745 cl
.set_dup_function (copy_function
);
747 if (unref_function
!= null) {
748 cl
.set_unref_function (unref_function
);
749 } else if (free_function
!= null) {
750 cl
.set_free_function (free_function
);
753 current_data_type
= null;
757 private TypeSymbol?
parse_enum (IdlNodeEnum en_node
) {
758 weak IdlNode node
= (IdlNode
) en_node
;
760 var en
= new
Enum (node
.name
, current_source_reference
);
761 en
.access
= SymbolAccessibility
.PUBLIC
;
762 en
.has_type_id
= (en_node
.gtype_name
!= null && en_node
.gtype_name
!= "");
764 string common_prefix
= null;
766 foreach (weak IdlNode value
in en_node
.values
) {
767 if (common_prefix
== null) {
768 common_prefix
= value
.name
;
769 while (common_prefix
.len () > 0 && !common_prefix
.has_suffix ("_")) {
770 // FIXME: could easily be made faster
771 common_prefix
= common_prefix
.ndup (common_prefix
.size () - 1);
774 while (!value
.name
.has_prefix (common_prefix
)) {
775 common_prefix
= common_prefix
.ndup (common_prefix
.size () - 1);
778 while (common_prefix
.len () > 0 && (!common_prefix
.has_suffix ("_") ||
779 (value
.name
.offset (common_prefix
.size ()).get_char ().isdigit ()) && (value
.name
.len () - common_prefix
.len ()) <= 1)) {
780 // enum values may not consist solely of digits
781 common_prefix
= common_prefix
.ndup (common_prefix
.size () - 1);
785 bool is_errordomain
= false;
787 var cheader_filenames
= new ArrayList
<string> ();
789 var en_attributes
= get_attributes (node
.name
);
790 if (en_attributes
!= null) {
791 foreach (string attr
in en_attributes
) {
792 var nv
= attr
.split ("=", 2);
793 if (nv
[0] == "common_prefix") {
794 common_prefix
= eval (nv
[1]);
795 } else if (nv
[0] == "cheader_filename") {
796 cheader_filenames
.add (eval (nv
[1]));
797 en
.add_cheader_filename (eval (nv
[1]));
798 } else if (nv
[0] == "hidden") {
799 if (eval (nv
[1]) == "1") {
802 } else if (nv
[0] == "rename_to") {
803 en
.name
= eval (nv
[1]);
804 } else if (nv
[0] == "errordomain") {
805 if (eval (nv
[1]) == "1") {
806 is_errordomain
= true;
812 en
.set_cprefix (common_prefix
);
814 foreach (weak IdlNode value2
in en_node
.values
) {
815 var ev
= new
EnumValue (value2
.name
.offset (common_prefix
.len ()));
819 if (is_errordomain
) {
820 var ed
= new
ErrorDomain (en
.name
);
821 ed
.access
= SymbolAccessibility
.PUBLIC
;
822 ed
.set_cprefix (common_prefix
);
824 foreach (string filename
in cheader_filenames
) {
825 ed
.add_cheader_filename (filename
);
828 foreach (EnumValue ev
in en
.get_values ()) {
829 ed
.add_code (new
ErrorCode (ev
.name
));
838 private void parse_object (IdlNodeInterface node
, Namespace ns
, IdlModule module
) {
839 string name
= fix_type_name (((IdlNode
) node
).name
, ns
);
841 string base_class
= null;
843 var cl
= ns
.scope
.lookup (name
) as Class
;
845 cl
= new
Class (name
, current_source_reference
);
846 cl
.access
= SymbolAccessibility
.PUBLIC
;
848 var attributes
= get_attributes (node
.gtype_name
);
849 if (attributes
!= null) {
850 foreach (string attr
in attributes
) {
851 var nv
= attr
.split ("=", 2);
852 if (nv
[0] == "cheader_filename") {
853 cl
.add_cheader_filename (eval (nv
[1]));
854 } else if (nv
[0] == "base_class") {
855 base_class
= eval (nv
[1]);
856 } else if (nv
[0] == "hidden") {
857 if (eval (nv
[1]) == "1") {
860 } else if (nv
[0] == "type_check_function") {
861 cl
.type_check_function
= eval (nv
[1]);
862 } else if (nv
[0] == "abstract") {
863 if (eval (nv
[1]) == "1") {
864 cl
.is_abstract
= true;
871 current_source_file
.add_node (cl
);
874 if (base_class
!= null) {
875 var parent
= parse_type_string (base_class
);
876 cl
.add_base_type (parent
);
877 } else if (node
.parent
!= null) {
878 var parent
= parse_type_string (node
.parent
);
879 cl
.add_base_type (parent
);
881 var gobject_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "Object");
882 cl
.add_base_type (new UnresolvedType
.from_symbol (gobject_symbol
));
885 foreach (string iface_name
in node
.interfaces
) {
886 var iface
= parse_type_string (iface_name
);
887 cl
.add_base_type (iface
);
890 current_data_type
= cl
;
892 current_type_symbol_set
= new HashSet
<string> (str_hash
, str_equal
);
893 var current_type_func_map
= new HashMap
<string,weak IdlNodeFunction
> (str_hash
, str_equal
);
894 var current_type_vfunc_map
= new HashMap
<string,string> (str_hash
, str_equal
);
896 foreach (weak IdlNode member
in node
.members
) {
897 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
898 current_type_func_map
.set (member
.name
, (IdlNodeFunction
) member
);
900 if (member
.type
== IdlNodeTypeId
.VFUNC
) {
901 current_type_vfunc_map
.set (member
.name
, "1");
905 foreach (weak IdlNode member
in node
.members
) {
906 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
907 // Ignore if vfunc (handled below)
908 if (!current_type_vfunc_map
.contains (member
.name
)) {
909 var m
= parse_function ((IdlNodeFunction
) member
);
914 } else if (member
.type
== IdlNodeTypeId
.VFUNC
) {
915 var m
= parse_virtual ((IdlNodeVFunc
) member
, current_type_func_map
.get (member
.name
));
919 } else if (member
.type
== IdlNodeTypeId
.PROPERTY
) {
920 var prop
= parse_property ((IdlNodeProperty
) member
);
922 cl
.add_property (prop
);
924 } else if (member
.type
== IdlNodeTypeId
.SIGNAL
) {
925 var sig
= parse_signal ((IdlNodeSignal
) member
);
932 foreach (weak IdlNode member
in node
.members
) {
933 if (member
.type
== IdlNodeTypeId
.FIELD
) {
934 if (!current_type_symbol_set
.contains (member
.name
)) {
935 var f
= parse_field ((IdlNodeField
) member
);
943 foreach (Property prop
in cl
.get_properties ()) {
944 var getter
= "get_%s".printf (prop
.name
);
946 if (prop
.get_accessor
!= null && !current_type_symbol_set
.contains (getter
)) {
947 prop
.no_accessor_method
= true;
950 var setter
= "set_%s".printf (prop
.name
);
952 if (prop
.set_accessor
!= null && !current_type_symbol_set
.contains (setter
)) {
953 prop
.no_accessor_method
= true;
957 current_data_type
= null;
958 current_type_symbol_set
= null;
961 private void parse_interface (IdlNodeInterface node
, Namespace ns
, IdlModule module
) {
962 string name
= fix_type_name (node
.gtype_name
, ns
);
964 var iface
= ns
.scope
.lookup (name
) as Interface
;
966 iface
= new
Interface (name
, current_source_reference
);
967 iface
.access
= SymbolAccessibility
.PUBLIC
;
969 var attributes
= get_attributes (node
.gtype_name
);
970 if (attributes
!= null) {
971 foreach (string attr
in attributes
) {
972 var nv
= attr
.split ("=", 2);
973 if (nv
[0] == "cheader_filename") {
974 iface
.add_cheader_filename (eval (nv
[1]));
975 } else if (nv
[0] == "lower_case_csuffix") {
976 iface
.set_lower_case_csuffix (eval (nv
[1]));
981 foreach (string prereq_name
in node
.prerequisites
) {
982 var prereq
= parse_type_string (prereq_name
);
983 iface
.add_prerequisite (prereq
);
986 ns
.add_interface (iface
);
987 current_source_file
.add_node (iface
);
990 current_data_type
= iface
;
992 var current_type_func_map
= new HashMap
<string,weak IdlNodeFunction
> (str_hash
, str_equal
);
993 var current_type_vfunc_map
= new HashMap
<string,string> (str_hash
, str_equal
);
995 foreach (weak IdlNode member
in node
.members
) {
996 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
997 current_type_func_map
.set (member
.name
, (IdlNodeFunction
) member
);
999 if (member
.type
== IdlNodeTypeId
.VFUNC
) {
1000 current_type_vfunc_map
.set (member
.name
, "1");
1004 foreach (weak IdlNode member
in node
.members
) {
1005 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1006 // Ignore if vfunc (handled below)
1007 if (!current_type_vfunc_map
.contains (member
.name
)) {
1008 var m
= parse_function ((IdlNodeFunction
) member
, true);
1010 iface
.add_method (m
);
1013 } else if (member
.type
== IdlNodeTypeId
.VFUNC
) {
1014 var m
= parse_virtual ((IdlNodeVFunc
) member
, current_type_func_map
.get (member
.name
), true);
1016 iface
.add_method (m
);
1018 } else if (member
.type
== IdlNodeTypeId
.PROPERTY
) {
1019 var prop
= parse_property ((IdlNodeProperty
) member
);
1021 iface
.add_property (prop
);
1023 } else if (member
.type
== IdlNodeTypeId
.SIGNAL
) {
1024 var sig
= parse_signal ((IdlNodeSignal
) member
);
1026 iface
.add_signal (sig
);
1031 current_data_type
= null;
1034 private DataType?
parse_type (IdlNodeType type_node
, out ParameterDirection direction
= null) {
1035 ParameterDirection dir
= ParameterDirection
.IN
;
1037 var type
= new
UnresolvedType ();
1038 if (type_node
.tag
== TypeTag
.VOID
) {
1039 if (type_node
.is_pointer
) {
1040 return new
PointerType (new
VoidType ());
1042 return new
VoidType ();
1044 } else if (type_node
.tag
== TypeTag
.BOOLEAN
) {
1045 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "bool");
1046 } else if (type_node
.tag
== TypeTag
.INT8
) {
1047 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "char");
1048 } else if (type_node
.tag
== TypeTag
.UINT8
) {
1049 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uchar");
1050 } else if (type_node
.tag
== TypeTag
.INT16
) {
1051 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "short");
1052 } else if (type_node
.tag
== TypeTag
.UINT16
) {
1053 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ushort");
1054 } else if (type_node
.tag
== TypeTag
.INT32
) {
1055 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int");
1056 } else if (type_node
.tag
== TypeTag
.UINT32
) {
1057 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint");
1058 } else if (type_node
.tag
== TypeTag
.INT64
) {
1059 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int64");
1060 } else if (type_node
.tag
== TypeTag
.UINT64
) {
1061 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint64");
1062 } else if (type_node
.tag
== TypeTag
.INT
) {
1063 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int");
1064 } else if (type_node
.tag
== TypeTag
.UINT
) {
1065 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint");
1066 } else if (type_node
.tag
== TypeTag
.LONG
) {
1067 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "long");
1068 } else if (type_node
.tag
== TypeTag
.ULONG
) {
1069 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ulong");
1070 } else if (type_node
.tag
== TypeTag
.SSIZE
) {
1071 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "long");
1072 } else if (type_node
.tag
== TypeTag
.SIZE
) {
1073 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ulong");
1074 } else if (type_node
.tag
== TypeTag
.FLOAT
) {
1075 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "float");
1076 } else if (type_node
.tag
== TypeTag
.DOUBLE
) {
1077 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "double");
1078 } else if (type_node
.tag
== TypeTag
.UTF8
) {
1079 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1080 } else if (type_node
.tag
== TypeTag
.FILENAME
) {
1081 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1082 } else if (type_node
.tag
== TypeTag
.ARRAY
) {
1083 var element_type
= parse_type (type_node
.parameter_type1
);
1084 type
= element_type as UnresolvedType
;
1086 return element_type
;
1088 return new
ArrayType (element_type
, 1, element_type
.source_reference
);
1089 } else if (type_node
.tag
== TypeTag
.LIST
) {
1090 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "List");
1091 } else if (type_node
.tag
== TypeTag
.SLIST
) {
1092 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "SList");
1093 } else if (type_node
.tag
== TypeTag
.HASH
) {
1094 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "HashTable");
1095 } else if (type_node
.tag
== TypeTag
.ERROR
) {
1096 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "Error");
1097 } else if (type_node
.is_interface
) {
1098 var n
= type_node
.@
interface;
1104 if (n
.has_prefix ("const-")) {
1105 n
= n
.offset ("const-".len ());
1108 if (type_node
.is_pointer
&&
1109 (n
== "gchar" || n
== "char")) {
1110 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1111 if (type_node
.unparsed
.has_suffix ("**")) {
1112 dir
= ParameterDirection
.OUT
;
1114 } else if (n
== "gunichar") {
1115 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "unichar");
1116 } else if (n
== "gchar") {
1117 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "char");
1118 } else if (n
== "guchar" || n
== "guint8") {
1119 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uchar");
1120 if (type_node
.is_pointer
) {
1121 return new
ArrayType (type
, 1, type
.source_reference
);
1123 } else if (n
== "gushort") {
1124 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ushort");
1125 } else if (n
== "gshort") {
1126 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "short");
1127 } else if (n
== "gconstpointer" || n
== "void") {
1128 return new
PointerType (new
VoidType ());
1129 } else if (n
== "goffset" || n
== "off_t") {
1130 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int64");
1131 } else if (n
== "value_array") {
1132 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "ValueArray");
1133 } else if (n
== "time_t") {
1134 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ulong");
1135 } else if (n
== "socklen_t") {
1136 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint32");
1137 } else if (n
== "mode_t") {
1138 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint");
1139 } else if (n
== "gint" || n
== "pid_t") {
1140 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int");
1141 } else if (n
== "unsigned" || n
== "unsigned-int") {
1142 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint");
1143 } else if (n
== "FILE") {
1144 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "FileStream");
1145 } else if (n
== "struct") {
1146 return new
PointerType (new
VoidType ());
1147 } else if (n
== "iconv_t") {
1148 return new
PointerType (new
VoidType ());
1149 } else if (n
== "GType") {
1150 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "Type");
1151 if (type_node
.is_pointer
) {
1152 return new
ArrayType (type
, 1, type
.source_reference
);
1154 } else if (n
== "GStrv") {
1155 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1156 return new
ArrayType (type
, 1, type
.source_reference
);
1158 var named_type
= parse_type_string (n
);
1159 type
= named_type as UnresolvedType
;
1163 if (is_simple_type (n
)) {
1164 if (type_node
.is_pointer
) {
1165 dir
= ParameterDirection
.OUT
;
1167 } else if (type_node
.unparsed
.has_suffix ("**")) {
1168 dir
= ParameterDirection
.OUT
;
1172 stdout
.printf ("%d\n", type_node
.tag
);
1174 if (&direction
!= null) {
1180 private bool is_simple_type (string type_name
) {
1181 var st
= cname_type_map
[type_name
] as Struct
;
1182 if (st
!= null && st
.is_simple_type ()) {
1189 private DataType
parse_type_string (string n
) {
1190 if (n
== "va_list") {
1192 return new
PointerType (new
VoidType ());
1195 var type
= new
UnresolvedType ();
1197 var dt
= cname_type_map
[n
];
1199 UnresolvedSymbol parent_symbol
= null;
1200 if (dt
.parent_symbol
.name
!= null) {
1201 parent_symbol
= new
UnresolvedSymbol (null, dt
.parent_symbol
.name
);
1203 type
.unresolved_symbol
= new
UnresolvedSymbol (parent_symbol
, dt
.name
);
1207 var type_attributes
= get_attributes (n
);
1209 string ns_name
= null;
1211 if (null != type_attributes
) {
1212 foreach (string attr
in type_attributes
) {
1213 var nv
= attr
.split ("=", 2);
1215 if (nv
[0] == "cprefix") {
1216 type
.unresolved_symbol
= new
UnresolvedSymbol (null, n
.offset (eval (nv
[1]).len ()));
1217 } else if (nv
[0] == "name") {
1218 type
.unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1219 } else if (nv
[0] == "namespace") {
1220 ns_name
= eval (nv
[1]);
1221 } else if (nv
[0] == "rename_to") {
1222 type
.unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1227 if (type
.unresolved_symbol
!= null) {
1228 if (type
.unresolved_symbol
.name
== "pointer") {
1229 return new
PointerType (new
VoidType ());
1231 if (ns_name
!= null) {
1232 type
.unresolved_symbol
.inner
= new
UnresolvedSymbol (null, ns_name
);
1237 if (n
.has_prefix (current_namespace
.name
)) {
1238 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, current_namespace
.name
), n
.offset (current_namespace
.name
.len ()));
1239 } else if (n
.has_prefix ("G")) {
1240 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), n
.offset (1));
1242 var name_parts
= n
.split (".", 2);
1243 if (name_parts
[1] == null) {
1244 type
.unresolved_symbol
= new
UnresolvedSymbol (null, name_parts
[0]);
1246 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, name_parts
[0]), name_parts
[1]);
1253 private DataType?
parse_param (IdlNodeParam param
, out ParameterDirection direction
= null) {
1254 var type
= parse_type (param
.type
, out direction
);
1256 // disable for now as null_ok not yet correctly set
1257 // type.non_null = !param.null_ok;
1262 private Method?
create_method (string name
, string symbol
, IdlNodeParam? res
, GLib
.List
<IdlNodeParam
>? parameters
, bool is_constructor
, bool is_interface
) {
1263 DataType return_type
= null;
1265 return_type
= parse_param (res
);
1269 if (!is_interface
&& (is_constructor
|| name
.has_prefix ("new"))) {
1270 m
= new
CreationMethod (null, name
, current_source_reference
);
1271 m
.has_construct_function
= false;
1272 if (m
.name
== "new") {
1274 } else if (m
.name
.has_prefix ("new_")) {
1275 m
.name
= m
.name
.offset ("new_".len ());
1277 // For classes, check whether a creation method return type equals to the
1278 // type of the class created. If the types do not match (e.g. in most
1279 // gtk widgets) add an attribute to the creation method indicating the used
1281 if (current_data_type is Class
&& res
!= null) {
1282 if ("%s*".printf (current_data_type
.get_cname()) != res
.type
.unparsed
) {
1283 ((CreationMethod
)m
).custom_return_type_cname
= res
.type
.unparsed
;
1287 m
= new
Method (name
, return_type
, current_source_reference
);
1289 m
.access
= SymbolAccessibility
.PUBLIC
;
1291 if (current_type_symbol_set
!= null) {
1292 current_type_symbol_set
.add (name
);
1295 if (current_data_type
!= null) {
1296 var sig_attributes
= get_attributes ("%s::%s".printf (current_data_type
.get_cname (), name
));
1297 if (sig_attributes
!= null) {
1298 foreach (string attr
in sig_attributes
) {
1299 var nv
= attr
.split ("=", 2);
1300 if (nv
[0] == "has_emitter" && eval (nv
[1]) == "1") {
1307 bool add_ellipsis
= false;
1308 bool suppress_throws
= false;
1310 var attributes
= get_attributes (symbol
);
1311 if (attributes
!= null) {
1312 foreach (string attr
in attributes
) {
1313 var nv
= attr
.split ("=", 2);
1314 if (nv
[0] == "name") {
1315 m
.set_cname (m
.name
);
1316 m
.name
= eval (nv
[1]);
1317 } else if (nv
[0] == "hidden") {
1318 if (eval (nv
[1]) == "1") {
1321 } else if (nv
[0] == "ellipsis") {
1322 if (eval (nv
[1]) == "1") {
1323 add_ellipsis
= true;
1325 } else if (nv
[0] == "transfer_ownership") {
1326 if (eval (nv
[1]) == "1") {
1327 return_type
.value_owned
= true;
1329 } else if (nv
[0] == "nullable") {
1330 if (eval (nv
[1]) == "1") {
1331 return_type
.nullable
= true;
1333 } else if (nv
[0] == "sentinel") {
1334 m
.sentinel
= eval (nv
[1]);
1335 } else if (nv
[0] == "is_array") {
1336 if (eval (nv
[1]) == "1") {
1337 return_type
= new
ArrayType (return_type
, 1, return_type
.source_reference
);
1338 m
.return_type
= return_type
;
1340 } else if (nv
[0] == "throws") {
1341 if (eval (nv
[1]) == "0") {
1342 suppress_throws
= true;
1344 } else if (nv
[0] == "no_array_length") {
1345 if (eval (nv
[1]) == "1") {
1346 m
.no_array_length
= true;
1348 } else if (nv
[0] == "type_name") {
1349 var sym
= new
UnresolvedSymbol (null, eval (nv
[1]));
1350 if (return_type is UnresolvedType
) {
1351 ((UnresolvedType
) return_type
).unresolved_symbol
= sym
;
1353 // Overwrite old return_type, so "type_name" must be before any
1354 // other return type modifying metadata
1355 m
.return_type
= return_type
= new UnresolvedType
.from_symbol (sym
, return_type
.source_reference
);
1357 } else if (nv
[0] == "type_arguments") {
1358 var type_args
= eval (nv
[1]).split (",");
1359 foreach (string type_arg
in type_args
) {
1360 var arg_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, type_arg
));
1361 arg_type
.value_owned
= true;
1362 return_type
.add_type_argument (arg_type
);
1364 } else if (nv
[0] == "cheader_filename") {
1365 m
.add_cheader_filename (eval (nv
[1]));
1366 } else if (nv
[0] == "abstract") {
1367 if (eval (nv
[1]) == "1") {
1368 m
.is_abstract
= true;
1370 } else if (nv
[0] == "virtual") {
1371 if (eval (nv
[1]) == "1") {
1372 m
.is_virtual
= true;
1379 m
.set_cname (symbol
);
1382 FormalParameter last_param
= null;
1383 DataType last_param_type
= null;
1384 foreach (weak IdlNodeParam param
in parameters
) {
1385 weak IdlNode param_node
= (IdlNode
) param
;
1389 if (!(m is CreationMethod
) &&
1390 current_data_type
!= null &&
1391 param
.type
.is_interface
&&
1392 (param_node
.name
== "self" ||
1393 param
.type
.@
interface.has_suffix (current_data_type
.get_cname ()))) {
1396 } else if (!(m is CreationMethod
) &&
1397 current_data_type
!= null &&
1398 param
.type
.is_interface
&&
1399 (param_node
.name
== "klass" ||
1400 param
.type
.@
interface.has_suffix ("%sClass".printf(current_data_type
.get_cname ())))) {
1402 m
.binding
= MemberBinding
.CLASS
;
1403 if (m
.name
.has_prefix ("class_")) {
1404 m
.name
= m
.name
.substring ("class_".len (), m
.name
.len () - "class_".len ());
1409 m
.binding
= MemberBinding
.STATIC
;
1413 if (suppress_throws
== false && param_is_exception (param
)) {
1414 m
.add_error_type (parse_type (param
.type
));
1418 string param_name
= param_node
.name
;
1419 if (param_name
== "result") {
1420 // avoid conflict with generated result variable
1421 param_name
= "_result";
1422 } else if (param_name
== "string") {
1423 // avoid conflict with string type
1426 ParameterDirection direction
;
1427 var param_type
= parse_param (param
, out direction
);
1428 var p
= new
FormalParameter (param_name
, param_type
);
1429 p
.direction
= direction
;
1431 bool hide_param
= false;
1432 bool show_param
= false;
1433 bool set_array_length_pos
= false;
1434 double array_length_pos
= 0;
1435 bool set_delegate_target_pos
= false;
1436 double delegate_target_pos
= 0;
1437 bool array_requested
= false;
1438 var attributes
= get_attributes ("%s.%s".printf (symbol
, param_node
.name
));
1439 if (attributes
!= null) {
1440 foreach (string attr
in attributes
) {
1441 var nv
= attr
.split ("=", 2);
1442 if (nv
[0] == "is_array") {
1443 if (eval (nv
[1]) == "1") {
1444 param_type
= new
ArrayType (param_type
, 1, param_type
.source_reference
);
1445 p
.parameter_type
= param_type
;
1446 p
.direction
= ParameterDirection
.IN
;
1447 array_requested
= true;
1449 } else if (nv
[0] == "is_out") {
1450 if (eval (nv
[1]) == "1") {
1451 p
.direction
= ParameterDirection
.OUT
;
1452 if (!array_requested
&& param_type is ArrayType
) {
1453 var array_type
= (ArrayType
) param_type
;
1454 param_type
= array_type
.element_type
;
1455 p
.parameter_type
= param_type
;
1458 } else if (nv
[0] == "is_ref") {
1459 if (eval (nv
[1]) == "1") {
1460 p
.direction
= ParameterDirection
.REF
;
1461 if (!array_requested
&& param_type is ArrayType
) {
1462 var array_type
= (ArrayType
) param_type
;
1463 param_type
= array_type
.element_type
;
1464 p
.parameter_type
= param_type
;
1467 } else if (nv
[0] == "nullable") {
1468 if (eval (nv
[1]) == "1") {
1469 param_type
.nullable
= true;
1471 } else if (nv
[0] == "transfer_ownership") {
1472 if (eval (nv
[1]) == "1") {
1473 param_type
.value_owned
= true;
1475 } else if (nv
[0] == "takes_ownership") {
1476 if (eval (nv
[1]) == "1") {
1477 param_type
.value_owned
= true;
1479 } else if (nv
[0] == "value_owned") {
1480 if (eval (nv
[1]) == "0") {
1481 param_type
.value_owned
= false;
1482 } else if (eval (nv
[1]) == "1") {
1483 param_type
.value_owned
= true;
1485 } else if (nv
[0] == "hidden") {
1486 if (eval (nv
[1]) == "1") {
1488 } else if (eval (nv
[1]) == "0") {
1491 } else if (nv
[0] == "array_length_pos") {
1492 set_array_length_pos
= true;
1493 array_length_pos
= eval (nv
[1]).to_double ();
1494 } else if (nv
[0] == "delegate_target_pos") {
1495 set_delegate_target_pos
= true;
1496 delegate_target_pos
= eval (nv
[1]).to_double ();
1497 } else if (nv
[0] == "type_name") {
1498 ((UnresolvedType
) param_type
).unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1499 } else if (nv
[0] == "ctype") {
1500 p
.ctype
= eval (nv
[1]);
1501 } else if (nv
[0] == "type_arguments") {
1502 var type_args
= eval (nv
[1]).split (",");
1503 foreach (string type_arg
in type_args
) {
1504 var arg_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, type_arg
));
1505 arg_type
.value_owned
= true;
1506 param_type
.add_type_argument (arg_type
);
1512 if (last_param
!= null && p
.name
== "n_" + last_param
.name
) {
1513 // last_param is array, p is array length
1514 last_param_type
= new
ArrayType (last_param_type
, 1, last_param_type
.source_reference
);
1515 last_param
.parameter_type
= last_param_type
;
1516 last_param
.direction
= ParameterDirection
.IN
;
1518 // hide array length param
1520 } else if (last_param
!= null && p
.name
== "user_data") {
1521 // last_param is delegate
1523 // hide deleate target param
1527 if (show_param
|| !hide_param
) {
1528 m
.add_parameter (p
);
1529 if (set_array_length_pos
) {
1530 p
.carray_length_parameter_position
= array_length_pos
;
1532 if (set_delegate_target_pos
) {
1533 p
.cdelegate_target_parameter_position
= delegate_target_pos
;
1538 last_param_type
= param_type
;
1542 // no parameters => static method
1543 m
.binding
= MemberBinding
.STATIC
;
1546 if (last_param
!= null && last_param
.name
.has_prefix ("first_")) {
1547 last_param
.ellipsis
= true;
1548 } else if (add_ellipsis
) {
1549 m
.add_parameter (new FormalParameter
.with_ellipsis ());
1555 private bool param_is_exception (IdlNodeParam param
) {
1556 if (!param
.type
.is_error
) {
1559 var s
= param
.type
.unparsed
.chomp ();
1560 if (s
.has_suffix ("**")) {
1566 private Method?
parse_function (IdlNodeFunction f
, bool is_interface
= false) {
1567 weak IdlNode node
= (IdlNode
) f
;
1573 return create_method (node
.name
, f
.symbol
, f
.result
, f
.parameters
, f
.is_constructor
, is_interface
);
1576 private Method
parse_virtual (IdlNodeVFunc v
, IdlNodeFunction? func
, bool is_interface
= false) {
1577 weak IdlNode node
= (IdlNode
) v
;
1578 string symbol
= "%s%s".printf (current_data_type
.get_lower_case_cprefix(), node
.name
);
1581 symbol
= func
.symbol
;
1584 Method m
= create_method (node
.name
, symbol
, v
.result
, func
!= null ? func
.parameters
: v
.parameters
, false, is_interface
);
1586 m
.binding
= MemberBinding
.INSTANCE
;
1587 m
.is_virtual
= !(m
.is_abstract
|| is_interface
);
1588 m
.is_abstract
= m
.is_abstract
|| is_interface
;
1591 m
.attributes
.append (new
Attribute ("NoWrapper", null));
1598 private string fix_prop_name (string name
) {
1599 var str
= new
StringBuilder ();
1603 while (i
.len () > 0) {
1604 unichar c
= i
.get_char ();
1608 str
.append_unichar (c
);
1617 private Property?
parse_property (IdlNodeProperty prop_node
) {
1618 weak IdlNode node
= (IdlNode
) prop_node
;
1620 if (prop_node
.deprecated
) {
1624 if (!prop_node
.readable
&& !prop_node
.writable
) {
1625 // buggy GIDL definition
1626 prop_node
.readable
= true;
1627 prop_node
.writable
= true;
1630 PropertyAccessor get_acc
= null;
1631 PropertyAccessor set_acc
= null;
1632 if (prop_node
.readable
) {
1633 get_acc
= new
PropertyAccessor (true, false, false, null, null);
1635 if (prop_node
.writable
) {
1636 set_acc
= new
PropertyAccessor (false, false, false, null, null);
1637 if (prop_node
.construct_only
) {
1638 set_acc
.construction
= true;
1640 set_acc
.writable
= true;
1641 set_acc
.construction
= prop_node
.@
construct;
1645 var prop
= new
Property (fix_prop_name (node
.name
), parse_type (prop_node
.type
), get_acc
, set_acc
, current_source_reference
);
1646 prop
.access
= SymbolAccessibility
.PUBLIC
;
1647 prop
.interface_only
= true;
1649 var attributes
= get_attributes ("%s:%s".printf (current_data_type
.get_cname (), node
.name
));
1650 if (attributes
!= null) {
1651 foreach (string attr
in attributes
) {
1652 var nv
= attr
.split ("=", 2);
1653 if (nv
[0] == "hidden") {
1654 if (eval (nv
[1]) == "1") {
1657 } else if (nv
[0] == "type_arguments") {
1658 var type_args
= eval (nv
[1]).split (",");
1659 foreach (string type_arg
in type_args
) {
1660 var arg_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, type_arg
));
1661 arg_type
.value_owned
= true;
1662 prop
.property_type
.add_type_argument (arg_type
);
1668 if (current_type_symbol_set
!= null) {
1669 current_type_symbol_set
.add (prop
.name
);
1675 private Constant?
parse_constant (IdlNodeConstant const_node
) {
1676 weak IdlNode node
= (IdlNode
) const_node
;
1678 var type
= parse_type (const_node
.type
);
1683 var c
= new
Constant (node
.name
, type
, null, current_source_reference
);
1685 string[] attributes
= get_attributes (node
.name
);
1686 if (attributes
!= null) {
1687 foreach (string attr
in attributes
) {
1688 var nv
= attr
.split ("=", 2);
1689 if (nv
[0] == "cheader_filename") {
1690 c
.add_cheader_filename (eval (nv
[1]));
1691 } else if (nv
[0] == "hidden") {
1692 if (eval (nv
[1]) == "1") {
1699 c
.access
= SymbolAccessibility
.PUBLIC
;
1704 private Field?
parse_field (IdlNodeField field_node
) {
1705 weak IdlNode node
= (IdlNode
) field_node
;
1706 bool unhidden
= false;
1708 var type
= parse_type (field_node
.type
);
1713 string cheader_filename
= null;
1714 string ctype
= null;
1716 var attributes
= get_attributes ("%s.%s".printf (current_data_type
.get_cname (), node
.name
));
1717 if (attributes
!= null) {
1718 foreach (string attr
in attributes
) {
1719 var nv
= attr
.split ("=", 2);
1720 if (nv
[0] == "hidden") {
1721 if (eval (nv
[1]) == "1") {
1726 } else if (nv
[0] == "is_array") {
1727 if (eval (nv
[1]) == "1") {
1728 type
= new
ArrayType (type
, 1, type
.source_reference
);
1730 } else if (nv
[0] == "weak") {
1731 if (eval (nv
[1]) == "0") {
1732 type
.value_owned
= true;
1734 } else if (nv
[0] == "type_name") {
1735 ((UnresolvedType
) type
).unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1736 } else if (nv
[0] == "type_arguments") {
1737 var type_args
= eval (nv
[1]).split (",");
1738 foreach (string type_arg
in type_args
) {
1739 var arg_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, type_arg
));
1740 arg_type
.value_owned
= true;
1741 type
.add_type_argument (arg_type
);
1743 } else if (nv
[0] == "cheader_filename") {
1744 cheader_filename
= eval (nv
[1]);
1745 } else if (nv
[0] == "ctype") {
1746 ctype
= eval (nv
[1]);
1751 if (node
.name
.has_prefix("_") && !unhidden
) {
1755 if (current_type_symbol_set
!= null) {
1756 current_type_symbol_set
.add (node
.name
);
1759 string field_name
= node
.name
;
1760 if (field_name
== "string") {
1761 // avoid conflict with string type
1765 var field
= new
Field (field_name
, type
, null, current_source_reference
);
1766 field
.access
= SymbolAccessibility
.PUBLIC
;
1768 if (field_name
!= node
.name
) {
1769 field
.set_cname (node
.name
);
1772 if (ctype
!= null) {
1773 field
.set_ctype (ctype
);
1776 if (cheader_filename
!= null) {
1777 field
.add_cheader_filename (cheader_filename
);
1780 field
.no_array_length
= true;
1786 private string[]?
get_attributes (string codenode
) {
1787 var attributes
= codenode_attributes_map
.get (codenode
);
1789 if (attributes
== null) {
1790 var dot_required
= (null != codenode
.chr (-1, '.'));
1791 var colon_required
= (null != codenode
.chr (-1, ':'));
1793 var pattern_specs
= codenode_attributes_patterns
.get_keys ();
1794 foreach (PatternSpec
* pattern
in pattern_specs
) {
1795 var pspec
= codenode_attributes_patterns
[pattern
];
1797 if ((dot_required
&& null == pspec
.chr (-1, '.')) ||
1798 (colon_required
&& null == pspec
.chr (-1, ':'))) {
1802 if (pattern
->match_string (codenode
)) {
1803 return get_attributes (pspec
);
1808 if (attributes
== null) {
1812 return attributes
.split (" ");
1815 private string eval (string s
) {
1816 return s
.offset (1).ndup (s
.size () - 2);
1819 private Signal?
parse_signal (IdlNodeSignal sig_node
) {
1820 weak IdlNode node
= (IdlNode
) sig_node
;
1822 if (sig_node
.deprecated
|| sig_node
.result
== null) {
1826 var sig
= new
Signal (fix_prop_name (node
.name
), parse_param (sig_node
.result
), current_source_reference
);
1827 sig
.access
= SymbolAccessibility
.PUBLIC
;
1829 var attributes
= get_attributes ("%s::%s".printf (current_data_type
.get_cname (), sig
.name
));
1830 if (attributes
!= null) {
1831 foreach (string attr
in attributes
) {
1832 var nv
= attr
.split ("=", 2);
1833 if (nv
[0] == "name") {
1834 sig
.set_cname (sig
.name
);
1835 sig
.name
= eval (nv
[1]);
1836 } else if (nv
[0] == "has_emitter" && eval (nv
[1]) == "1") {
1837 sig
.has_emitter
= true;
1838 } else if (nv
[0] == "hidden") {
1839 if (eval (nv
[1]) == "1") {
1846 sig
.is_virtual
= true;
1850 foreach (weak IdlNodeParam param
in sig_node
.parameters
) {
1852 // ignore implicit first signal parameter (sender)
1857 weak IdlNode param_node
= (IdlNode
) param
;
1859 ParameterDirection direction
;
1860 var param_type
= parse_param (param
, out direction
);
1861 var p
= new
FormalParameter (param_node
.name
, param_type
);
1862 p
.direction
= direction
;
1863 sig
.add_parameter (p
);
1865 var attributes
= get_attributes ("%s::%s.%s".printf (current_data_type
.get_cname (), sig
.name
, param_node
.name
));
1866 if (attributes
!= null) {
1867 string ns_name
= null;
1868 foreach (string attr
in attributes
) {
1869 var nv
= attr
.split ("=", 2);
1870 if (nv
[0] == "is_array") {
1871 if (eval (nv
[1]) == "1") {
1872 param_type
= new
ArrayType (param_type
, 1, param_type
.source_reference
);
1873 p
.parameter_type
= param_type
;
1874 p
.direction
= ParameterDirection
.IN
;
1876 } else if (nv
[0] == "is_out") {
1877 if (eval (nv
[1]) == "1") {
1878 p
.direction
= ParameterDirection
.OUT
;
1880 } else if (nv
[0] == "is_ref") {
1881 if (eval (nv
[1]) == "1") {
1882 p
.direction
= ParameterDirection
.REF
;
1884 } else if (nv
[0] == "nullable") {
1885 if (eval (nv
[1]) == "1") {
1886 param_type
.nullable
= true;
1888 } else if (nv
[0] == "type_name") {
1889 ((UnresolvedType
) param_type
).unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
1890 } else if (nv
[0] == "namespace_name") {
1891 ns_name
= eval (nv
[1]);
1894 if (ns_name
!= null) {
1895 ((UnresolvedType
) param_type
).unresolved_symbol
.inner
= new
UnresolvedSymbol (null, ns_name
);