3 * Copyright (C) 2006-2010 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
28 * Code visitor parsing all GIDL files.
30 public class Vala
.GIdlParser
: CodeVisitor
{
31 private CodeContext context
;
33 private SourceFile current_source_file
;
35 private SourceReference current_source_reference
;
37 private Namespace current_namespace
;
38 private TypeSymbol current_data_type
;
39 private Map
<string,string> codenode_attributes_map
;
40 private Map
<PatternSpec
*,string> codenode_attributes_patterns
;
41 private Set
<string> current_type_symbol_set
;
43 private Map
<string,TypeSymbol
> cname_type_map
;
45 static GLib
.Regex type_from_string_regex
;
48 * Parse all source files in the specified code context and build a
51 * @param context a code context
53 public void parse (CodeContext context
) {
54 cname_type_map
= new HashMap
<string,TypeSymbol
> (str_hash
, str_equal
);
56 this
.context
= context
;
57 context
.accept (this
);
59 cname_type_map
= null;
62 public override void visit_namespace (Namespace ns
) {
63 ns
.accept_children (this
);
66 public override void visit_class (Class cl
) {
70 public override void visit_struct (Struct st
) {
74 public override void visit_interface (Interface iface
) {
78 public override void visit_enum (Enum en
) {
82 public override void visit_error_domain (ErrorDomain ed
) {
86 public override void visit_delegate (Delegate d
) {
90 private void visit_type (TypeSymbol t
) {
91 if (!cname_type_map
.contains (get_cname (t
))) {
92 cname_type_map
[get_cname (t
)] = t
;
96 public override void visit_source_file (SourceFile source_file
) {
97 if (source_file
.filename
.has_suffix (".gi")) {
98 parse_file (source_file
);
102 private void parse_file (SourceFile source_file
) {
103 string metadata_filename
= "%s.metadata".printf (source_file
.filename
.substring (0, source_file
.filename
.length
- ".gi".length
));
105 current_source_file
= source_file
;
107 codenode_attributes_map
= new HashMap
<string,string> (str_hash
, str_equal
);
108 codenode_attributes_patterns
= new HashMap
<PatternSpec
*,string> (direct_hash
, (EqualFunc
<PatternSpec
>) PatternSpec
.equal
);
110 if (FileUtils
.test (metadata_filename
, FileTest
.EXISTS
)) {
113 FileUtils
.get_contents (metadata_filename
, out metadata
, null);
115 foreach (unowned
string line
in metadata
.split ("\n")) {
116 if (line
.has_prefix ("#")) {
117 // ignore comment lines
121 var tokens
= line
.split (" ", 2);
123 if (null == tokens
[0]) {
127 if (-1 != tokens
[0].index_of_char ('*')) {
128 PatternSpec
* pattern
= new
PatternSpec (tokens
[0]);
129 codenode_attributes_patterns
[pattern
] = tokens
[0];
132 codenode_attributes_map
[tokens
[0]] = tokens
[1];
134 } catch (FileError e
) {
135 Report
.error (null, "Unable to read metadata file: %s".printf (e
.message
));
140 var modules
= Idl
.parse_file (source_file
.filename
);
142 current_source_reference
= new
SourceReference (source_file
, SourceLocation (null, 0, 0), SourceLocation (null, 0, 0));
144 foreach (weak IdlModule module
in modules
) {
145 var ns
= parse_module (module
);
147 context
.root
.add_namespace (ns
);
150 } catch (MarkupError e
) {
151 Report
.error (null, "Unable to parse GIDL file: %s".printf (e
.message
));
155 private string fix_type_name (string type_name
, Symbol container
) {
156 var attributes
= get_attributes (type_name
);
157 if (attributes
!= null) {
158 foreach (string attr
in attributes
) {
159 var nv
= attr
.split ("=", 2);
160 if (nv
[0] == "name") {
166 if (type_name
.has_prefix (container
.name
)) {
167 return type_name
.substring (container
.name
.length
);
169 var cprefix
= get_cprefix (container
);
170 if (type_name
.has_prefix (cprefix
)) {
171 return type_name
.substring (cprefix
.length
);;
178 private string fix_const_name (string const_name
, Symbol container
) {
179 var pref
= get_lower_case_cprefix (container
).ascii_up ();
180 if (const_name
.has_prefix (pref
)) {
181 return const_name
.substring (pref
.length
);
186 private string get_cheader_filename (Symbol sym
) {
187 var cheader_filename
= sym
.get_attribute_string ("CCode", "cheader_filename");
188 if (cheader_filename
!= null) {
189 return cheader_filename
;
191 if (sym
.parent_symbol
!= null) {
192 return get_cheader_filename (sym
.parent_symbol
);
193 } else if (sym
.source_reference
!= null) {
194 return sym
.source_reference
.file
.get_cinclude_filename ();
199 private string get_cname (Symbol sym
, Symbol? container
= null) {
200 if (container
== null) {
201 container
= sym
.parent_symbol
;
203 var cname
= sym
.get_attribute_string ("CCode", "cname");
209 if (sym is CreationMethod
) {
210 if (name
== null || name
== ".new") {
213 name
= "new_%s".printf (name
);
216 if (container
!= null) {
217 return "%s%s".printf (get_lower_case_cprefix (container
), name
);
222 if (container
!= null) {
223 return "%s%s".printf (get_cprefix (container
), sym
.name
);
230 private string get_finish_cname (Method m
) {
231 var finish_cname
= m
.get_attribute_string ("CCode", "finish_name");
232 if (finish_cname
!= null) {
235 var result
= get_cname (m
);
236 if (result
.has_suffix ("_async")) {
237 result
= result
.substring (0, result
.length
- "_async".length
);
239 return result
+ "_finish";
242 private string get_lower_case_cname (Symbol sym
) {
243 var lower_case_csuffix
= Symbol
.camel_case_to_lower_case (sym
.name
);
244 if (sym is ObjectTypeSymbol
) {
245 // remove underscores in some cases to avoid conflicts of type macros
246 if (lower_case_csuffix
.has_prefix ("type_")) {
247 lower_case_csuffix
= "type" + lower_case_csuffix
.substring ("type_".length
);
248 } else if (lower_case_csuffix
.has_prefix ("is_")) {
249 lower_case_csuffix
= "is" + lower_case_csuffix
.substring ("is_".length
);
251 if (lower_case_csuffix
.has_suffix ("_class")) {
252 lower_case_csuffix
= lower_case_csuffix
.substring (0, lower_case_csuffix
.length
- "_class".length
) + "class";
255 if (sym
.parent_symbol
!= null) {
256 return "%s%s".printf (get_lower_case_cprefix (sym
.parent_symbol
), lower_case_csuffix
);
258 return lower_case_csuffix
;
262 private string get_lower_case_cprefix (Symbol sym
) {
263 if (sym
.name
== null) {
267 cprefix
= sym
.get_attribute_string ("CCode", "lower_case_cprefix");
268 if (cprefix
== null && (sym is ObjectTypeSymbol
|| sym is Struct
)) {
269 cprefix
= sym
.get_attribute_string ("CCode", "cprefix");
271 if (cprefix
!= null) {
274 return get_lower_case_cname (sym
) + "_";
277 public string get_cprefix (Symbol sym
) {
278 if (sym is ObjectTypeSymbol
) {
279 return get_cname (sym
);
280 } else if (sym is Enum
|| sym is ErrorDomain
) {
281 return "%s_".printf (get_lower_case_cname (sym
).ascii_up ());
282 } else if (sym is Namespace
) {
283 if (sym
.name
!= null) {
284 var cprefix
= sym
.get_attribute_string ("CCode", "cprefix");
285 if (cprefix
!= null) {
288 if (sym
.parent_symbol
!= null) {
289 return "%s%s".printf (get_cprefix (sym
.parent_symbol
), sym
.name
);
296 } else if (sym
.name
!= null) {
302 private string[] get_attributes_for_node (IdlNode node
) {
305 if (node
.type
== IdlNodeTypeId
.FUNCTION
) {
306 name
= ((IdlNodeFunction
) node
).symbol
;
307 } else if (node
.type
== IdlNodeTypeId
.SIGNAL
) {
308 name
= "%s::%s".printf (get_cname (current_data_type
), node
.name
);
309 } else if (node
.type
== IdlNodeTypeId
.PROPERTY
) {
310 name
= "%s:%s".printf (get_cname (current_data_type
), node
.name
);
311 } else if (node
.type
== IdlNodeTypeId
.FIELD
) {
312 name
= "%s.%s".printf (get_cname (current_data_type
), node
.name
);
317 return get_attributes (name
);
320 private void add_symbol_to_container (Symbol container
, Symbol sym
) {
321 if (container is Class
) {
322 unowned Class cl
= (Class
) container
;
325 cl
.add_class ((Class
) sym
);
326 } else if (sym is Constant
) {
327 cl
.add_constant ((Constant
) sym
);
328 } else if (sym is Enum
) {
329 cl
.add_enum ((Enum
) sym
);
330 } else if (sym is Field
) {
331 cl
.add_field ((Field
) sym
);
332 } else if (sym is Method
) {
333 cl
.add_method ((Method
) sym
);
334 } else if (sym is Property
) {
335 cl
.add_property ((Property
) sym
);
336 } else if (sym is Signal
) {
337 cl
.add_signal ((Signal
) sym
);
338 } else if (sym is Struct
) {
339 cl
.add_struct ((Struct
) sym
);
341 } else if (container is Enum
) {
342 unowned Enum en
= (Enum
) container
;
344 if (sym is EnumValue
) {
345 en
.add_value ((EnumValue
) sym
);
346 } else if (sym is Constant
) {
347 en
.add_constant ((Constant
) sym
);
348 } else if (sym is Method
) {
349 en
.add_method ((Method
) sym
);
351 } else if (container is Interface
) {
352 unowned Interface iface
= (Interface
) container
;
355 iface
.add_class ((Class
) sym
);
356 } else if (sym is Constant
) {
357 iface
.add_constant ((Constant
) sym
);
358 } else if (sym is Enum
) {
359 iface
.add_enum ((Enum
) sym
);
360 } else if (sym is Field
) {
361 iface
.add_field ((Field
) sym
);
362 } else if (sym is Method
) {
363 iface
.add_method ((Method
) sym
);
364 } else if (sym is Property
) {
365 iface
.add_property ((Property
) sym
);
366 } else if (sym is Signal
) {
367 iface
.add_signal ((Signal
) sym
);
368 } else if (sym is Struct
) {
369 iface
.add_struct ((Struct
) sym
);
371 } else if (container is Namespace
) {
372 unowned Namespace ns
= (Namespace
) container
;
374 if (sym is Namespace
) {
375 ns
.add_namespace ((Namespace
) sym
);
376 } else if (sym is Class
) {
377 ns
.add_class ((Class
) sym
);
378 } else if (sym is Constant
) {
379 ns
.add_constant ((Constant
) sym
);
380 } else if (sym is Delegate
) {
381 ns
.add_delegate ((Delegate
) sym
);
382 } else if (sym is Enum
) {
383 ns
.add_enum ((Enum
) sym
);
384 } else if (sym is ErrorDomain
) {
385 ns
.add_error_domain ((ErrorDomain
) sym
);
386 } else if (sym is Field
) {
387 ns
.add_field ((Field
) sym
);
388 } else if (sym is Interface
) {
389 ns
.add_interface ((Interface
) sym
);
390 } else if (sym is Method
) {
391 ns
.add_method ((Method
) sym
);
392 } else if (sym is Namespace
) {
393 ns
.add_namespace ((Namespace
) sym
);
394 } else if (sym is Struct
) {
395 ns
.add_struct ((Struct
) sym
);
397 } else if (container is Struct
) {
398 unowned Struct st
= (Struct
) container
;
400 if (sym is Constant
) {
401 st
.add_constant ((Constant
) sym
);
402 } else if (sym is Field
) {
403 st
.add_field ((Field
) sym
);
404 } else if (sym is Method
) {
405 st
.add_method ((Method
) sym
);
406 } else if (sym is Property
) {
407 st
.add_property ((Property
) sym
);
411 if (!(sym is Namespace
) && container is Namespace
) {
413 sym
.set_attribute_string ("CCode", "cheader_filename", get_cheader_filename (sym
));
417 private void parse_node (IdlNode node
, IdlModule module
, Symbol container
) {
418 if (node
.type
== IdlNodeTypeId
.CALLBACK
) {
419 var cb
= parse_delegate ((IdlNodeFunction
) node
);
423 cb
.name
= fix_type_name (cb
.name
, container
);
424 add_symbol_to_container (container
, cb
);
425 current_source_file
.add_node (cb
);
426 } else if (node
.type
== IdlNodeTypeId
.STRUCT
) {
427 parse_struct ((IdlNodeStruct
) node
, container
, module
);
428 } else if (node
.type
== IdlNodeTypeId
.UNION
) {
429 parse_union ((IdlNodeUnion
) node
, container
, module
);
430 } else if (node
.type
== IdlNodeTypeId
.BOXED
) {
431 parse_boxed ((IdlNodeBoxed
) node
, container
, module
);
432 } else if (node
.type
== IdlNodeTypeId
.ENUM
) {
433 parse_enum ((IdlNodeEnum
) node
, container
, module
, false);
434 } else if (node
.type
== IdlNodeTypeId
.FLAGS
) {
435 parse_enum ((IdlNodeEnum
) node
, container
, module
, true);
436 } else if (node
.type
== IdlNodeTypeId
.OBJECT
) {
437 parse_object ((IdlNodeInterface
) node
, container
, module
);
438 } else if (node
.type
== IdlNodeTypeId
.INTERFACE
) {
439 parse_interface ((IdlNodeInterface
) node
, container
, module
);
440 } else if (node
.type
== IdlNodeTypeId
.CONSTANT
) {
441 var c
= parse_constant ((IdlNodeConstant
) node
);
443 c
.name
= fix_const_name (c
.name
, container
);
444 add_symbol_to_container (container
, c
);
445 current_source_file
.add_node (c
);
447 } else if (node
.type
== IdlNodeTypeId
.FUNCTION
) {
448 var m
= parse_function ((IdlNodeFunction
) node
);
450 m
.binding
= MemberBinding
.STATIC
;
451 add_symbol_to_container (container
, m
);
452 current_source_file
.add_node (m
);
457 private Symbol?
get_container_from_name (string name
) {
458 var path
= name
.split (".");
459 Symbol? cp
= current_namespace
;
460 if (cp
.parent_symbol
!= context
.root
) {
461 cp
= cp
.parent_symbol
;
465 foreach ( unowned
string tok
in path
) {
466 cc
= cp
.scope
.lookup (tok
) as Symbol
;
468 cc
= new
Namespace (tok
, current_source_reference
);
469 add_symbol_to_container (cp
, cc
);
477 private Namespace?
parse_module (IdlModule module
) {
478 Symbol sym
= context
.root
.scope
.lookup (module
.name
);
480 if (sym is Namespace
) {
481 ns
= (Namespace
) sym
;
482 if (ns
.external_package
) {
483 ns
.attributes
= null;
484 ns
.source_reference
= current_source_reference
;
487 ns
= new
Namespace (module
.name
, current_source_reference
);
490 current_namespace
= ns
;
492 var attributes
= get_attributes (ns
.name
);
493 if (attributes
!= null) {
494 foreach (string attr
in attributes
) {
495 var nv
= attr
.split ("=", 2);
496 if (nv
[0] == "cheader_filename") {
497 ns
.set_attribute_string ("CCode", "cheader_filename", eval (nv
[1]));
498 } else if (nv
[0] == "cprefix") {
499 ns
.set_attribute_string ("CCode", "cprefix", eval (nv
[1]));
500 } else if (nv
[0] == "lower_case_cprefix") {
501 ns
.set_attribute_string ("CCode", "lower_case_cprefix", eval (nv
[1]));
502 } else if (nv
[0] == "gir_namespace") {
503 ns
.source_reference
.file
.gir_namespace
= eval (nv
[1]);
504 ns
.set_attribute_string ("CCode", "gir_namespace", eval (nv
[1]));
505 } else if (nv
[0] == "gir_version") {
506 ns
.source_reference
.file
.gir_version
= eval (nv
[1]);
507 ns
.set_attribute_string ("CCode", "gir_version", eval (nv
[1]));
508 } else if (nv
[0] == "deprecated") {
509 if (eval (nv
[1]) == "1") {
510 ns
.set_attribute_bool ("Version", "deprecated", true);
512 } else if (nv
[0] == "replacement") {
513 ns
.set_attribute_string ("Version", "replacement", eval (nv
[1]));
514 } else if (nv
[0] == "deprecated_since") {
515 ns
.set_attribute_string ("Version", "deprecated_since", eval (nv
[1]));
520 var deferred
= new ArrayList
<unowned IdlNode
> ();
522 foreach (weak IdlNode node
in module
.entries
) {
523 bool is_deferred
= false;
524 var child_attributes
= get_attributes_for_node (node
);
525 if (child_attributes
!= null) {
526 foreach (unowned
string attr
in child_attributes
) {
527 var nv
= attr
.split ("=", 2);
528 if (nv
[0] == "parent") {
536 parse_node (node
, module
, ns
);
540 foreach (unowned IdlNode node
in deferred
) {
541 Symbol container
= ns
;
542 var child_attributes
= get_attributes_for_node (node
);
543 if (child_attributes
!= null) {
544 foreach (unowned
string attr
in child_attributes
) {
545 var nv
= attr
.split ("=", 2);
546 if (nv
[0] == "parent") {
547 container
= get_container_from_name (eval (nv
[1]));
552 if (container is Namespace
) {
553 current_namespace
= (Namespace
) container
;
555 current_data_type
= (TypeSymbol
) container
;
557 parse_node (node
, module
, container
);
558 current_namespace
= ns
;
559 current_data_type
= null;
562 current_namespace
= null;
564 if (sym is Namespace
) {
570 private Delegate?
parse_delegate (IdlNodeFunction f_node
) {
571 weak IdlNode node
= (IdlNode
) f_node
;
573 var return_type
= parse_param (f_node
.result
);
575 var cb
= new
Delegate (node
.name
, return_type
, current_source_reference
);
576 cb
.access
= SymbolAccessibility
.PUBLIC
;
577 cb
.has_target
= false;
579 bool check_has_target
= true;
580 bool suppress_throws
= false;
581 string? error_types
= null;
583 var attributes
= get_attributes (node
.name
);
584 if (attributes
!= null) {
585 foreach (string attr
in attributes
) {
586 var nv
= attr
.split ("=", 2);
587 if (nv
[0] == "hidden") {
588 if (eval (nv
[1]) == "1") {
591 } else if (nv
[0] == "cheader_filename") {
592 cb
.set_attribute_string ("CCode", "cheader_filename", eval (nv
[1]));
593 } else if (nv
[0] == "has_target") {
594 if (eval (nv
[1]) == "0") {
595 check_has_target
= false;
596 } else if (eval (nv
[1]) == "1") {
597 cb
.has_target
= true;
599 } else if (nv
[0] == "transfer_ownership") {
600 if (eval (nv
[1]) == "1") {
601 return_type
.value_owned
= true;
603 } else if (nv
[0] == "is_array") {
604 if (eval (nv
[1]) == "1") {
605 return_type
.value_owned
= true;
606 return_type
= new
ArrayType (return_type
, 1, return_type
.source_reference
);
607 cb
.return_type
= return_type
;
609 } else if (nv
[0] == "throws") {
610 if (eval (nv
[1]) == "0") {
611 suppress_throws
= true;
613 } else if (nv
[0] == "error_types") {
614 error_types
= eval (nv
[1]);
615 } else if (nv
[0] == "array_length_type") {
616 cb
.set_attribute_string ("CCode", "array_length_type", eval (nv
[1]));
617 } else if (nv
[0] == "type_name") {
618 cb
.return_type
= return_type
= parse_type_from_string (eval (nv
[1]), return_type
.value_owned
);
619 } else if (nv
[0] == "deprecated") {
620 if (eval (nv
[1]) == "1") {
621 cb
.set_attribute_bool ("Version", "deprecated", true);
623 } else if (nv
[0] == "replacement") {
624 cb
.set_attribute_string ("Version", "replacement", eval (nv
[1]));
625 } else if (nv
[0] == "deprecated_since") {
626 cb
.set_attribute_string ("Version", "deprecated_since", eval (nv
[1]));
627 } else if (nv
[0] == "type_arguments") {
628 parse_type_arguments_from_string (return_type
, eval (nv
[1]));
629 } else if (nv
[0] == "instance_pos") {
630 cb
.set_attribute_double ("CCode", "instance_pos", double.parse (eval (nv
[1])));
631 } else if (nv
[0] == "type_parameters") {
632 foreach (string type_param_name
in eval (nv
[1]).split (",")) {
633 cb
.add_type_parameter (new
TypeParameter (type_param_name
, current_source_reference
));
635 } else if (nv
[0] == "experimental") {
636 if (eval (nv
[1]) == "1") {
637 cb
.set_attribute_bool ("Version", "experimental", true);
643 uint remaining_params
= f_node
.parameters
.length ();
644 foreach (weak IdlNodeParam param
in f_node
.parameters
) {
645 weak IdlNode param_node
= (IdlNode
) param
;
647 if (check_has_target
&& remaining_params
== 1 && (param_node
.name
== "user_data" || param_node
.name
== "data")) {
648 // hide user_data parameter for instance delegates
649 cb
.has_target
= true;
651 // check for GError parameter
652 if (suppress_throws
== false && param_is_exception (param
)) {
653 if (error_types
== null)
654 cb
.add_error_type (parse_type (param
.type
));
659 string param_name
= param_node
.name
;
660 if (param_name
== "string") {
661 // avoid conflict with string type
663 } else if (param_name
== "self") {
664 // avoid conflict with delegate target
665 param_name
= "_self";
668 ParameterDirection direction
;
669 var param_type
= parse_param (param
, out direction
);
670 var p
= new
Parameter (param_name
, param_type
);
671 p
.direction
= direction
;
673 bool hide_param
= false;
674 bool show_param
= false;
675 bool array_requested
= false;
676 bool out_requested
= false;
677 attributes
= get_attributes ("%s.%s".printf (node
.name
, param_node
.name
));
678 if (attributes
!= null) {
679 foreach (string attr
in attributes
) {
680 var nv
= attr
.split ("=", 2);
681 if (nv
[0] == "hidden") {
682 if (eval (nv
[1]) == "1") {
684 } else if (eval (nv
[1]) == "0") {
687 } else if (nv
[0] == "is_array") {
688 if (eval (nv
[1]) == "1") {
689 param_type
.value_owned
= true;
690 param_type
= new
ArrayType (param_type
, 1, param_type
.source_reference
);
691 p
.variable_type
= param_type
;
692 if (!out_requested
) {
693 p
.direction
= ParameterDirection
.IN
;
695 array_requested
= true;
697 } else if (nv
[0] == "is_out") {
698 if (eval (nv
[1]) == "1") {
699 p
.direction
= ParameterDirection
.OUT
;
700 out_requested
= true;
701 if (!array_requested
&& param_type is ArrayType
) {
702 var array_type
= (ArrayType
) param_type
;
703 param_type
= array_type
.element_type
;
704 p
.variable_type
= param_type
;
707 } else if (nv
[0] == "is_ref") {
708 if (eval (nv
[1]) == "1") {
709 p
.direction
= ParameterDirection
.REF
;
710 if (!array_requested
&& param_type is ArrayType
) {
711 var array_type
= (ArrayType
) param_type
;
712 param_type
= array_type
.element_type
;
713 p
.variable_type
= param_type
;
716 } else if (nv
[0] == "takes_ownership") {
717 if (eval (nv
[1]) == "1") {
718 param_type
.value_owned
= true;
720 } else if (nv
[0] == "nullable") {
721 if (eval (nv
[1]) == "1") {
722 param_type
.nullable
= true;
724 } else if (nv
[0] == "type_arguments") {
725 parse_type_arguments_from_string (param_type
, eval (nv
[1]));
726 } else if (nv
[0] == "no_array_length") {
727 if (eval (nv
[1]) == "1") {
728 p
.set_attribute_bool ("CCode", "array_length", false);
730 } else if (nv
[0] == "array_length_type") {
731 p
.set_attribute_string ("CCode", "array_length_type", eval (nv
[1]));
732 } else if (nv
[0] == "array_null_terminated") {
733 if (eval (nv
[1]) == "1") {
734 p
.set_attribute_bool ("CCode", "array_length", false);
735 p
.set_attribute_bool ("CCode", "array_null_terminated", true);
737 } else if (nv
[0] == "type_name") {
738 p
.variable_type
= param_type
= parse_type_from_string (eval (nv
[1]), false);
743 if (show_param
|| !hide_param
) {
744 cb
.add_parameter (p
);
751 if (suppress_throws
== false && error_types
!= null) {
752 var type_args
= eval (error_types
).split (",");
753 foreach (unowned
string type_arg
in type_args
) {
754 cb
.add_error_type (parse_type_from_string (type_arg
, true));
761 private bool is_reference_type (string cname
) {
762 var st_attributes
= get_attributes (cname
);
763 if (st_attributes
!= null) {
764 foreach (string attr
in st_attributes
) {
765 var nv
= attr
.split ("=", 2);
766 if (nv
[0] == "is_value_type" && eval (nv
[1]) == "1") {
774 private void parse_struct (IdlNodeStruct st_node
, Symbol container
, IdlModule module
) {
775 weak IdlNode node
= (IdlNode
) st_node
;
777 if (st_node
.deprecated
) {
781 string name
= fix_type_name (node
.name
, container
);
783 if (!is_reference_type (node
.name
)) {
784 var st
= container
.scope
.lookup (name
) as Struct
;
786 st
= new
Struct (name
, current_source_reference
);
787 st
.access
= SymbolAccessibility
.PUBLIC
;
789 var st_attributes
= get_attributes (node
.name
);
790 if (st_attributes
!= null) {
791 foreach (string attr
in st_attributes
) {
792 var nv
= attr
.split ("=", 2);
793 if (nv
[0] == "cheader_filename") {
794 st
.set_attribute_string ("CCode", "cheader_filename", eval (nv
[1]));
795 } else if (nv
[0] == "hidden") {
796 if (eval (nv
[1]) == "1") {
799 } else if (nv
[0] == "base_type") {
800 st
.base_type
= parse_type_string (eval (nv
[1]));
801 } else if (nv
[0] == "rank") {
802 st
.set_rank (int.parse (eval (nv
[1])));
803 } else if (nv
[0] == "simple_type") {
804 if (eval (nv
[1]) == "1") {
805 st
.set_simple_type (true);
807 } else if (nv
[0] == "immutable") {
808 if (eval (nv
[1]) == "1") {
809 st
.set_attribute ("Immutable", true);
811 } else if (nv
[0] == "has_type_id") {
812 if (eval (nv
[1]) == "0") {
813 st
.set_attribute_bool ("CCode", "has_type_id", false);
815 } else if (nv
[0] == "type_id") {
816 st
.set_attribute_string ("CCode", "type_id", eval (nv
[1]));
817 } else if (nv
[0] == "has_copy_function") {
818 if (eval (nv
[1]) == "0") {
819 st
.set_attribute_bool ("CCode", "has_copy_function", false);
821 } else if (nv
[0] == "deprecated") {
822 if (eval (nv
[1]) == "1") {
823 st
.set_attribute_bool ("Version", "deprecated", true);
825 } else if (nv
[0] == "replacement") {
826 st
.set_attribute_string ("Version", "replacement", eval (nv
[1]));
827 } else if (nv
[0] == "deprecated_since") {
828 st
.set_attribute_string ("Version", "deprecated_since", eval (nv
[1]));
829 } else if (nv
[0] == "has_destroy_function") {
830 if (eval (nv
[1]) == "0") {
831 st
.set_attribute_bool ("CCode", "has_destroy_function", false);
833 } else if (nv
[0] == "experimental") {
834 if (eval (nv
[1]) == "1") {
835 st
.set_attribute_bool ("Version", "experimental", true);
841 add_symbol_to_container (container
, st
);
842 current_source_file
.add_node (st
);
845 current_data_type
= st
;
847 foreach (weak IdlNode member
in st_node
.members
) {
848 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
849 var m
= parse_function ((IdlNodeFunction
) member
);
853 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
854 var f
= parse_field ((IdlNodeField
) member
);
861 current_data_type
= null;
863 bool ref_function_void
= false;
864 string ref_function
= null;
865 string unref_function
= null;
866 string copy_function
= null;
867 string free_function
= null;
869 var cl
= container
.scope
.lookup (name
) as Class
;
871 string base_class
= null;
872 bool is_fundamental
= false;
874 cl
= new
Class (name
, current_source_reference
);
875 cl
.access
= SymbolAccessibility
.PUBLIC
;
877 var cl_attributes
= get_attributes (node
.name
);
878 if (cl_attributes
!= null) {
879 foreach (string attr
in cl_attributes
) {
880 var nv
= attr
.split ("=", 2);
881 if (nv
[0] == "cheader_filename") {
882 cl
.set_attribute_string ("CCode", "cheader_filename", eval (nv
[1]));
883 } else if (nv
[0] == "base_class") {
884 base_class
= eval (nv
[1]);
885 } else if (nv
[0] == "hidden") {
886 if (eval (nv
[1]) == "1") {
889 } else if (nv
[0] == "is_immutable") {
890 if (eval (nv
[1]) == "1") {
891 cl
.is_immutable
= true;
893 } else if (nv
[0] == "const_cname") {
894 cl
.set_attribute_string ("CCode", "const_cname", eval (nv
[1]));
895 } else if (nv
[0] == "is_fundamental") {
896 if (eval (nv
[1]) == "1") {
897 is_fundamental
= true;
899 } else if (nv
[0] == "abstract" && base_class
!= null) {
900 if (eval (nv
[1]) == "1") {
901 cl
.is_abstract
= true;
903 } else if (nv
[0] == "free_function") {
904 free_function
= eval (nv
[1]);
905 } else if (nv
[0] == "ref_function") {
906 ref_function
= eval (nv
[1]);
907 } else if (nv
[0] == "unref_function") {
908 unref_function
= eval (nv
[1]);
909 } else if (nv
[0] == "copy_function") {
910 copy_function
= eval (nv
[1]);
911 } else if (nv
[0] == "ref_function_void") {
912 if (eval (nv
[1]) == "1") {
913 ref_function_void
= true;
915 } else if (nv
[0] == "deprecated") {
916 if (eval (nv
[1]) == "1") {
917 cl
.set_attribute_bool ("Version", "deprecated", true);
919 } else if (nv
[0] == "replacement") {
920 cl
.set_attribute_string ("Version", "replacement", eval (nv
[1]));
921 } else if (nv
[0] == "deprecated_since") {
922 cl
.set_attribute_string ("Version", "deprecated_since", eval (nv
[1]));
923 } else if (nv
[0] == "type_parameters") {
924 foreach (unowned
string type_param_name
in eval (nv
[1]).split (",")) {
925 cl
.add_type_parameter (new
TypeParameter (type_param_name
, current_source_reference
));
927 } else if (nv
[0] == "experimental") {
928 if (eval (nv
[1]) == "1") {
929 cl
.set_attribute_bool ("Version", "experimental", true);
931 } else if (nv
[0] == "delegate_target_cname") {
932 cl
.set_attribute_string ("CCode", "delegate_target_cname", eval (nv
[1]));
937 add_symbol_to_container (container
, cl
);
938 current_source_file
.add_node (cl
);
940 if (base_class
!= null) {
941 var parent
= parse_type_string (base_class
);
942 cl
.add_base_type (parent
);
944 if (base_class
== null && !is_fundamental
) {
945 cl
.is_compact
= true;
949 current_data_type
= cl
;
951 foreach (weak IdlNode member
in st_node
.members
) {
952 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
953 if ((ref_function
== null) && (member
.name
== "ref")) {
954 ref_function
= ((IdlNodeFunction
) member
).symbol
;
955 ref_function_void
= (parse_type (((IdlNodeFunction
) member
).result
.type
) is VoidType
);
956 } else if ((unref_function
== null) && (member
.name
== "unref")) {
957 unref_function
= ((IdlNodeFunction
) member
).symbol
;
958 } else if ((free_function
== null) && (member
.name
== "free" || member
.name
== "destroy")) {
959 free_function
= ((IdlNodeFunction
) member
).symbol
;
961 if ((copy_function
== null) && (member
.name
== "copy")) {
962 copy_function
= ((IdlNodeFunction
) member
).symbol
;
964 var m
= parse_function ((IdlNodeFunction
) member
);
969 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
970 var f
= parse_field ((IdlNodeField
) member
);
977 if (ref_function
!= null) {
978 cl
.set_attribute_string ("CCode", "ref_function", ref_function
);
979 if (ref_function_void
) {
980 cl
.set_attribute_bool ("CCode", "ref_function_void", ref_function_void
);
982 } else if (copy_function
!= null) {
983 cl
.set_attribute_string ("CCode", "copy_function", copy_function
);
985 if (unref_function
!= null) {
986 cl
.set_attribute_string ("CCode", "unref_function", unref_function
);
987 } else if (free_function
!= null && free_function
!= "%sfree".printf (get_lower_case_cprefix (cl
))) {
988 cl
.set_attribute_string ("CCode", "free_function", free_function
);
991 current_data_type
= null;
995 private void parse_union (IdlNodeUnion un_node
, Symbol container
, IdlModule module
) {
996 weak IdlNode node
= (IdlNode
) un_node
;
998 if (un_node
.deprecated
) {
1002 string name
= fix_type_name (node
.name
, container
);
1004 if (!is_reference_type (node
.name
)) {
1005 var st
= container
.scope
.lookup (name
) as Struct
;
1007 st
= new
Struct (name
, current_source_reference
);
1008 st
.access
= SymbolAccessibility
.PUBLIC
;
1010 var st_attributes
= get_attributes (node
.name
);
1011 if (st_attributes
!= null) {
1012 foreach (string attr
in st_attributes
) {
1013 var nv
= attr
.split ("=", 2);
1014 if (nv
[0] == "cheader_filename") {
1015 st
.set_attribute_string ("CCode", "cheader_filename", eval (nv
[1]));
1016 } else if (nv
[0] == "deprecated") {
1017 if (eval (nv
[1]) == "1") {
1018 st
.set_attribute_bool ("Version", "deprecated", true);
1020 } else if (nv
[0] == "replacement") {
1021 st
.set_attribute_string ("Version", "replacement", eval (nv
[1]));
1022 } else if (nv
[0] == "deprecated_since") {
1023 st
.set_attribute_string ("Version", "deprecated_since", eval (nv
[1]));
1024 } else if (nv
[0] == "hidden") {
1025 if (eval (nv
[1]) == "1") {
1028 } else if (nv
[0] == "experimental") {
1029 if (eval (nv
[1]) == "1") {
1030 st
.set_attribute_bool ("Version", "experimental", true);
1036 add_symbol_to_container (container
, st
);
1037 current_source_file
.add_node (st
);
1040 current_data_type
= st
;
1042 foreach (weak IdlNode member
in un_node
.members
) {
1043 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1044 var m
= parse_function ((IdlNodeFunction
) member
);
1048 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
1049 var f
= parse_field ((IdlNodeField
) member
);
1056 current_data_type
= null;
1058 var cl
= container
.scope
.lookup (name
) as Class
;
1060 cl
= new
Class (name
, current_source_reference
);
1061 cl
.access
= SymbolAccessibility
.PUBLIC
;
1062 cl
.is_compact
= true;
1064 var cl_attributes
= get_attributes (node
.name
);
1065 if (cl_attributes
!= null) {
1066 foreach (string attr
in cl_attributes
) {
1067 var nv
= attr
.split ("=", 2);
1068 if (nv
[0] == "cheader_filename") {
1069 cl
.set_attribute_string ("CCode", "cheader_filename", eval (nv
[1]));
1070 } else if (nv
[0] == "hidden") {
1071 if (eval (nv
[1]) == "1") {
1078 add_symbol_to_container (container
, cl
);
1079 current_source_file
.add_node (cl
);
1082 current_data_type
= cl
;
1084 bool ref_function_void
= false;
1085 string ref_function
= null;
1086 string unref_function
= null;
1087 string copy_function
= null;
1088 string free_function
= null;
1090 foreach (weak IdlNode member
in un_node
.members
) {
1091 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1092 if (member
.name
== "ref") {
1093 ref_function
= ((IdlNodeFunction
) member
).symbol
;
1094 ref_function_void
= (parse_type (((IdlNodeFunction
) member
).result
.type
) is VoidType
);
1095 } else if (member
.name
== "unref") {
1096 unref_function
= ((IdlNodeFunction
) member
).symbol
;
1097 } else if (member
.name
== "free" || member
.name
== "destroy") {
1098 free_function
= ((IdlNodeFunction
) member
).symbol
;
1100 if (member
.name
== "copy") {
1101 copy_function
= ((IdlNodeFunction
) member
).symbol
;
1103 var m
= parse_function ((IdlNodeFunction
) member
);
1108 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
1109 var f
= parse_field ((IdlNodeField
) member
);
1116 if (ref_function
!= null) {
1117 cl
.set_attribute_string ("CCode", "ref_function", ref_function
);
1118 if (ref_function_void
) {
1119 cl
.set_attribute_bool ("CCode", "ref_function_void", ref_function_void
);
1121 } else if (copy_function
!= null) {
1122 cl
.set_attribute_string ("CCode", "copy_function", copy_function
);
1124 if (unref_function
!= null) {
1125 cl
.set_attribute_string ("CCode", "unref_function", unref_function
);
1126 } else if (free_function
!= null && free_function
!= "%sfree".printf (get_lower_case_cprefix (cl
))) {
1127 cl
.set_attribute_string ("CCode", "free_function", free_function
);
1130 current_data_type
= null;
1134 private void parse_boxed (IdlNodeBoxed boxed_node
, Symbol container
, IdlModule module
) {
1135 weak IdlNode node
= (IdlNode
) boxed_node
;
1137 string name
= fix_type_name (node
.name
, container
);
1139 var node_attributes
= get_attributes (node
.name
);
1140 if (node_attributes
!= null) {
1141 foreach (string attr
in node_attributes
) {
1142 var nv
= attr
.split ("=", 2);
1143 if (nv
[0] == "hidden") {
1149 if (!is_reference_type (node
.name
)) {
1150 var st
= container
.scope
.lookup (name
) as Struct
;
1152 st
= new
Struct (name
, current_source_reference
);
1153 st
.access
= SymbolAccessibility
.PUBLIC
;
1155 var st_attributes
= get_attributes (node
.name
);
1156 if (st_attributes
!= null) {
1157 foreach (string attr
in st_attributes
) {
1158 var nv
= attr
.split ("=", 2);
1159 if (nv
[0] == "cheader_filename") {
1160 st
.set_attribute_string ("CCode", "cheader_filename", eval (nv
[1]));
1161 } else if (nv
[0] == "deprecated") {
1162 if (eval (nv
[1]) == "1") {
1163 st
.set_attribute_bool ("Version", "deprecated", true);
1165 } else if (nv
[0] == "replacement") {
1166 st
.set_attribute_string ("Version", "replacement", eval (nv
[1]));
1167 } else if (nv
[0] == "deprecated_since") {
1168 st
.set_attribute_string ("Version", "deprecated_since", eval (nv
[1]));
1169 } else if (nv
[0] == "immutable") {
1170 if (eval (nv
[1]) == "1") {
1171 st
.set_attribute ("Immutable", true);
1173 } else if (nv
[0] == "has_copy_function") {
1174 if (eval (nv
[1]) == "0") {
1175 st
.set_attribute_bool ("CCode", "has_copy_function", false);
1177 } else if (nv
[0] == "has_destroy_function") {
1178 if (eval (nv
[1]) == "0") {
1179 st
.set_attribute_bool ("CCode", "has_destroy_function", false);
1181 } else if (nv
[0] == "experimental") {
1182 if (eval (nv
[1]) == "1") {
1183 st
.set_attribute_bool ("Version", "experimental", true);
1189 add_symbol_to_container (container
, st
);
1190 current_source_file
.add_node (st
);
1193 current_data_type
= st
;
1195 foreach (weak IdlNode member
in boxed_node
.members
) {
1196 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1197 var m
= parse_function ((IdlNodeFunction
) member
);
1201 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
1202 var f
= parse_field ((IdlNodeField
) member
);
1209 current_data_type
= null;
1211 bool ref_function_void
= false;
1212 string ref_function
= null;
1213 string unref_function
= null;
1214 string copy_function
= null;
1215 string free_function
= null;
1217 var cl
= container
.scope
.lookup (name
) as Class
;
1219 string base_class
= null;
1221 cl
= new
Class (name
, current_source_reference
);
1222 cl
.access
= SymbolAccessibility
.PUBLIC
;
1223 cl
.is_compact
= true;
1224 if (boxed_node
.gtype_init
!= null) {
1225 cl
.set_attribute_string ("CCode", "type_id", "%s ()".printf (boxed_node
.gtype_init
));
1228 var cl_attributes
= get_attributes (node
.name
);
1229 if (cl_attributes
!= null) {
1230 foreach (string attr
in cl_attributes
) {
1231 var nv
= attr
.split ("=", 2);
1232 if (nv
[0] == "cheader_filename") {
1233 cl
.set_attribute_string ("CCode", "cheader_filename", eval (nv
[1]));
1234 } else if (nv
[0] == "base_class") {
1235 base_class
= eval (nv
[1]);
1236 } else if (nv
[0] == "is_immutable") {
1237 if (eval (nv
[1]) == "1") {
1238 cl
.is_immutable
= true;
1240 } else if (nv
[0] == "deprecated") {
1241 if (eval (nv
[1]) == "1") {
1242 cl
.set_attribute_bool ("Version", "deprecated", true);
1244 } else if (nv
[0] == "replacement") {
1245 cl
.set_attribute_string ("Version", "replacement", eval (nv
[1]));
1246 } else if (nv
[0] == "deprecated_since") {
1247 cl
.set_attribute_string ("Version", "deprecated_since", eval (nv
[1]));
1248 } else if (nv
[0] == "const_cname") {
1249 cl
.set_attribute_string ("CCode", "const_cname", eval (nv
[1]));
1250 } else if (nv
[0] == "free_function") {
1251 free_function
= eval (nv
[1]);
1252 } else if (nv
[0] == "ref_function") {
1253 ref_function
= eval (nv
[1]);
1254 } else if (nv
[0] == "unref_function") {
1255 unref_function
= eval (nv
[1]);
1256 } else if (nv
[0] == "copy_function") {
1257 copy_function
= eval (nv
[1]);
1258 } else if (nv
[0] == "ref_function_void") {
1259 if (eval (nv
[1]) == "1") {
1260 ref_function_void
= true;
1262 } else if (nv
[0] == "experimental") {
1263 if (eval (nv
[1]) == "1") {
1264 cl
.set_attribute_bool ("Version", "experimental", true);
1270 add_symbol_to_container (container
, cl
);
1271 current_source_file
.add_node (cl
);
1273 if (base_class
!= null) {
1274 var parent
= parse_type_string (base_class
);
1275 cl
.add_base_type (parent
);
1279 current_data_type
= cl
;
1281 foreach (weak IdlNode member
in boxed_node
.members
) {
1282 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1283 if (member
.name
== "ref") {
1284 ref_function
= ((IdlNodeFunction
) member
).symbol
;
1285 ref_function_void
= (parse_type (((IdlNodeFunction
) member
).result
.type
) is VoidType
);
1286 } else if (member
.name
== "unref") {
1287 unref_function
= ((IdlNodeFunction
) member
).symbol
;
1288 } else if (member
.name
== "free" || member
.name
== "destroy") {
1289 free_function
= ((IdlNodeFunction
) member
).symbol
;
1291 if (member
.name
== "copy") {
1292 copy_function
= ((IdlNodeFunction
) member
).symbol
;
1294 var m
= parse_function ((IdlNodeFunction
) member
);
1299 } else if (member
.type
== IdlNodeTypeId
.FIELD
) {
1300 var f
= parse_field ((IdlNodeField
) member
);
1307 if (ref_function
!= null) {
1308 cl
.set_attribute_string ("CCode", "ref_function", ref_function
);
1309 if (ref_function_void
) {
1310 cl
.set_attribute_bool ("CCode", "ref_function_void", ref_function_void
);
1312 } else if (copy_function
!= null) {
1313 cl
.set_attribute_string ("CCode", "copy_function", copy_function
);
1315 if (unref_function
!= null) {
1316 cl
.set_attribute_string ("CCode", "unref_function", unref_function
);
1317 } else if (free_function
!= null && free_function
!= "%sfree".printf (get_lower_case_cprefix (cl
))) {
1318 cl
.set_attribute_string ("CCode", "free_function", free_function
);
1321 current_data_type
= null;
1325 private void parse_enum (IdlNodeEnum en_node
, Symbol container
, IdlModule module
, bool is_flags
) {
1326 weak IdlNode node
= (IdlNode
) en_node
;
1327 string name
= fix_type_name (node
.name
, container
);
1328 bool existing
= true;
1330 var en
= container
.scope
.lookup (name
) as Enum
;
1332 en
= new
Enum (name
, current_source_reference
);
1333 en
.access
= SymbolAccessibility
.PUBLIC
;
1336 // ignore dummy enum values in -custom.vala files
1337 // they exist for syntactical reasons
1338 var dummy
= (EnumValue
) en
.scope
.lookup ("__DUMMY__");
1339 if (dummy
!= null) {
1340 en
.get_values ().remove (dummy
);
1341 en
.scope
.remove ("__DUMMY__");
1345 if (en_node
.gtype_name
== null || en_node
.gtype_name
== "") {
1346 en
.set_attribute_bool ("CCode", "has_type_id", false);
1349 string common_prefix
= null;
1351 foreach (weak IdlNode value
in en_node
.values
) {
1352 var val_attributes
= get_attributes (value
.name
);
1353 bool is_hidden
= false;
1354 if (val_attributes
!= null) {
1355 foreach (string attr
in val_attributes
) {
1356 var nv
= attr
.split ("=", 2);
1357 if (nv
[0] == "hidden" && eval(nv
[1]) == "1") {
1367 if (common_prefix
== null) {
1368 common_prefix
= value
.name
;
1369 while (common_prefix
.length
> 0 && !common_prefix
.has_suffix ("_")) {
1370 // FIXME: could easily be made faster
1371 common_prefix
= common_prefix
.substring (0, common_prefix
.length
- 1);
1374 while (!value
.name
.has_prefix (common_prefix
)) {
1375 common_prefix
= common_prefix
.substring (0, common_prefix
.length
- 1);
1378 while (common_prefix
.length
> 0 && (!common_prefix
.has_suffix ("_") ||
1379 (value
.name
.get_char (common_prefix
.length
).isdigit ()) && (value
.name
.length
- common_prefix
.length
) <= 1)) {
1380 // enum values may not consist solely of digits
1381 common_prefix
= common_prefix
.substring (0, common_prefix
.length
- 1);
1385 bool is_errordomain
= false;
1387 string cheader_filename
= null;
1389 var en_attributes
= get_attributes (node
.name
);
1390 if (en_attributes
!= null) {
1391 foreach (string attr
in en_attributes
) {
1392 var nv
= attr
.split ("=", 2);
1393 if (nv
[0] == "common_prefix") {
1394 common_prefix
= eval (nv
[1]);
1395 } else if (nv
[0] == "cheader_filename") {
1396 cheader_filename
= eval (nv
[1]);
1397 en
.set_attribute_string ("CCode", "cheader_filename", cheader_filename
);
1398 } else if (nv
[0] == "hidden") {
1399 if (eval (nv
[1]) == "1") {
1402 } else if (nv
[0] == "deprecated") {
1403 if (eval (nv
[1]) == "1") {
1404 en
.set_attribute_bool ("Version", "deprecated", true);
1406 } else if (nv
[0] == "default_value") {
1407 en
.set_attribute_string ("CCode", "default_value", eval (nv
[1]));
1408 } else if (nv
[0] == "replacement") {
1409 en
.set_attribute_string ("Version", "replacement", eval (nv
[1]));
1410 } else if (nv
[0] == "deprecated_since") {
1411 en
.set_attribute_string ("Version", "deprecated_since", eval (nv
[1]));
1412 } else if (nv
[0] == "rename_to") {
1413 en
.name
= eval (nv
[1]);
1414 } else if (nv
[0] == "errordomain") {
1415 if (eval (nv
[1]) == "1") {
1416 is_errordomain
= true;
1418 } else if (nv
[0] == "to_string") {
1419 var return_type
= new
UnresolvedType ();
1420 return_type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1421 return_type
.value_owned
= false;
1422 var m
= new
Method ("to_string", return_type
, current_source_reference
);
1423 m
.access
= SymbolAccessibility
.PUBLIC
;
1424 m
.set_attribute_string ("CCode", "cname", eval(nv
[1]));
1426 } else if (nv
[0] == "experimental") {
1427 if (eval (nv
[1]) == "1") {
1428 en
.set_attribute_bool ("Version", "experimental", true);
1434 en
.set_attribute_string ("CCode", "cprefix", common_prefix
);
1436 foreach (weak IdlNode value2
in en_node
.values
) {
1437 EnumValue ev
= new
EnumValue (value2
.name
.substring (common_prefix
.length
), null);
1439 var val_attributes
= get_attributes (value2
.name
);
1440 bool is_hidden
= false;
1441 if (val_attributes
!= null) {
1442 foreach (string attr
in val_attributes
) {
1443 var nv
= attr
.split ("=", 2);
1444 if (nv
[0] == "hidden" && eval(nv
[1]) == "1") {
1446 } else if (nv
[0] == "deprecated") {
1447 if (eval (nv
[1]) == "1") {
1448 ev
.set_attribute_bool ("Version", "deprecated", true);
1450 } else if (nv
[0] == "replacement") {
1451 ev
.set_attribute_string ("Version", "replacement", eval (nv
[1]));
1452 } else if (nv
[0] == "deprecated_since") {
1453 ev
.set_attribute_string ("Version", "deprecated_since", eval (nv
[1]));
1463 if (is_errordomain
) {
1464 var ed
= new
ErrorDomain (en
.name
, current_source_reference
);
1465 ed
.access
= SymbolAccessibility
.PUBLIC
;
1466 ed
.set_attribute_string ("CCode", "cprefix", common_prefix
);
1468 if (cheader_filename
!= null) {
1469 ed
.set_attribute_string ("CCode", "cheader_filename", cheader_filename
);
1472 foreach (EnumValue ev
in en
.get_values ()) {
1473 ed
.add_code (new
ErrorCode (ev
.name
));
1476 current_source_file
.add_node (ed
);
1478 add_symbol_to_container (container
, ed
);
1481 en
.set_attribute ("Flags", is_flags
);
1482 current_source_file
.add_node (en
);
1484 add_symbol_to_container (container
, en
);
1489 private void parse_object (IdlNodeInterface node
, Symbol container
, IdlModule module
) {
1490 string name
= fix_type_name (((IdlNode
) node
).name
, container
);
1492 string base_class
= null;
1494 var cl
= container
.scope
.lookup (name
) as Class
;
1496 cl
= new
Class (name
, current_source_reference
);
1497 cl
.access
= SymbolAccessibility
.PUBLIC
;
1499 var attributes
= get_attributes (node
.gtype_name
);
1500 if (attributes
!= null) {
1501 foreach (string attr
in attributes
) {
1502 var nv
= attr
.split ("=", 2);
1503 if (nv
[0] == "cheader_filename") {
1504 cl
.set_attribute_string ("CCode", "cheader_filename", eval (nv
[1]));
1505 } else if (nv
[0] == "base_class") {
1506 base_class
= eval (nv
[1]);
1507 } else if (nv
[0] == "hidden") {
1508 if (eval (nv
[1]) == "1") {
1511 } else if (nv
[0] == "type_check_function") {
1512 cl
.set_attribute_string ("CCode", "type_check_function", eval (nv
[1]));
1513 } else if (nv
[0] == "deprecated") {
1514 if (eval (nv
[1]) == "1") {
1515 cl
.set_attribute_bool ("Version", "deprecated", true);
1517 } else if (nv
[0] == "replacement") {
1518 cl
.set_attribute_string ("Version", "replacement", eval (nv
[1]));
1519 } else if (nv
[0] == "deprecated_since") {
1520 cl
.set_attribute_string ("Version", "deprecated_since", eval (nv
[1]));
1521 } else if (nv
[0] == "type_id") {
1522 cl
.set_attribute_string ("CCode", "type_id", eval (nv
[1]));
1523 } else if (nv
[0] == "abstract") {
1524 if (eval (nv
[1]) == "1") {
1525 cl
.is_abstract
= true;
1527 } else if (nv
[0] == "experimental") {
1528 if (eval (nv
[1]) == "1") {
1529 cl
.set_attribute_bool ("Version", "experimental", true);
1531 } else if (nv
[0] == "compact") {
1532 if (eval (nv
[1]) == "1") {
1533 cl
.is_compact
= true;
1535 } else if (nv
[0] == "ref_function") {
1536 cl
.set_attribute_string ("CCode", "ref_function", eval (nv
[1]));
1537 } else if (nv
[0] == "unref_function") {
1538 cl
.set_attribute_string ("CCode", "unref_function", eval (nv
[1]));
1539 } else if (nv
[0] == "copy_function") {
1540 cl
.set_attribute_string ("CCode", "copy_function", eval (nv
[1]));
1541 } else if (nv
[0] == "free_function") {
1542 cl
.set_attribute_string ("CCode", "free_function", eval (nv
[1]));
1547 add_symbol_to_container (container
, cl
);
1548 current_source_file
.add_node (cl
);
1551 if (base_class
!= null) {
1552 var parent
= parse_type_string (base_class
);
1553 cl
.add_base_type (parent
);
1554 } else if (node
.parent
!= null) {
1555 if (!cl
.is_compact
) {
1556 var parent
= parse_type_string (node
.parent
);
1557 cl
.add_base_type (parent
);
1560 var gobject_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "Object");
1561 cl
.add_base_type (new UnresolvedType
.from_symbol (gobject_symbol
));
1564 foreach (string iface_name
in node
.interfaces
) {
1565 bool skip_iface
= false;
1567 var attributes
= get_attributes (iface_name
);
1568 if (attributes
!= null) {
1569 foreach (string attr
in attributes
) {
1570 var nv
= attr
.split ("=", 2);
1571 if (nv
[0] == "hidden") {
1572 if (eval (nv
[1]) == "1") {
1583 var iface
= parse_type_string (iface_name
);
1584 cl
.add_base_type (iface
);
1587 current_data_type
= cl
;
1589 current_type_symbol_set
= new HashSet
<string> (str_hash
, str_equal
);
1590 var current_type_func_map
= new HashMap
<string,weak IdlNodeFunction
> (str_hash
, str_equal
);
1591 var current_type_vfunc_map
= new HashMap
<string,string> (str_hash
, str_equal
);
1593 foreach (weak IdlNode member
in node
.members
) {
1594 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1595 current_type_func_map
.set (member
.name
, (IdlNodeFunction
) member
);
1597 if (member
.type
== IdlNodeTypeId
.VFUNC
) {
1598 current_type_vfunc_map
.set (member
.name
, "1");
1602 foreach (weak IdlNode member
in node
.members
) {
1603 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1604 // Ignore if vfunc (handled below)
1605 if (!current_type_vfunc_map
.contains (member
.name
)) {
1606 var m
= parse_function ((IdlNodeFunction
) member
);
1611 } else if (member
.type
== IdlNodeTypeId
.VFUNC
) {
1612 var m
= parse_virtual ((IdlNodeVFunc
) member
, current_type_func_map
.get (member
.name
));
1616 } else if (member
.type
== IdlNodeTypeId
.PROPERTY
) {
1617 var prop
= parse_property ((IdlNodeProperty
) member
);
1619 cl
.add_property (prop
);
1621 } else if (member
.type
== IdlNodeTypeId
.SIGNAL
) {
1622 var sig
= parse_signal ((IdlNodeSignal
) member
);
1624 cl
.add_signal (sig
);
1629 foreach (weak IdlNode member
in node
.members
) {
1630 if (member
.type
== IdlNodeTypeId
.FIELD
) {
1631 if (!current_type_symbol_set
.contains (member
.name
)) {
1632 var f
= parse_field ((IdlNodeField
) member
);
1640 foreach (Property prop
in cl
.get_properties ()) {
1641 var getter
= "get_%s".printf (prop
.name
);
1643 if (prop
.get_accessor
!= null && !current_type_symbol_set
.contains (getter
)) {
1644 prop
.set_attribute ("NoAccessorMethod", true);
1647 var setter
= "set_%s".printf (prop
.name
);
1649 if (prop
.set_accessor
!= null && prop
.set_accessor
.writable
1650 && !current_type_symbol_set
.contains (setter
)) {
1651 prop
.set_attribute ("NoAccessorMethod", true);
1654 if (prop
.get_attribute ("NoAccessorMethod") != null && prop
.get_accessor
!= null) {
1655 prop
.get_accessor
.value_type
.value_owned
= true;
1659 handle_async_methods (cl
);
1661 if (cl
.default_construction_method
== null) {
1662 // always provide constructor in generated bindings
1663 // to indicate that implicit Object () chainup is allowed
1664 var cm
= new
CreationMethod (null, null, cl
.source_reference
);
1665 cm
.has_construct_function
= false;
1666 cm
.access
= SymbolAccessibility
.PROTECTED
;
1670 current_data_type
= null;
1671 current_type_symbol_set
= null;
1674 private void parse_interface (IdlNodeInterface node
, Symbol container
, IdlModule module
) {
1675 string name
= fix_type_name (node
.gtype_name
, container
);
1677 var iface
= container
.scope
.lookup (name
) as Interface
;
1678 if (iface
== null) {
1679 iface
= new
Interface (name
, current_source_reference
);
1680 iface
.access
= SymbolAccessibility
.PUBLIC
;
1682 var attributes
= get_attributes (node
.gtype_name
);
1683 if (attributes
!= null) {
1684 foreach (string attr
in attributes
) {
1685 var nv
= attr
.split ("=", 2);
1686 if (nv
[0] == "cheader_filename") {
1687 iface
.set_attribute_string ("CCode", "cheader_filename", eval (nv
[1]));
1688 } else if (nv
[0] == "hidden") {
1689 if (eval (nv
[1]) == "1") {
1692 } else if (nv
[0] == "type_cname") {
1693 iface
.set_attribute_string ("CCode", "type_cname", eval (nv
[1]));
1694 } else if (nv
[0] == "lower_case_csuffix") {
1695 iface
.set_attribute_string ("CCode", "lower_case_csuffix", eval (nv
[1]));
1700 foreach (string prereq_name
in node
.prerequisites
) {
1701 var prereq
= parse_type_string (prereq_name
);
1702 iface
.add_prerequisite (prereq
);
1705 add_symbol_to_container (container
, iface
);
1706 current_source_file
.add_node (iface
);
1709 current_data_type
= iface
;
1711 current_type_symbol_set
= new HashSet
<string> (str_hash
, str_equal
);
1712 var current_type_func_map
= new HashMap
<string,weak IdlNodeFunction
> (str_hash
, str_equal
);
1713 var current_type_vfunc_map
= new HashMap
<string,string> (str_hash
, str_equal
);
1715 foreach (weak IdlNode member
in node
.members
) {
1716 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1717 current_type_func_map
.set (member
.name
, (IdlNodeFunction
) member
);
1719 if (member
.type
== IdlNodeTypeId
.VFUNC
) {
1720 current_type_vfunc_map
.set (member
.name
, "1");
1724 foreach (weak IdlNode member
in node
.members
) {
1725 if (member
.type
== IdlNodeTypeId
.FUNCTION
) {
1726 // Ignore if vfunc (handled below)
1727 if (!current_type_vfunc_map
.contains (member
.name
)) {
1728 var m
= parse_function ((IdlNodeFunction
) member
, true);
1730 iface
.add_method (m
);
1733 } else if (member
.type
== IdlNodeTypeId
.VFUNC
) {
1734 var m
= parse_virtual ((IdlNodeVFunc
) member
, current_type_func_map
.get (member
.name
), true);
1736 iface
.add_method (m
);
1738 } else if (member
.type
== IdlNodeTypeId
.PROPERTY
) {
1739 var prop
= parse_property ((IdlNodeProperty
) member
);
1741 iface
.add_property (prop
);
1743 } else if (member
.type
== IdlNodeTypeId
.SIGNAL
) {
1744 var sig
= parse_signal ((IdlNodeSignal
) member
);
1746 iface
.add_signal (sig
);
1747 sig
.is_virtual
= false;
1752 foreach (Property prop
in iface
.get_properties ()) {
1753 var getter
= "get_%s".printf (prop
.name
);
1755 if (prop
.get_accessor
!= null && !current_type_symbol_set
.contains (getter
)) {
1756 prop
.set_attribute ("NoAccessorMethod", true);
1759 var setter
= "set_%s".printf (prop
.name
);
1761 if (prop
.set_accessor
!= null && prop
.set_accessor
.writable
1762 && !current_type_symbol_set
.contains (setter
)) {
1763 prop
.set_attribute ("NoAccessorMethod", true);
1766 if (prop
.get_attribute ("NoAccessorMethod") != null && prop
.get_accessor
!= null) {
1767 prop
.get_accessor
.value_type
.value_owned
= true;
1771 handle_async_methods (iface
);
1773 current_data_type
= null;
1776 void handle_async_methods (ObjectTypeSymbol type_symbol
) {
1777 Set
<Method
> finish_methods
= new HashSet
<Method
> ();
1778 var methods
= type_symbol
.get_methods ();
1780 foreach (Method m
in methods
) {
1782 string finish_method_base
;
1783 if (m
.name
.has_suffix ("_async")) {
1784 finish_method_base
= m
.name
.substring (0, m
.name
.length
- "_async".length
);
1786 finish_method_base
= m
.name
;
1788 var finish_method
= type_symbol
.scope
.lookup (finish_method_base
+ "_finish") as Method
;
1790 // check if the method is using non-standard finish method name
1791 if (finish_method
== null) {
1792 var method_cname
= get_finish_cname (m
);
1793 foreach (Method method
in type_symbol
.get_methods ()) {
1794 if (get_cname (method
) == method_cname
) {
1795 finish_method
= method
;
1801 if (finish_method
!= null) {
1802 m
.return_type
= finish_method
.return_type
.copy ();
1803 var a
= finish_method
.get_attribute ("CCode");
1804 if (a
!= null && a
.has_argument ("array_length")) {
1805 m
.set_attribute_bool ("CCode", "array_length", a
.get_bool ("array_length"));
1807 if (a
!= null && a
.has_argument ("array_null_terminated")) {
1808 m
.set_attribute_bool ("CCode", "array_null_terminated", a
.get_bool ("array_null_terminated"));
1810 foreach (var param
in finish_method
.get_parameters ()) {
1811 if (param
.direction
== ParameterDirection
.OUT
) {
1812 var async_param
= param
.copy ();
1813 if (m
.scope
.lookup (param
.name
) != null) {
1814 // parameter name conflict
1815 async_param
.name
+= "_out";
1817 m
.add_parameter (async_param
);
1820 foreach (DataType error_type
in finish_method
.get_error_types ()) {
1821 m
.add_error_type (error_type
.copy ());
1823 finish_methods
.add (finish_method
);
1828 foreach (Method m
in finish_methods
)
1830 type_symbol
.scope
.remove (m
.name
);
1835 private DataType?
parse_type (IdlNodeType type_node
, out ParameterDirection direction
= null) {
1836 direction
= ParameterDirection
.IN
;
1838 var type
= new
UnresolvedType ();
1839 if (type_node
.tag
== TypeTag
.VOID
) {
1840 if (type_node
.is_pointer
) {
1841 return new
PointerType (new
VoidType ());
1843 return new
VoidType ();
1845 } else if (type_node
.tag
== TypeTag
.BOOLEAN
) {
1846 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "bool");
1847 } else if (type_node
.tag
== TypeTag
.INT8
) {
1848 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "char");
1849 } else if (type_node
.tag
== TypeTag
.UINT8
) {
1850 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uchar");
1851 } else if (type_node
.tag
== TypeTag
.INT16
) {
1852 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int16");
1853 } else if (type_node
.tag
== TypeTag
.UINT16
) {
1854 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint16");
1855 } else if (type_node
.tag
== TypeTag
.INT32
) {
1856 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int32");
1857 } else if (type_node
.tag
== TypeTag
.UINT32
) {
1858 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint32");
1859 } else if (type_node
.tag
== TypeTag
.INT64
) {
1860 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int64");
1861 } else if (type_node
.tag
== TypeTag
.UINT64
) {
1862 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint64");
1863 } else if (type_node
.tag
== TypeTag
.INT
) {
1864 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int");
1865 } else if (type_node
.tag
== TypeTag
.UINT
) {
1866 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint");
1867 } else if (type_node
.tag
== TypeTag
.LONG
) {
1868 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "long");
1869 } else if (type_node
.tag
== TypeTag
.ULONG
) {
1870 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ulong");
1871 } else if (type_node
.tag
== TypeTag
.SSIZE
) {
1872 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ssize_t");
1873 } else if (type_node
.tag
== TypeTag
.SIZE
) {
1874 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "size_t");
1875 } else if (type_node
.tag
== TypeTag
.FLOAT
) {
1876 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "float");
1877 } else if (type_node
.tag
== TypeTag
.DOUBLE
) {
1878 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "double");
1879 } else if (type_node
.tag
== TypeTag
.UTF8
) {
1880 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1881 } else if (type_node
.tag
== TypeTag
.FILENAME
) {
1882 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1883 } else if (type_node
.tag
== TypeTag
.ARRAY
) {
1884 var element_type
= parse_type (type_node
.parameter_type1
);
1885 type
= element_type as UnresolvedType
;
1887 return element_type
;
1889 element_type
.value_owned
= true;
1890 return new
ArrayType (element_type
, 1, element_type
.source_reference
);
1891 } else if (type_node
.tag
== TypeTag
.LIST
) {
1892 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "List");
1893 } else if (type_node
.tag
== TypeTag
.SLIST
) {
1894 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "SList");
1895 } else if (type_node
.tag
== TypeTag
.HASH
) {
1896 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "HashTable");
1897 } else if (type_node
.tag
== TypeTag
.ERROR
) {
1898 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "Error");
1899 } else if (type_node
.unparsed
.has_prefix ("cairo_device_t") || type_node
.unparsed
.has_prefix ("cairo_pattern_t") ||
1900 type_node
.unparsed
.has_prefix ("cairo_surface_t")) {
1901 if (type_node
.unparsed
.has_prefix ("cairo_device_t")) {
1902 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "Cairo"), "Device");
1903 } else if (type_node
.unparsed
.has_prefix ("cairo_pattern_t")) {
1904 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "Cairo"), "Pattern");
1905 } else if (type_node
.unparsed
.has_prefix ("cairo_surface_t")) {
1906 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "Cairo"), "Surface");
1908 if (type_node
.unparsed
.has_suffix ("**")) {
1909 direction
= ParameterDirection
.OUT
;
1911 } else if (type_node
.is_interface
) {
1912 var n
= type_node
.@
interface;
1918 if (n
.has_prefix ("const-")) {
1919 n
= n
.substring ("const-".length
);
1922 if (type_node
.is_pointer
&&
1923 (n
== "gchar" || n
== "char")) {
1924 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1925 if (type_node
.unparsed
.has_suffix ("**")) {
1926 direction
= ParameterDirection
.OUT
;
1928 } else if (n
== "gunichar") {
1929 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "unichar");
1930 } else if (n
== "gchar") {
1931 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "char");
1932 } else if (n
== "guchar" || n
== "guint8") {
1933 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uchar");
1934 if (type_node
.is_pointer
) {
1935 type
.value_owned
= true;
1936 return new
ArrayType (type
, 1, type
.source_reference
);
1938 } else if (n
== "gushort") {
1939 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ushort");
1940 } else if (n
== "gshort") {
1941 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "short");
1942 } else if (n
== "gconstpointer" || n
== "void") {
1943 return new
PointerType (new
VoidType ());
1944 } else if (n
== "goffset" || n
== "off_t") {
1945 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int64");
1946 } else if (n
== "value_array") {
1947 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "ValueArray");
1948 } else if (n
== "time_t") {
1949 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "ulong");
1950 } else if (n
== "socklen_t") {
1951 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint32");
1952 } else if (n
== "mode_t") {
1953 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint");
1954 } else if (n
== "gint" || n
== "pid_t") {
1955 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "int");
1956 } else if (n
== "unsigned" || n
== "unsigned-int") {
1957 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "uint");
1958 } else if (n
== "FILE") {
1959 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "FileStream");
1960 } else if (n
== "struct") {
1961 return new
PointerType (new
VoidType ());
1962 } else if (n
== "iconv_t") {
1963 return new
PointerType (new
VoidType ());
1964 } else if (n
== "GType") {
1965 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), "Type");
1966 if (type_node
.is_pointer
) {
1967 type
.value_owned
= true;
1968 return new
ArrayType (type
, 1, type
.source_reference
);
1970 } else if (n
== "GStrv") {
1971 type
.unresolved_symbol
= new
UnresolvedSymbol (null, "string");
1972 type
.value_owned
= true;
1973 return new
ArrayType (type
, 1, type
.source_reference
);
1975 var named_type
= parse_type_string (n
);
1976 type
= named_type as UnresolvedType
;
1980 if (is_simple_type (n
)) {
1981 if (type_node
.is_pointer
) {
1982 direction
= ParameterDirection
.OUT
;
1984 } else if (type_node
.unparsed
.has_suffix ("**")) {
1985 direction
= ParameterDirection
.OUT
;
1989 stdout
.printf ("%d\n", type_node
.tag
);
1994 private bool is_simple_type (string type_name
) {
1995 var st
= cname_type_map
[type_name
] as Struct
;
1996 if (st
!= null && st
.is_simple_type ()) {
2003 private DataType
parse_type_string (string n
) {
2004 if (n
== "va_list") {
2006 return new
PointerType (new
VoidType ());
2009 var type
= new
UnresolvedType ();
2011 var dt
= cname_type_map
[n
];
2013 UnresolvedSymbol parent_symbol
= null;
2014 if (dt
.parent_symbol
.name
!= null) {
2015 parent_symbol
= new
UnresolvedSymbol (null, dt
.parent_symbol
.name
);
2017 type
.unresolved_symbol
= new
UnresolvedSymbol (parent_symbol
, dt
.name
);
2021 var type_attributes
= get_attributes (n
);
2023 string ns_name
= null;
2025 if (null != type_attributes
) {
2026 foreach (string attr
in type_attributes
) {
2027 var nv
= attr
.split ("=", 2);
2029 if (nv
[0] == "cprefix") {
2030 type
.unresolved_symbol
= new
UnresolvedSymbol (null, n
.substring (eval (nv
[1]).length
));
2031 } else if (nv
[0] == "name") {
2032 type
.unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
2033 } else if (nv
[0] == "namespace") {
2034 ns_name
= eval (nv
[1]);
2035 } else if (nv
[0] == "rename_to") {
2036 type
.unresolved_symbol
= new
UnresolvedSymbol (null, eval (nv
[1]));
2041 if (type
.unresolved_symbol
!= null) {
2042 if (type
.unresolved_symbol
.name
== "pointer") {
2043 return new
PointerType (new
VoidType ());
2045 if (ns_name
!= null) {
2046 type
.unresolved_symbol
.inner
= new
UnresolvedSymbol (null, ns_name
);
2051 if (n
.has_prefix (current_namespace
.name
)) {
2052 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, current_namespace
.name
), n
.substring (current_namespace
.name
.length
));
2053 } else if (current_namespace
.parent_symbol
!= null && current_namespace
.parent_symbol
.name
!= null && n
.has_prefix (current_namespace
.parent_symbol
.name
)) {
2054 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, current_namespace
.parent_symbol
.name
), n
.substring (current_namespace
.parent_symbol
.name
.length
));
2055 } else if (n
.has_prefix ("G")) {
2056 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, "GLib"), n
.substring (1));
2058 var name_parts
= n
.split (".", 2);
2059 if (name_parts
[1] == null) {
2060 type
.unresolved_symbol
= new
UnresolvedSymbol (null, name_parts
[0]);
2062 type
.unresolved_symbol
= new
UnresolvedSymbol (new
UnresolvedSymbol (null, name_parts
[0]), name_parts
[1]);
2069 private DataType?
parse_param (IdlNodeParam param
, out ParameterDirection direction
= null) {
2070 var type
= parse_type (param
.type
, out direction
);
2072 // disable for now as null_ok not yet correctly set
2073 // type.non_null = !param.null_ok;
2078 private UnresolvedSymbol?
parse_symbol_from_string (string symbol_string
, SourceReference? source_reference
= null) {
2079 UnresolvedSymbol? sym
= null;
2080 foreach (unowned
string s
in symbol_string
.split (".")) {
2081 sym
= new
UnresolvedSymbol (sym
, s
, source_reference
);
2084 Report
.error (source_reference
, "a symbol must be specified");
2089 private bool parse_type_arguments_from_string (DataType parent_type
, string type_arguments
, SourceReference? source_reference
= null) {
2090 int type_arguments_length
= (int) type_arguments
.length
;
2091 GLib
.StringBuilder current
= new GLib
.StringBuilder
.sized (type_arguments_length
);
2094 for (var c
= 0 ; c
< type_arguments_length
; c
++) {
2095 if (type_arguments
[c
] == '<' || type_arguments
[c
] == '[') {
2097 current
.append_unichar (type_arguments
[c
]);
2098 } else if (type_arguments
[c
] == '>' || type_arguments
[c
] == ']') {
2100 current
.append_unichar (type_arguments
[c
]);
2101 } else if (type_arguments
[c
] == ',') {
2103 var dt
= parse_type_from_string (current
.str
, true, source_reference
);
2107 parent_type
.add_type_argument (dt
);
2108 current
.truncate ();
2110 current
.append_unichar (type_arguments
[c
]);
2113 current
.append_unichar (type_arguments
[c
]);
2117 var dt
= parse_type_from_string (current
.str
, true, source_reference
);
2121 parent_type
.add_type_argument (dt
);
2126 private DataType?
parse_type_from_string (string type_string
, bool owned_by_default
, SourceReference? source_reference
= null) {
2127 if (type_from_string_regex
== null) {
2129 type_from_string_regex
= new GLib
.Regex ("^(?:(owned|unowned|weak) +)?([0-9a-zA-Z_\\.]+)(?:<(.+)>)?(\\*+)?(\\[(,*)?\\])?(\\?)?$", GLib
.RegexCompileFlags
.ANCHORED
| GLib
.RegexCompileFlags
.DOLLAR_ENDONLY
| GLib
.RegexCompileFlags
.OPTIMIZE
);
2130 } catch (GLib
.RegexError e
) {
2131 GLib
.error ("Unable to compile regex: %s", e
.message
);
2135 GLib
.MatchInfo match
;
2136 if (!type_from_string_regex
.match (type_string
, 0, out match
)) {
2137 Report
.error (source_reference
, "unable to parse type");
2141 DataType? type
= null;
2143 var ownership_data
= match
.fetch (1);
2144 var type_name
= match
.fetch (2);
2145 var type_arguments_data
= match
.fetch (3);
2146 var pointers_data
= match
.fetch (4);
2147 var array_data
= match
.fetch (5);
2148 var array_dimension_data
= match
.fetch (6);
2149 var nullable_data
= match
.fetch (7);
2151 var nullable
= nullable_data
!= null && nullable_data
.length
> 0;
2153 if (ownership_data
== null && type_name
== "void") {
2154 if (array_data
== null && !nullable
) {
2155 type
= new
VoidType (source_reference
);
2156 if (pointers_data
!= null) {
2157 for (int i
=0; i
< pointers_data
.length
; i
++) {
2158 type
= new
PointerType (type
);
2163 Report
.error (source_reference
, "invalid void type");
2168 bool value_owned
= owned_by_default
;
2170 if (ownership_data
== "owned") {
2172 } else if (ownership_data
== "unowned") {
2173 value_owned
= false;
2176 var sym
= parse_symbol_from_string (type_name
, source_reference
);
2180 type
= new UnresolvedType
.from_symbol (sym
, source_reference
);
2182 if (type_arguments_data
!= null && type_arguments_data
.length
> 0) {
2183 if (!parse_type_arguments_from_string (type
, type_arguments_data
, source_reference
)) {
2188 if (pointers_data
!= null) {
2189 for (int i
=0; i
< pointers_data
.length
; i
++) {
2190 type
= new
PointerType (type
);
2194 if (array_data
!= null && array_data
.length
> 0) {
2195 type
.value_owned
= true;
2196 type
= new
ArrayType (type
, array_dimension_data
.length
+ 1, source_reference
);
2199 type
.nullable
= nullable
;
2200 type
.value_owned
= value_owned
;
2204 private Method?
create_method (string name
, string symbol
, IdlNodeParam? res
, GLib
.List
<IdlNodeParam
>? parameters
, bool is_constructor
, bool is_interface
) {
2205 DataType return_type
= null;
2207 return_type
= parse_param (res
);
2211 if (!is_interface
&& (is_constructor
|| name
.has_prefix ("new"))) {
2212 m
= new
CreationMethod (null, name
, current_source_reference
);
2213 m
.has_construct_function
= false;
2214 if (m
.name
== "new") {
2216 } else if (m
.name
.has_prefix ("new_")) {
2217 m
.name
= m
.name
.substring ("new_".length
);
2219 // For classes, check whether a creation method return type equals to the
2220 // type of the class created. If the types do not match (e.g. in most
2221 // gtk widgets) add an attribute to the creation method indicating the used
2223 if (current_data_type is Class
&& res
!= null) {
2224 if ("%s*".printf (get_cname (current_data_type
)) != res
.type
.unparsed
) {
2225 m
.set_attribute_string ("CCode", "type", res
.type
.unparsed
);
2229 m
= new
Method (name
, return_type
, current_source_reference
);
2231 m
.access
= SymbolAccessibility
.PUBLIC
;
2233 if (current_type_symbol_set
!= null) {
2234 current_type_symbol_set
.add (name
);
2237 if (current_data_type
!= null) {
2238 var sig_attributes
= get_attributes ("%s::%s".printf (get_cname (current_data_type
), name
));
2239 if (sig_attributes
!= null) {
2240 foreach (string attr
in sig_attributes
) {
2241 var nv
= attr
.split ("=", 2);
2242 if (nv
[0] == "has_emitter" && eval (nv
[1]) == "1") {
2249 bool add_ellipsis
= false;
2250 bool suppress_throws
= false;
2251 string? error_types
= null;
2252 Symbol? container
= null;
2254 var attributes
= get_attributes (symbol
);
2255 if (attributes
!= null) {
2256 foreach (string attr
in attributes
) {
2257 var nv
= attr
.split ("=", 2);
2258 if (nv
[0] == "name") {
2259 m
.name
= eval (nv
[1]);
2260 } else if (nv
[0] == "hidden") {
2261 if (eval (nv
[1]) == "1") {
2264 } else if (nv
[0] == "ellipsis") {
2265 if (eval (nv
[1]) == "1") {
2266 add_ellipsis
= true;
2268 } else if (nv
[0] == "printf_format") {
2269 if (eval (nv
[1]) == "1") {
2270 m
.set_attribute ("PrintfFormat", true);
2272 } else if (nv
[0] == "transfer_ownership") {
2273 if (eval (nv
[1]) == "1") {
2274 return_type
.value_owned
= true;
2276 } else if (nv
[0] == "transfer_container") {
2277 if (eval (nv
[1]) == "1") {
2278 return_type
.value_owned
= true;
2279 if (return_type is ArrayType
) {
2280 ((ArrayType
) return_type
).element_type
.value_owned
= false;
2283 } else if (nv
[0] == "destroys_instance") {
2284 if (eval (nv
[1]) == "1") {
2285 m
.set_attribute ("DestroysInstance", true, m
.source_reference
);
2287 } else if (nv
[0] == "returns_floating_reference") {
2288 if (eval (nv
[1]) == "1") {
2289 m
.set_attribute_bool ("CCode", "returns_floating_reference", true);
2290 m
.return_type
.value_owned
= true;
2292 } else if (nv
[0] == "nullable") {
2293 if (eval (nv
[1]) == "1" && !(return_type is VoidType
)) {
2294 return_type
.nullable
= true;
2296 } else if (nv
[0] == "sentinel") {
2297 m
.set_attribute_string ("CCode", "sentinel", eval (nv
[1]));
2298 } else if (nv
[0] == "is_array") {
2299 if (eval (nv
[1]) == "1") {
2300 return_type
.value_owned
= true;
2301 return_type
= new
ArrayType (return_type
, 1, return_type
.source_reference
);
2302 m
.return_type
= return_type
;
2304 } else if (nv
[0] == "is_pointer") {
2305 if (eval (nv
[1]) == "1") {
2306 return_type
= new
PointerType (return_type
, return_type
.source_reference
);
2307 m
.return_type
= return_type
;
2309 } else if (nv
[0] == "throws") {
2310 if (eval (nv
[1]) == "0") {
2311 suppress_throws
= true;
2313 } else if (nv
[0] == "error_types") {
2314 error_types
= eval (nv
[1]);
2315 } else if (nv
[0] == "no_array_length") {
2316 if (eval (nv
[1]) == "1") {
2317 m
.set_attribute_bool ("CCode", "array_length", false);
2319 } else if (nv
[0] == "array_null_terminated") {
2320 if (eval (nv
[1]) == "1") {
2321 m
.set_attribute_bool ("CCode", "array_length", false);
2322 m
.set_attribute_bool ("CCode", "array_null_terminated", true);;
2324 } else if (nv
[0] == "array_length_type") {
2325 m
.set_attribute_string ("CCode", "array_length_type", eval (nv
[1]));
2326 } else if (nv
[0] == "type_name") {
2327 m
.return_type
= return_type
= parse_type_from_string (eval (nv
[1]), return_type
.value_owned
);
2328 } else if (nv
[0] == "ctype") {
2329 m
.set_attribute_string ("CCode", "type", eval (nv
[1]));
2330 } else if (nv
[0] == "type_arguments") {
2331 parse_type_arguments_from_string (return_type
, eval (nv
[1]));
2332 } else if (nv
[0] == "deprecated") {
2333 if (eval (nv
[1]) == "1") {
2334 m
.set_attribute_bool ("Version", "deprecated", true);
2336 } else if (nv
[0] == "replacement") {
2337 m
.set_attribute_string ("Version", "replacement", eval (nv
[1]));
2338 } else if (nv
[0] == "deprecated_since") {
2339 m
.set_attribute_string ("Version", "deprecated_since", eval (nv
[1]));
2340 } else if (nv
[0] == "cheader_filename") {
2341 m
.set_attribute_string ("CCode", "cheader_filename", eval (nv
[1]));
2342 } else if (nv
[0] == "abstract") {
2343 if (eval (nv
[1]) == "1") {
2344 m
.is_abstract
= true;
2346 } else if (nv
[0] == "virtual") {
2347 if (eval (nv
[1]) == "1") {
2348 m
.is_virtual
= true;
2350 } else if (nv
[0] == "vfunc_name") {
2351 m
.set_attribute_string ("CCode", "vfunc_name", eval (nv
[1]));
2352 } else if (nv
[0] == "finish_vfunc_name") {
2353 m
.set_attribute_string ("CCode", "finish_vfunc_name", eval (nv
[1]));
2354 } else if (nv
[0] == "finish_name") {
2355 m
.set_attribute_string ("CCode", "finish_name", eval (nv
[1]));
2356 } else if (nv
[0] == "async") {
2357 if (eval (nv
[1]) == "1") {
2358 // force async function, even if it doesn't end in _async
2361 } else if (nv
[0] == "parent") {
2362 container
= get_container_from_name (eval (nv
[1]));
2363 var prefix
= get_lower_case_cprefix (container
);
2364 if (symbol
.has_prefix (prefix
)) {
2365 m
.name
= symbol
.substring (prefix
.length
);
2367 } else if (nv
[0] == "experimental") {
2368 if (eval (nv
[1]) == "1") {
2369 m
.set_attribute_bool ("Version", "experimental", true);
2371 } else if (nv
[0] == "simple_generics") {
2372 if (eval (nv
[1]) == "1") {
2373 m
.set_attribute_bool ("CCode", "simple_generics", true);
2380 Parameter last_param
= null;
2381 DataType last_param_type
= null;
2382 foreach (weak IdlNodeParam param
in parameters
) {
2383 weak IdlNode param_node
= (IdlNode
) param
;
2387 if (!(m is CreationMethod
) &&
2388 current_data_type
!= null &&
2389 param
.type
.is_interface
&&
2390 (param_node
.name
== "self" ||
2391 param
.type
.@
interface.has_suffix (get_cname (current_data_type
)))) {
2394 } else if (!(m is CreationMethod
) &&
2395 current_data_type
!= null &&
2396 param
.type
.is_interface
&&
2397 (param_node
.name
== "klass" ||
2398 param
.type
.@
interface.has_suffix ("%sClass".printf(get_cname (current_data_type
))))) {
2400 m
.binding
= MemberBinding
.CLASS
;
2401 if (m
.name
.has_prefix ("class_")) {
2402 m
.name
= m
.name
.substring ("class_".length
, m
.name
.length
- "class_".length
);
2407 m
.binding
= MemberBinding
.STATIC
;
2411 if (param
.type
.@
interface == "GAsyncReadyCallback" && (symbol
.has_suffix ("_async") || m
.coroutine
)) {
2417 // check for GError parameter
2418 if (suppress_throws
== false && param_is_exception (param
)) {
2419 if (error_types
== null)
2420 m
.add_error_type (parse_type (param
.type
));
2424 string param_name
= param_node
.name
;
2425 if (param_name
== "result") {
2426 // avoid conflict with generated result variable
2427 param_name
= "_result";
2428 } else if (param_name
== "string") {
2429 // avoid conflict with string type
2432 ParameterDirection direction
;
2433 var param_type
= parse_param (param
, out direction
);
2434 var p
= new
Parameter (param_name
, param_type
);
2435 p
.direction
= direction
;
2437 bool hide_param
= false;
2438 bool show_param
= false;
2439 bool set_array_length_pos
= false;
2440 double array_length_pos
= 0;
2441 bool set_delegate_target_pos
= false;
2442 double delegate_target_pos
= 0;
2443 bool array_requested
= false;
2444 bool out_requested
= false;
2445 attributes
= get_attributes ("%s.%s".printf (symbol
, param_node
.name
));
2446 if (attributes
!= null) {
2447 foreach (string attr
in attributes
) {
2448 var nv
= attr
.split ("=", 2);
2449 if (nv
[0] == "is_array") {
2450 if (eval (nv
[1]) == "1") {
2451 param_type
.value_owned
= true;
2452 param_type
= new
ArrayType (param_type
, 1, param_type
.source_reference
);
2453 p
.variable_type
= param_type
;
2454 if (!out_requested
) {
2455 p
.direction
= ParameterDirection
.IN
;
2457 array_requested
= true;
2459 } else if (nv
[0] == "is_pointer") {
2460 if (eval (nv
[1]) == "1") {
2461 param_type
= new
PointerType (param_type
, return_type
.source_reference
);
2462 p
.variable_type
= param_type
;
2463 if (!out_requested
) {
2464 p
.direction
= ParameterDirection
.IN
;
2467 } else if (nv
[0] == "is_out") {
2468 if (eval (nv
[1]) == "1") {
2469 p
.direction
= ParameterDirection
.OUT
;
2470 out_requested
= true;
2471 if (!array_requested
&& param_type is ArrayType
) {
2472 var array_type
= (ArrayType
) param_type
;
2473 param_type
= array_type
.element_type
;
2474 p
.variable_type
= param_type
;
2477 } else if (nv
[0] == "is_ref") {
2478 if (eval (nv
[1]) == "1") {
2479 p
.direction
= ParameterDirection
.REF
;
2480 if (!array_requested
&& param_type is ArrayType
) {
2481 var array_type
= (ArrayType
) param_type
;
2482 param_type
= array_type
.element_type
;
2483 p
.variable_type
= param_type
;
2486 } else if (nv
[0] == "nullable") {
2487 if (eval (nv
[1]) == "1" && !(param_type is VoidType
)) {
2488 param_type
.nullable
= true;
2490 } else if (nv
[0] == "transfer_ownership") {
2491 if (eval (nv
[1]) == "1") {
2492 param_type
.value_owned
= true;
2494 } else if (nv
[0] == "takes_ownership") {
2495 if (eval (nv
[1]) == "1") {
2496 param_type
.value_owned
= true;
2498 } else if (nv
[0] == "value_owned") {
2499 if (eval (nv
[1]) == "0") {
2500 param_type
.value_owned
= false;
2501 } else if (eval (nv
[1]) == "1") {
2502 param_type
.value_owned
= true;
2504 } else if (nv
[0] == "hidden") {
2505 if (eval (nv
[1]) == "1") {
2507 } else if (eval (nv
[1]) == "0") {
2510 } else if (nv
[0] == "no_array_length") {
2511 if (eval (nv
[1]) == "1") {
2512 p
.set_attribute_bool ("CCode", "array_length", false);
2514 } else if (nv
[0] == "array_length_type") {
2515 p
.set_attribute_string ("CCode", "array_length_type", eval (nv
[1]));
2516 } else if (nv
[0] == "array_null_terminated") {
2517 if (eval (nv
[1]) == "1") {
2518 p
.set_attribute_bool ("CCode", "array_length", false);
2519 p
.set_attribute_bool ("CCode", "array_null_terminated", true);
2521 } else if (nv
[0] == "array_length_pos") {
2522 set_array_length_pos
= true;
2523 array_length_pos
= double.parse (eval (nv
[1]));
2524 } else if (nv
[0] == "delegate_target_pos") {
2525 set_delegate_target_pos
= true;
2526 delegate_target_pos
= double.parse (eval (nv
[1]));
2527 } else if (nv
[0] == "type_name") {
2528 p
.variable_type
= param_type
= parse_type_from_string (eval (nv
[1]), false);
2529 } else if (nv
[0] == "ctype") {
2530 p
.set_attribute_string ("CCode", "type", eval (nv
[1]));
2531 } else if (nv
[0] == "scope") {
2532 p
.set_attribute_string ("CCode", "scope", eval (nv
[1]));
2533 } else if (nv
[0] == "type_arguments") {
2534 parse_type_arguments_from_string (param_type
, eval (nv
[1]));
2535 } else if (nv
[0] == "default_value") {
2536 var val
= eval (nv
[1]);
2537 if (val
== "null") {
2538 p
.initializer
= new
NullLiteral (param_type
.source_reference
);
2539 } else if (val
== "true") {
2540 p
.initializer
= new
BooleanLiteral (true, param_type
.source_reference
);
2541 } else if (val
== "false") {
2542 p
.initializer
= new
BooleanLiteral (false, param_type
.source_reference
);
2543 } else if (val
== "") {
2544 p
.initializer
= new
StringLiteral ("\"\"", param_type
.source_reference
);
2546 if (int64.try_parse (val
)) {
2547 p
.initializer
= new
IntegerLiteral (val
, param_type
.source_reference
);
2549 if (double.try_parse (val
)) {
2550 p
.initializer
= new
RealLiteral (val
, param_type
.source_reference
);
2552 if (val
.has_prefix ("\"") && val
.has_suffix ("\"")) {
2553 p
.initializer
= new
StringLiteral (val
, param_type
.source_reference
);
2555 foreach (unowned
string member
in val
.split (".")) {
2556 p
.initializer
= new
MemberAccess (p
.initializer
, member
, param_type
.source_reference
);
2566 if (last_param
!= null && p
.name
== "n_" + last_param
.name
) {
2567 if (!(last_param_type is ArrayType
)) {
2568 // last_param is array, p is array length
2569 last_param_type
.value_owned
= true;
2570 last_param_type
= new
ArrayType (last_param_type
, 1, last_param_type
.source_reference
);
2571 last_param
.variable_type
= last_param_type
;
2572 last_param
.direction
= ParameterDirection
.IN
;
2575 // hide array length param
2577 } else if (last_param
!= null && p
.name
== "user_data") {
2578 // last_param is delegate
2580 // hide deleate target param
2584 if (show_param
|| !hide_param
) {
2585 m
.add_parameter (p
);
2586 if (set_array_length_pos
) {
2587 p
.set_attribute_double ("CCode", "array_length_pos", array_length_pos
);
2589 if (set_delegate_target_pos
) {
2590 p
.set_attribute_double ("CCode", "delegate_target_pos", delegate_target_pos
);
2595 last_param_type
= param_type
;
2598 if (suppress_throws
== false && error_types
!= null) {
2599 var type_args
= eval (error_types
).split (",");
2600 foreach (unowned
string type_arg
in type_args
) {
2601 m
.add_error_type (parse_type_from_string (type_arg
, true));
2606 // no parameters => static method
2607 m
.binding
= MemberBinding
.STATIC
;
2610 if (last_param
!= null && last_param
.name
.has_prefix ("first_")) {
2611 last_param
.ellipsis
= true;
2612 } else if (add_ellipsis
) {
2613 m
.add_parameter (new Parameter
.with_ellipsis ());
2616 if (container
== null) {
2617 container
= current_data_type
;
2618 if (container
== null) {
2619 container
= current_namespace
;
2622 if (symbol
!= get_cname (m
, container
)) {
2623 m
.set_attribute_string ("CCode", "cname", symbol
);
2629 private bool param_is_exception (IdlNodeParam param
) {
2630 if (!param
.type
.is_error
) {
2633 var s
= param
.type
.unparsed
.chomp ();
2634 if (s
.has_suffix ("**")) {
2640 private Method?
parse_function (IdlNodeFunction f
, bool is_interface
= false) {
2641 weak IdlNode node
= (IdlNode
) f
;
2647 return create_method (node
.name
, f
.symbol
, f
.result
, f
.parameters
, f
.is_constructor
, is_interface
);
2650 private Method
parse_virtual (IdlNodeVFunc v
, IdlNodeFunction? func
, bool is_interface
= false) {
2651 weak IdlNode node
= (IdlNode
) v
;
2652 string symbol
= "%s%s".printf (get_lower_case_cprefix (current_data_type
), node
.name
);
2655 symbol
= func
.symbol
;
2658 Method m
= create_method (node
.name
, symbol
, v
.result
, func
!= null ? func
.parameters
: v
.parameters
, false, is_interface
);
2660 m
.binding
= MemberBinding
.INSTANCE
;
2661 m
.is_virtual
= !(m
.is_abstract
|| is_interface
);
2662 m
.is_abstract
= m
.is_abstract
|| is_interface
;
2664 var attributes
= get_attributes (symbol
);
2665 if (attributes
!= null) {
2666 foreach (string attr
in attributes
) {
2667 var nv
= attr
.split ("=", 2);
2668 if (nv
[0] == "virtual") {
2669 if (eval (nv
[1]) == "0") {
2670 m
.is_virtual
= false;
2671 m
.is_abstract
= false;
2673 m
.is_virtual
= true;
2674 m
.is_abstract
= false;
2681 m
.set_attribute ("NoWrapper", true);
2688 private string fix_prop_name (string name
) {
2689 var str
= new
StringBuilder ();
2693 while (i
.length
> 0) {
2694 unichar c
= i
.get_char ();
2698 str
.append_unichar (c
);
2707 private Property?
parse_property (IdlNodeProperty prop_node
) {
2708 weak IdlNode node
= (IdlNode
) prop_node
;
2710 if (prop_node
.deprecated
) {
2714 if (!prop_node
.readable
&& !prop_node
.writable
) {
2715 // buggy GIDL definition
2716 prop_node
.readable
= true;
2717 prop_node
.writable
= true;
2720 var prop
= new
Property (fix_prop_name (node
.name
), parse_type (prop_node
.type
), null, null, current_source_reference
);
2721 prop
.access
= SymbolAccessibility
.PUBLIC
;
2722 prop
.interface_only
= true;
2724 if (prop_node
.type
.is_interface
&& prop_node
.type
.interface == "GStrv") {
2725 prop
.set_attribute_bool ("CCode", "array_length", false);
2726 prop
.set_attribute_bool ("CCode", "array_null_terminated", true);
2729 if (prop_node
.readable
) {
2730 prop
.get_accessor
= new
PropertyAccessor (true, false, false, prop
.property_type
.copy (), null, null);
2732 if (prop_node
.writable
) {
2733 if (prop_node
.construct_only
) {
2734 prop
.set_accessor
= new
PropertyAccessor (false, false, true, prop
.property_type
.copy (), null, null);
2736 prop
.set_accessor
= new
PropertyAccessor (false, true, prop_node
.@
construct, prop
.property_type
.copy (), null, null);
2740 var attributes
= get_attributes ("%s:%s".printf (get_cname (current_data_type
), node
.name
));
2741 if (attributes
!= null) {
2742 foreach (string attr
in attributes
) {
2743 var nv
= attr
.split ("=", 2);
2744 if (nv
[0] == "hidden") {
2745 if (eval (nv
[1]) == "1") {
2748 } else if (nv
[0] == "type_arguments") {
2749 parse_type_arguments_from_string (prop
.property_type
, eval (nv
[1]));
2750 } else if (nv
[0] == "deprecated") {
2751 if (eval (nv
[1]) == "1") {
2752 prop
.set_attribute_bool ("Version", "deprecated", true);
2754 } else if (nv
[0] == "replacement") {
2755 prop
.set_attribute_string ("Version", "replacement", eval (nv
[1]));
2756 } else if (nv
[0] == "deprecated_since") {
2757 prop
.set_attribute_string ("Version", "deprecated_since", eval (nv
[1]));
2758 } else if (nv
[0] == "accessor_method") {
2759 if (eval (nv
[1]) == "0") {
2760 prop
.set_attribute ("NoAccessorMethod", true);
2762 } else if (nv
[0] == "owned_get") {
2763 if (eval (nv
[1]) == "1") {
2764 prop
.get_accessor
.value_type
.value_owned
= true;
2766 } else if (nv
[0] == "type_name") {
2767 prop
.property_type
= parse_type_from_string (eval (nv
[1]), false);
2768 } else if (nv
[0] == "experimental") {
2769 if (eval (nv
[1]) == "1") {
2770 prop
.set_attribute_bool ("Version", "experimental", true);
2772 } else if (nv
[0] == "nullable") {
2773 if (eval (nv
[1]) == "1" && !(prop
.property_type is VoidType
)) {
2774 prop
.property_type
.nullable
= true;
2776 } else if (nv
[0] == "abstract") {
2777 if (eval (nv
[1]) == "1") {
2778 prop
.is_abstract
= true;
2784 if (current_type_symbol_set
!= null) {
2785 current_type_symbol_set
.add (prop
.name
);
2791 private Constant?
parse_constant (IdlNodeConstant const_node
) {
2792 weak IdlNode node
= (IdlNode
) const_node
;
2794 var type
= parse_type (const_node
.type
);
2799 var c
= new
Constant (node
.name
, type
, null, current_source_reference
);
2802 string[] attributes
= get_attributes (node
.name
);
2803 if (attributes
!= null) {
2804 foreach (string attr
in attributes
) {
2805 var nv
= attr
.split ("=", 2);
2806 if (nv
[0] == "cheader_filename") {
2807 c
.set_attribute_string ("CCode", "cheader_filename", eval (nv
[1]));
2808 } else if (nv
[0] == "deprecated") {
2809 if (eval (nv
[1]) == "1") {
2810 c
.set_attribute_bool ("Version", "deprecated", true);
2812 } else if (nv
[0] == "replacement") {
2813 c
.set_attribute_string ("Version", "replacement", eval (nv
[1]));
2814 } else if (nv
[0] == "deprecated_since") {
2815 c
.set_attribute_string ("Version", "deprecated_since", eval (nv
[1]));
2816 } else if (nv
[0] == "hidden") {
2817 if (eval (nv
[1]) == "1") {
2820 } else if (nv
[0] == "experimental") {
2821 if (eval (nv
[1]) == "1") {
2822 c
.set_attribute_bool ("Version", "experimental", true);
2828 c
.access
= SymbolAccessibility
.PUBLIC
;
2833 private Field?
parse_field (IdlNodeField field_node
) {
2834 weak IdlNode node
= (IdlNode
) field_node
;
2835 bool unhidden
= false;
2837 var type
= parse_type (field_node
.type
);
2842 string cheader_filename
= null;
2843 string ctype
= null;
2844 string array_length_cname
= null;
2845 string array_length_type
= null;
2846 bool array_null_terminated
= false;
2847 bool deprecated
= false;
2848 string deprecated_since
= null;
2849 string replacement
= null;
2850 bool experimental
= false;
2851 bool no_delegate_target
= false;
2853 var attributes
= get_attributes ("%s.%s".printf (get_cname (current_data_type
), node
.name
));
2854 if (attributes
!= null) {
2855 foreach (string attr
in attributes
) {
2856 var nv
= attr
.split ("=", 2);
2857 if (nv
[0] == "hidden") {
2858 if (eval (nv
[1]) == "1") {
2863 } else if (nv
[0] == "is_array") {
2864 if (eval (nv
[1]) == "1") {
2865 type
.value_owned
= true;
2866 type
= new
ArrayType (type
, 1, type
.source_reference
);
2868 } else if (nv
[0] == "weak") {
2869 if (eval (nv
[1]) == "0") {
2870 type
.value_owned
= true;
2872 } else if (nv
[0] == "value_owned") {
2873 if (eval (nv
[1]) == "0") {
2874 type
.value_owned
= false;
2875 } else if (eval (nv
[1]) == "1") {
2876 type
.value_owned
= true;
2878 } else if (nv
[0] == "type_name") {
2879 type
= parse_type_from_string (eval (nv
[1]), true);
2880 } else if (nv
[0] == "type_arguments") {
2881 parse_type_arguments_from_string (type
, eval (nv
[1]));
2882 } else if (nv
[0] == "deprecated") {
2883 if (eval (nv
[1]) == "1") {
2886 } else if (nv
[0] == "replacement") {
2887 replacement
= eval (nv
[1]);
2888 } else if (nv
[0] == "deprecated_since") {
2889 deprecated_since
= eval (nv
[1]);
2890 } else if (nv
[0] == "cheader_filename") {
2891 cheader_filename
= eval (nv
[1]);
2892 } else if (nv
[0] == "ctype") {
2893 ctype
= eval (nv
[1]);
2894 } else if (nv
[0] == "array_null_terminated") {
2895 if (eval (nv
[1]) == "1") {
2896 array_null_terminated
= true;
2898 } else if (nv
[0] == "array_length_cname") {
2899 array_length_cname
= eval (nv
[1]);
2900 } else if (nv
[0] == "array_length_type") {
2901 array_length_type
= eval (nv
[1]);
2902 } else if (nv
[0] == "no_delegate_target") {
2903 if (eval (nv
[1]) == "1") {
2904 no_delegate_target
= true;
2906 } else if (nv
[0] == "experimental") {
2907 if (eval (nv
[1]) == "1") {
2908 experimental
= true;
2914 if (node
.name
.has_prefix("_") && !unhidden
) {
2918 if (current_type_symbol_set
!= null) {
2919 current_type_symbol_set
.add (node
.name
);
2922 string field_name
= node
.name
;
2923 if (field_name
== "string") {
2924 // avoid conflict with string type
2928 var field
= new
Field (field_name
, type
, null, current_source_reference
);
2929 field
.access
= SymbolAccessibility
.PUBLIC
;
2931 if (field_name
!= node
.name
) {
2932 field
.set_attribute_string ("CCode", "cname", node
.name
);
2936 field
.set_attribute_bool ("Version", "deprecated", true);
2938 if (deprecated_since
!= null) {
2939 field
.set_attribute_string ("Version", "deprecated_since", deprecated_since
);
2942 if (replacement
!= null) {
2943 field
.set_attribute_string ("Version", "replacement", replacement
);
2948 field
.set_attribute_bool ("Version", "experimental", true);
2951 if (ctype
!= null) {
2952 field
.set_attribute_string ("CCode", "type", ctype
);
2955 if (cheader_filename
!= null) {
2956 field
.set_attribute_string ("CCode", "cheader_filename", cheader_filename
);
2959 if (array_null_terminated
) {
2960 field
.set_attribute_bool ("CCode", "array_null_terminated", true);
2963 if (array_length_cname
!= null || array_length_type
!= null) {
2964 if (array_length_cname
!= null) {
2965 field
.set_attribute_string ("CCode", "array_length_cname", array_length_cname
);
2967 if (array_length_type
!= null) {
2968 field
.set_attribute_string ("CCode", "array_length_type", array_length_type
);
2970 } else if (field
.variable_type is ArrayType
) {
2971 field
.set_attribute_bool ("CCode", "array_length", false);
2974 if (no_delegate_target
) {
2975 field
.set_attribute_bool ("CCode", "delegate_target", false);
2981 private string[]?
get_attributes (string codenode
) {
2982 var attributes
= codenode_attributes_map
.get (codenode
);
2984 if (attributes
== null) {
2985 var dot_required
= (-1 != codenode
.index_of_char ('.'));
2986 var colon_required
= (-1 != codenode
.index_of_char (':'));
2988 var pattern_specs
= codenode_attributes_patterns
.get_keys ();
2989 foreach (PatternSpec
* pattern
in pattern_specs
) {
2990 var pspec
= codenode_attributes_patterns
[pattern
];
2992 if ((dot_required
&& -1 == pspec
.index_of_char ('.')) ||
2993 (colon_required
&& -1 == pspec
.index_of_char (':'))) {
2997 if (pattern
->match_string (codenode
)) {
2998 return get_attributes (pspec
);
3003 if (attributes
== null) {
3007 GLib
.SList
<string> attr_list
= new GLib
.SList
<string> ();
3008 var attr
= new GLib
.StringBuilder
.sized (attributes
.length
);
3009 var attributes_len
= attributes
.length
;
3010 unowned
string remaining
= attributes
;
3011 bool quoted
= false, escaped
= false;
3012 for (int b
= 0 ; b
< attributes_len
; b
++) {
3013 unichar c
= remaining
.get_char ();
3017 attr
.append_unichar (c
);
3020 attr
.append_unichar (c
);
3022 } else if (c
== '\\') {
3024 } else if (!quoted
&& (c
== ' ')) {
3025 attr_list
.prepend (attr
.str
);
3028 attr
.append_unichar (c
);
3032 remaining
= (string) ((char*) remaining
+ remaining
.index_of_nth_char (1));
3036 attr_list
.prepend (attr
.str
);
3039 var attrs
= new
string[attr_list
.length ()];
3040 unowned GLib
.SList
<string>? attr_i
= attr_list
;
3041 for (int a
= 0 ; a
< attrs
.length
; a
++, attr_i
= attr_i
.next
) {
3042 attrs
[(attrs
.length
- 1) - a
] = attr_i
.data
;
3048 private string eval (string s
) {
3049 return ((s
.length
>= 2) && s
.has_prefix ("\"") && s
.has_suffix ("\"")) ? s
.substring (1, s
.length
- 2) : s
;
3052 private Signal?
parse_signal (IdlNodeSignal sig_node
) {
3053 weak IdlNode node
= (IdlNode
) sig_node
;
3055 if (sig_node
.deprecated
|| sig_node
.result
== null) {
3059 var sig
= new
Signal (fix_prop_name (node
.name
), parse_param (sig_node
.result
), current_source_reference
);
3060 sig
.access
= SymbolAccessibility
.PUBLIC
;
3062 var attributes
= get_attributes ("%s::%s".printf (get_cname (current_data_type
), sig
.name
));
3063 if (attributes
!= null) {
3064 string ns_name
= null;
3065 foreach (string attr
in attributes
) {
3066 var nv
= attr
.split ("=", 2);
3067 if (nv
[0] == "name") {
3068 sig
.set_attribute_string ("CCode", "cname", sig
.name
.replace ("_", "-"));
3069 sig
.name
= eval (nv
[1]);
3070 } else if (nv
[0] == "has_emitter" && eval (nv
[1]) == "1") {
3071 sig
.set_attribute ("HasEmitter", true);
3072 } else if (nv
[0] == "hidden") {
3073 if (eval (nv
[1]) == "1") {
3076 } else if (nv
[0] == "deprecated") {
3077 if (eval (nv
[1]) == "1") {
3078 sig
.set_attribute_bool ("Version", "deprecated", true);
3080 } else if (nv
[0] == "replacement") {
3081 sig
.set_attribute_string ("Version", "replacement", eval (nv
[1]));
3082 } else if (nv
[0] == "deprecated_since") {
3083 sig
.set_attribute_string ("Version", "deprecated_since", eval (nv
[1]));
3084 } else if (nv
[0] == "transfer_ownership") {
3085 if (eval (nv
[1]) == "1") {
3086 sig
.return_type
.value_owned
= true;
3088 } else if (nv
[0] == "namespace_name") {
3089 ns_name
= eval (nv
[1]);
3090 } else if (nv
[0] == "type_name") {
3091 sig
.return_type
= parse_type_from_string (eval (nv
[1]), false);
3092 } else if (nv
[0] == "type_arguments") {
3093 parse_type_arguments_from_string (sig
.return_type
, eval (nv
[1]));
3094 } else if (nv
[0] == "experimental") {
3095 if (eval (nv
[1]) == "1") {
3096 sig
.set_attribute_bool ("Version", "experimental", true);
3100 if (ns_name
!= null) {
3101 ((UnresolvedType
) sig
.return_type
).unresolved_symbol
.inner
= new
UnresolvedSymbol (null, ns_name
);
3105 sig
.is_virtual
= true;
3109 foreach (weak IdlNodeParam param
in sig_node
.parameters
) {
3111 // ignore implicit first signal parameter (sender)
3116 weak IdlNode param_node
= (IdlNode
) param
;
3118 ParameterDirection direction
;
3119 var param_type
= parse_param (param
, out direction
);
3120 var p
= new
Parameter (param_node
.name
, param_type
);
3121 p
.direction
= direction
;
3123 bool hide_param
= false;
3124 bool show_param
= false;
3125 attributes
= get_attributes ("%s::%s.%s".printf (get_cname (current_data_type
), sig
.name
, param_node
.name
));
3126 if (attributes
!= null) {
3127 string ns_name
= null;
3128 foreach (string attr
in attributes
) {
3129 var nv
= attr
.split ("=", 2);
3130 if (nv
[0] == "hidden") {
3131 if (eval (nv
[1]) == "1") {
3133 } else if (eval (nv
[1]) == "0") {
3136 } else if (nv
[0] == "is_array") {
3137 if (eval (nv
[1]) == "1") {
3138 param_type
.value_owned
= true;
3139 param_type
= new
ArrayType (param_type
, 1, param_type
.source_reference
);
3140 p
.variable_type
= param_type
;
3141 p
.direction
= ParameterDirection
.IN
;
3143 } else if (nv
[0] == "no_array_length") {
3144 if (eval (nv
[1]) == "1") {
3145 p
.set_attribute_bool ("CCode", "array_length", false);
3147 } else if (nv
[0] == "array_length_type") {
3148 p
.set_attribute_string ("CCode", "array_length_type", nv
[1]);
3149 } else if (nv
[0] == "array_null_terminated") {
3150 if (eval (nv
[1]) == "1") {
3151 p
.set_attribute_bool ("CCode", "array_length", false);
3152 p
.set_attribute_bool ("CCode", "array_null_terminated", true);
3154 } else if (nv
[0] == "is_out") {
3155 if (eval (nv
[1]) == "1") {
3156 p
.direction
= ParameterDirection
.OUT
;
3158 } else if (nv
[0] == "is_ref") {
3159 if (eval (nv
[1]) == "1") {
3160 p
.direction
= ParameterDirection
.REF
;
3162 } else if (nv
[0] == "nullable") {
3163 if (eval (nv
[1]) == "1" && !(param_type is VoidType
)) {
3164 param_type
.nullable
= true;
3166 } else if (nv
[0] == "transfer_ownership") {
3167 if (eval (nv
[1]) == "1") {
3168 param_type
.value_owned
= true;
3170 } else if (nv
[0] == "type_name") {
3171 p
.variable_type
= param_type
= parse_type_from_string (eval (nv
[1]), false);
3172 } else if (nv
[0] == "type_arguments") {
3173 parse_type_arguments_from_string (p
.variable_type
, eval (nv
[1]));
3174 } else if (nv
[0] == "namespace_name") {
3175 ns_name
= eval (nv
[1]);
3178 if (ns_name
!= null) {
3179 ((UnresolvedType
) param_type
).unresolved_symbol
.inner
= new
UnresolvedSymbol (null, ns_name
);
3183 if (show_param
|| !hide_param
) {
3184 sig
.add_parameter (p
);