3 * Copyright (C) 2008-2010 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Jürg Billeter <j@bitron.ch>
26 * Code visitor parsing all Vala source files.
30 * 2) Parse GIR with metadata, track unresolved GIR symbols, create symbol mappings
31 * 3) Reconciliate the tree by mapping tracked symbols
33 * 5) Process callbacks/virtual
35 * 7) Autoreparent static methods
37 * Best hacking practices:
38 * - Keep GIR parsing bloat-free, it must contain the logic
39 * - Prefer being clean / short over performance
40 * - Try to make things common as much as possible
41 * - Prefer replace/merge after parse rather than a bunch of if-then-else and hardcoding
42 * - Prefer postprocessing over hardcoding the parser
44 public class Vala
.GirParser
: CodeVisitor
{
74 public static ArgumentType?
from_string (string name
) {
75 var enum_class
= (EnumClass
) typeof(ArgumentType
).class_ref ();
76 var nick
= name
.replace ("_", "-");
77 unowned GLib
.EnumValue? enum_value
= enum_class
.get_value_by_nick (nick
);
78 if (enum_value
!= null) {
79 ArgumentType value
= (ArgumentType
) enum_value
.value
;
87 public Expression expression
;
88 public SourceReference source_reference
;
90 public bool used
= false;
92 public Argument (Expression expression
, SourceReference? source_reference
= null) {
93 this
.expression
= expression
;
94 this
.source_reference
= source_reference
;
98 class MetadataSet
: Metadata
{
99 public MetadataSet (MetadataType type
) {
103 public void add_sibling (Metadata metadata
) {
104 foreach (var child
in metadata
.children
) {
107 // merge arguments and take precedence
108 foreach (var key
in metadata
.args
.get_keys ()) {
109 args
[key
] = metadata
.args
[key
];
115 private static Metadata _empty
= null;
116 public static Metadata empty
{
118 if (_empty
== null) {
119 _empty
= new
Metadata ("");
125 public string pattern
;
126 public PatternSpec pattern_spec
;
127 public MetadataType type
;
128 public SourceReference source_reference
;
130 public bool used
= false;
131 public Vala
.Map
<ArgumentType
,Argument
> args
= new HashMap
<ArgumentType
,Argument
> ();
132 public ArrayList
<Metadata
> children
= new ArrayList
<Metadata
> ();
134 public Metadata (string pattern
, MetadataType type
= MetadataType
.GENERIC
, SourceReference? source_reference
= null) {
135 this
.pattern
= pattern
;
136 this
.pattern_spec
= new
PatternSpec (pattern
);
138 this
.source_reference
= source_reference
;
141 public void add_child (Metadata metadata
) {
142 children
.add (metadata
);
145 public Metadata?
get_child (string pattern
, MetadataType type
= MetadataType
.GENERIC
) {
146 foreach (var metadata
in children
) {
147 if (metadata
.type
== type
&& metadata
.pattern
== pattern
) {
154 public Metadata
match_child (string name
, MetadataType type
= MetadataType
.GENERIC
) {
155 var result
= Metadata
.empty
;
156 foreach (var metadata
in children
) {
157 if (metadata
.type
== type
&& metadata
.pattern_spec
.match_string (name
)) {
158 metadata
.used
= true;
159 if (result
== Metadata
.empty
) {
163 var ms
= result as MetadataSet
;
166 ms
= new
MetadataSet (type
);
167 ms
.add_sibling (result
);
169 ms
.add_sibling (metadata
);
177 public void add_argument (ArgumentType key
, Argument value
) {
178 args
.set (key
, value
);
181 public bool has_argument (ArgumentType key
) {
182 return args
.contains (key
);
185 public Expression?
get_expression (ArgumentType arg
) {
186 var val
= args
.get (arg
);
189 return val
.expression
;
194 public string?
get_string (ArgumentType arg
) {
195 var lit
= get_expression (arg
) as StringLiteral
;
202 public int get_integer (ArgumentType arg
) {
203 var lit
= get_expression (arg
) as IntegerLiteral
;
205 return int.parse (lit
.value
);
211 public bool get_bool (ArgumentType arg
) {
212 var lit
= get_expression (arg
) as BooleanLiteral
;
219 public SourceReference?
get_source_reference (ArgumentType arg
) {
220 var val
= args
.get (arg
);
222 return val
.source_reference
;
228 class MetadataParser
{
231 * metadata ::= [ rule [ '\n' relativerule ]* ]
232 * rule ::= pattern ' ' [ args ]
233 * relativerule ::= [ access ] rule
234 * pattern ::= identifier [ access identifier ]*
235 * access ::= '.' | ':' | '::'
237 private Metadata tree
= new
Metadata ("");
238 private Scanner scanner
;
239 private SourceLocation begin
;
240 private SourceLocation end
;
241 private SourceLocation old_end
;
242 private TokenType current
;
243 private Metadata parent_metadata
;
245 public MetadataParser () {
249 SourceReference
get_current_src () {
250 return new
SourceReference (scanner
.source_file
, begin
.line
, begin
.column
, end
.line
, end
.column
);
253 SourceReference
get_src (SourceLocation begin
) {
254 return new
SourceReference (scanner
.source_file
, begin
.line
, begin
.column
, end
.line
, end
.column
);
257 public Metadata
parse_metadata (SourceFile metadata_file
) {
258 scanner
= new
Scanner (metadata_file
);
260 while (current
!= TokenType
.EOF
) {
261 if (!parse_rule ()) {
262 return Metadata
.empty
;
270 current
= scanner
.read_token (out begin
, out end
);
275 return old_end
.pos
!= begin
.pos
;
278 bool has_newline () {
279 return old_end
.line
!= begin
.line
;
282 string get_string () {
283 return ((string) begin
.pos
).substring (0, (int) (end
.pos
- begin
.pos
));
286 MetadataType?
parse_metadata_access () {
290 return MetadataType
.GENERIC
;
291 case TokenType
.COLON
:
293 return MetadataType
.PROPERTY
;
294 case TokenType
.DOUBLE_COLON
:
296 return MetadataType
.SIGNAL
;
302 string?
parse_identifier (out SourceReference source_reference
, bool is_glob
) {
303 var begin
= this
.begin
;
304 var builder
= new
StringBuilder ();
306 if (is_glob
&& current
== TokenType
.STAR
) {
307 builder
.append_c ('*');
311 case TokenType
.IDENTIFIER
:
312 case TokenType
.UNOWNED
:
313 case TokenType
.OWNED
:
316 case TokenType
.DEFAULT
:
319 case TokenType
.VIRTUAL
:
320 case TokenType
.ABSTRACT
:
327 builder
.append (str
);
329 source_reference
= get_src (begin
);
331 } while (!has_space ());
333 if (builder
.str
== "") {
335 Report
.error (get_src (begin
), "expected pattern");
337 Report
.error (get_src (begin
), "expected identifier");
344 Metadata?
parse_pattern () {
346 bool is_relative
= false;
347 MetadataType? type
= MetadataType
.GENERIC
;
348 if (current
== TokenType
.IDENTIFIER
|| current
== TokenType
.STAR
) {
350 parent_metadata
= tree
;
353 type
= parse_metadata_access ();
358 Report
.error (get_current_src (), "expected pattern, `.', `:' or `::'");
362 if (parent_metadata
== null) {
363 Report
.error (get_current_src (), "cannot determinate parent metadata");
368 var pattern
= parse_identifier (out src
, true);
369 if (pattern
== null) {
372 metadata
= parent_metadata
.get_child (pattern
, type
);
373 if (metadata
== null) {
374 metadata
= new
Metadata (pattern
, type
, src
);
375 parent_metadata
.add_child (metadata
);
378 while (current
!= TokenType
.EOF
&& !has_space ()) {
379 type
= parse_metadata_access ();
381 Report
.error (get_current_src (), "expected `.', `:' or `::'");
385 pattern
= parse_identifier (out src
, true);
386 if (pattern
== null) {
389 var child
= metadata
.get_child (pattern
, type
);
391 child
= new
Metadata (pattern
, type
, src
);
392 metadata
.add_child (child
);
397 parent_metadata
= metadata
;
403 Expression?
parse_expression () {
404 var src
= get_current_src ();
405 Expression expr
= null;
408 expr
= new
NullLiteral (src
);
411 expr
= new
BooleanLiteral (true, src
);
413 case TokenType
.FALSE
:
414 expr
= new
BooleanLiteral (false, src
);
416 case TokenType
.INTEGER_LITERAL
:
417 expr
= new
IntegerLiteral (get_string (), src
);
419 case TokenType
.REAL_LITERAL
:
420 expr
= new
RealLiteral (get_string (), src
);
422 case TokenType
.STRING_LITERAL
:
423 expr
= new
StringLiteral (get_string (), src
);
425 case TokenType
.IDENTIFIER
:
426 expr
= new
MemberAccess (null, get_string (), src
);
427 while (next () == TokenType
.DOT
) {
428 if (next () != TokenType
.IDENTIFIER
) {
429 Report
.error (get_current_src (), "expected identifier got `%s'".printf (current
.to_string ()));
432 expr
= new
MemberAccess (expr
, get_string (), get_current_src ());
436 Report
.error (src
, "expected literal or symbol got `%s'".printf (current
.to_string ()));
443 bool parse_args (Metadata metadata
) {
444 while (current
!= TokenType
.EOF
&& has_space () && !has_newline ()) {
446 var id
= parse_identifier (out src
, false);
450 var arg_type
= ArgumentType
.from_string (id
);
451 if (arg_type
== null) {
452 Report
.error (src
, "unknown argument");
456 if (current
!= TokenType
.ASSIGN
) {
458 metadata
.add_argument (arg_type
, new
Argument (new
BooleanLiteral (true, src
), src
));
463 Expression expr
= parse_expression ();
467 metadata
.add_argument (arg_type
, new
Argument (expr
, src
));
475 var metadata
= parse_pattern ();
476 if (metadata
== null) {
480 if (current
== TokenType
.EOF
|| old_end
.line
!= end
.line
) {
484 return parse_args (metadata
);
489 public Symbol symbol
;
490 public Metadata metadata
;
491 // additional information from GIR
492 public HashMap
<string,string> girdata
;
497 public DataType base_type
;
498 public Symbol parent_symbol
;
499 public SourceReference source_reference
;
502 static GLib
.Regex type_from_string_regex
;
509 SourceFile current_source_file
;
510 Symbol current_symbol
;
512 string current_gtype_struct_for
;
513 SourceLocation begin
;
515 MarkupTokenType current_token
;
517 string[] cheader_filenames
;
519 ArrayList
<Metadata
> metadata_stack
;
521 ArrayList
<HashMap
<string,string>> girdata_stack
;
522 HashMap
<string,string> girdata
;
524 HashMap
<string,ArrayList
<SymbolInfo
>> current_symbols_info
;
526 HashMap
<UnresolvedSymbol
,Symbol
> unresolved_symbols_map
= new HashMap
<UnresolvedSymbol
,Symbol
> (unresolved_symbol_hash
, unresolved_symbol_equal
);
527 HashMap
<Symbol
,Symbol
> concrete_symbols_map
= new HashMap
<Symbol
,Symbol
> ();
529 ArrayList
<UnresolvedSymbol
> unresolved_gir_symbols
= new ArrayList
<UnresolvedSymbol
> ();
530 HashMap
<UnresolvedSymbol
,ArrayList
<Symbol
>> symbol_reparent_map
= new HashMap
<UnresolvedSymbol
,ArrayList
<Symbol
>> (unresolved_symbol_hash
, unresolved_symbol_equal
);
531 HashMap
<Namespace
,ArrayList
<Method
>> namespace_methods
= new HashMap
<Namespace
,ArrayList
<Method
>> ();
532 ArrayList
<Alias
> aliases
= new ArrayList
<Alias
> ();
533 ArrayList
<Interface
> interfaces
= new ArrayList
<Interface
> ();
535 HashMap
<UnresolvedSymbol
,ArrayList
<Delegate
>> gtype_callbacks
;
538 * Parses all .gir source files in the specified code
539 * context and builds a code tree.
541 * @param context a code context
543 public void parse (CodeContext context
) {
544 this
.context
= context
;
545 glib_ns
= context
.root
.scope
.lookup ("GLib") as Namespace
;
546 context
.accept (this
);
548 resolve_gir_symbols ();
550 postprocess_interfaces ();
551 postprocess_reparenting ();
552 postprocess_aliases ();
553 postprocess_namespace_methods ();
556 public override void visit_source_file (SourceFile source_file
) {
557 // collect gir namespaces
558 foreach (var node
in source_file
.get_nodes ()) {
559 if (node is Namespace
) {
560 var ns
= (Namespace
) node
;
561 var gir_namespace
= source_file
.gir_namespace
;
562 if (gir_namespace
== null) {
563 var a
= ns
.get_attribute ("CCode");
564 if (a
!= null && a
.has_argument ("gir_namespace")) {
565 gir_namespace
= a
.get_string ("gir_namespace");
568 if (gir_namespace
!= null && gir_namespace
!= ns
.name
) {
569 var map_from
= new
UnresolvedSymbol (null, gir_namespace
);
570 set_symbol_mapping (map_from
, ns
);
576 if (source_file
.filename
.has_suffix (".gir")) {
577 parse_file (source_file
);
581 public void parse_file (SourceFile source_file
) {
582 metadata_stack
= new ArrayList
<Metadata
> ();
583 metadata
= Metadata
.empty
;
584 girdata_stack
= new ArrayList
<HashMap
<string,string>> ();
586 // load metadata, first look into metadata directories then in the same directory of the .gir.
587 string? metadata_filename
= context
.get_metadata_path (source_file
.filename
);
588 if (metadata_filename
!= null && FileUtils
.test (metadata_filename
, FileTest
.EXISTS
)) {
589 var metadata_parser
= new
MetadataParser ();
590 var metadata_file
= new
SourceFile (context
, source_file
.file_type
, metadata_filename
);
591 context
.add_source_file (metadata_file
);
592 metadata
= metadata_parser
.parse_metadata (metadata_file
);
595 this
.current_source_file
= source_file
;
596 reader
= new
MarkupReader (source_file
.filename
);
605 report_unused_metadata (metadata
);
608 this
.current_source_file
= null;
612 current_token
= reader
.read_token (out begin
, out end
);
614 // Skip *all* <doc> tags
615 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "doc")
619 void start_element (string name
) {
620 if (current_token
!= MarkupTokenType
.START_ELEMENT
|| reader
.name
!= name
) {
622 Report
.error (get_current_src (), "expected start element of `%s'".printf (name
));
626 void end_element (string name
) {
627 if (current_token
!= MarkupTokenType
.END_ELEMENT
|| reader
.name
!= name
) {
629 Report
.error (get_current_src (), "expected end element of `%s'".printf (name
));
634 SourceReference
get_current_src () {
635 return new
SourceReference (this
.current_source_file
, begin
.line
, begin
.column
, end
.line
, end
.column
);
638 const string GIR_VERSION
= "1.2";
640 void add_symbol_to_container (Symbol container
, Symbol sym
) {
642 if (name
== null && sym is CreationMethod
) {
645 if (container
.scope
.lookup (name
) != null) {
646 // overridden by -custom.vala
650 if (container is Class
) {
651 unowned Class cl
= (Class
) container
;
654 cl
.add_class ((Class
) sym
);
655 } else if (sym is Constant
) {
656 cl
.add_constant ((Constant
) sym
);
657 } else if (sym is Enum
) {
658 cl
.add_enum ((Enum
) sym
);
659 } else if (sym is Field
) {
660 cl
.add_field ((Field
) sym
);
661 } else if (sym is Method
) {
662 cl
.add_method ((Method
) sym
);
663 } else if (sym is Property
) {
664 cl
.add_property ((Property
) sym
);
665 } else if (sym is Signal
) {
666 cl
.add_signal ((Signal
) sym
);
667 } else if (sym is Struct
) {
668 cl
.add_struct ((Struct
) sym
);
670 } else if (container is Enum
) {
671 unowned Enum en
= (Enum
) container
;
673 if (sym is EnumValue
) {
674 en
.add_value ((EnumValue
) sym
);
675 } else if (sym is Constant
) {
676 en
.add_constant ((Constant
) sym
);
677 } else if (sym is Method
) {
678 en
.add_method ((Method
) sym
);
680 } else if (container is Interface
) {
681 unowned Interface iface
= (Interface
) container
;
684 iface
.add_class ((Class
) sym
);
685 } else if (sym is Constant
) {
686 iface
.add_constant ((Constant
) sym
);
687 } else if (sym is Enum
) {
688 iface
.add_enum ((Enum
) sym
);
689 } else if (sym is Field
) {
690 iface
.add_field ((Field
) sym
);
691 } else if (sym is Method
) {
692 iface
.add_method ((Method
) sym
);
693 } else if (sym is Property
) {
694 iface
.add_property ((Property
) sym
);
695 } else if (sym is Signal
) {
696 iface
.add_signal ((Signal
) sym
);
697 } else if (sym is Struct
) {
698 iface
.add_struct ((Struct
) sym
);
700 } else if (container is Namespace
) {
701 unowned Namespace ns
= (Namespace
) container
;
703 if (sym is Namespace
) {
704 ns
.add_namespace ((Namespace
) sym
);
705 } else if (sym is Class
) {
706 ns
.add_class ((Class
) sym
);
707 } else if (sym is Constant
) {
708 ns
.add_constant ((Constant
) sym
);
709 } else if (sym is Delegate
) {
710 ns
.add_delegate ((Delegate
) sym
);
711 } else if (sym is Enum
) {
712 ns
.add_enum ((Enum
) sym
);
713 } else if (sym is ErrorDomain
) {
714 ns
.add_error_domain ((ErrorDomain
) sym
);
715 } else if (sym is Field
) {
716 ns
.add_field ((Field
) sym
);
717 } else if (sym is Interface
) {
718 ns
.add_interface ((Interface
) sym
);
719 } else if (sym is Method
) {
720 ns
.add_method ((Method
) sym
);
721 } else if (sym is Namespace
) {
722 ns
.add_namespace ((Namespace
) sym
);
723 } else if (sym is Struct
) {
724 ns
.add_struct ((Struct
) sym
);
726 } else if (container is Struct
) {
727 unowned Struct st
= (Struct
) container
;
729 if (sym is Constant
) {
730 st
.add_constant ((Constant
) sym
);
731 } else if (sym is Field
) {
732 st
.add_field ((Field
) sym
);
733 } else if (sym is Method
) {
734 st
.add_method ((Method
) sym
);
735 } else if (sym is Property
) {
736 st
.add_property ((Property
) sym
);
739 Report
.error (sym
.source_reference
, "impossible to add to container `%s'".printf (container
.name
));
743 UnresolvedSymbol?
parse_symbol_from_string (string symbol_string
, SourceReference? source_reference
= null) {
744 UnresolvedSymbol? sym
= null;
745 foreach (unowned
string s
in symbol_string
.split (".")) {
746 sym
= new
UnresolvedSymbol (sym
, s
, source_reference
);
749 Report
.error (source_reference
, "a symbol must be specified");
754 UnresolvedSymbol
get_unresolved_symbol (Symbol symbol
) {
755 if (symbol is UnresolvedSymbol
) {
756 return (UnresolvedSymbol
) symbol
;
758 var sym
= new
UnresolvedSymbol (null, symbol
.name
);
760 var cur
= symbol
.parent_node as Symbol
;
761 while (cur
!= null && cur
.name
!= null) {
762 sym
= new
UnresolvedSymbol (sym
, cur
.name
);
763 cur
= cur
.parent_node as Symbol
;
768 void set_symbol_mapping (Symbol map_from
, Symbol map_to
) {
769 // last mapping is the most up-to-date
770 if (map_from is UnresolvedSymbol
) {
771 unresolved_symbols_map
[(UnresolvedSymbol
) map_from
] = map_to
;
773 concrete_symbols_map
[map_from
] = map_to
;
777 void assume_parameter_names (Signal sig
, Symbol sym
) {
778 Iterator
<Parameter
> iter
;
780 iter
= ((Method
) sym
).get_parameters ().iterator ();
782 iter
= ((Delegate
) sym
).get_parameters ().iterator ();
784 foreach (var param
in sig
.get_parameters ()) {
786 // unreachable for valid GIR
789 param
.name
= iter
.get ().name
;
793 SymbolInfo?
add_symbol_info (Symbol symbol
) {
794 var name
= symbol
.name
;
795 if (symbol is CreationMethod
&& name
== null) {
799 var info
= new
SymbolInfo ();
800 info
.symbol
= symbol
;
801 info
.metadata
= metadata
;
802 info
.girdata
= girdata
;
803 var colliding
= current_symbols_info
[name
];
804 if (colliding
== null) {
805 colliding
= new ArrayList
<SymbolInfo
> ();
806 current_symbols_info
[name
] = colliding
;
808 colliding
.add (info
);
812 SymbolInfo?
find_invoker (Method method
) {
813 /* most common use case is invoker has at least the given method prefix
814 and the same parameter names */
815 var prefix
= "%s_".printf (method
.name
);
816 foreach (var name
in current_symbols_info
.get_keys ()) {
817 if (!name
.has_prefix (prefix
)) {
820 var infos
= current_symbols_info
[name
];
821 foreach (var cinfo
in infos
) {
822 Method? invoker
= cinfo
.symbol as Method
;
823 if (invoker
== null || (method
.get_parameters ().size
!= invoker
.get_parameters ().size
)) {
826 var iter
= invoker
.get_parameters ().iterator ();
827 foreach (var param
in method
.get_parameters ()) {
828 assert (iter
.next ());
829 if (param
.name
!= iter
.get ().name
) {
834 if (invoker
!= null) {
843 void merge (SymbolInfo info
, ArrayList
<SymbolInfo
> colliding
, ArrayList
<SymbolInfo
> merged
) {
844 if (info
.symbol is Struct
) {
845 var gtype_struct_for
= info
.girdata
["glib:is-gtype-struct-for"];
846 if (gtype_struct_for
!= null && current_symbols_info
.contains (gtype_struct_for
)) {
847 var iface
= current_symbols_info
.get (gtype_struct_for
).get (0).symbol as Interface
;
849 // set the interface struct name
850 iface
.set_type_cname (((Struct
) info
.symbol
).get_cname ());
854 } else if (info
.symbol is Property
) {
855 foreach (var cinfo
in colliding
) {
856 var sym
= cinfo
.symbol
;
857 if (sym is Signal
|| sym is Field
) {
858 // properties take precedence
860 } else if (sym is Method
) {
861 // assume method is getter
865 var getter_name
= "get_%s".printf (info
.symbol
.name
);
866 var setter_name
= "set_%s".printf (info
.symbol
.name
);
867 if (current_symbols_info
.contains (getter_name
) || current_symbols_info
.contains (setter_name
)) {
868 ((Property
) info
.symbol
).no_accessor_method
= false;
870 } else if (info
.symbol is Signal
) {
871 var sig
= (Signal
) info
.symbol
;
872 foreach (var cinfo
in colliding
) {
873 var sym
= cinfo
.symbol
;
875 var method
= (Method
) sym
;
876 if (method
.is_virtual
) {
877 sig
.is_virtual
= true;
879 sig
.has_emitter
= true;
881 assume_parameter_names (sig
, method
);
883 } else if (sym is Field
) {
887 } else if (info
.symbol is Method
&& !(info
.symbol is CreationMethod
)) {
888 var method
= (Method
) info
.symbol
;
889 foreach (var cinfo
in colliding
) {
890 var sym
= cinfo
.symbol
;
891 if (sym
!= method
&& method
.is_virtual
&& sym is Method
) {
892 bool different_invoker
= false;
893 foreach (var attr
in method
.attributes
) {
894 if (attr
.name
== "NoWrapper") {
895 /* no invoker but this method has the same name,
896 most probably the invoker has a different name
897 and g-ir-scanner missed it */
898 var invoker
= find_invoker (method
);
899 if (invoker
!= null) {
900 method
.vfunc_name
= method
.name
;
901 method
.name
= invoker
.symbol
.name
;
902 method
.attributes
.remove (attr
);
903 merged
.add (invoker
);
904 different_invoker
= true;
909 if (!different_invoker
) {
914 } else if (info
.symbol is Field
) {
915 foreach (var cinfo
in colliding
) {
916 var sym
= cinfo
.symbol
;
918 // assume method is getter
923 var field
= (Field
) info
.symbol
;
924 if (field
.variable_type is ArrayType
) {
925 SymbolInfo array_length
= null;
926 if (current_symbols_info
.contains ("n_%s".printf (field
.name
))) {
927 array_length
= current_symbols_info
.get ("n_%s".printf (field
.name
)).get (0);
928 } else if (current_symbols_info
.contains ("%s_length".printf (field
.name
))) {
929 array_length
= current_symbols_info
.get ("%s_length".printf (field
.name
)).get (0);
931 if (array_length
!= null) {
933 field
.set_array_length_cname (array_length
.symbol
.name
);
934 field
.no_array_length
= false;
935 merged
.add (array_length
);
941 void postprocess_symbol (Symbol symbol
, Metadata metadata
) {
943 symbol
.replacement
= metadata
.get_string (ArgumentType
.REPLACEMENT
);
944 symbol
.deprecated_since
= element_get_string ("deprecated-version", ArgumentType
.DEPRECATED_SINCE
);
945 symbol
.deprecated
= metadata
.get_bool (ArgumentType
.DEPRECATED
) || symbol
.replacement
!= null || symbol
.deprecated_since
!= null;
947 // mark to be reparented
948 if (metadata
.has_argument (ArgumentType
.PARENT
)) {
949 var target_symbol
= parse_symbol_from_string (metadata
.get_string (ArgumentType
.PARENT
), metadata
.get_source_reference (ArgumentType
.PARENT
));
950 var reparent_list
= symbol_reparent_map
[target_symbol
];
951 if (reparent_list
== null) {
952 reparent_list
= new ArrayList
<Symbol
>();
953 symbol_reparent_map
[target_symbol
] = reparent_list
;
955 reparent_list
.add (symbol
);
957 // if referenceable, map unresolved references to point to the new place
958 if (symbol is Namespace
|| symbol is TypeSymbol
) {
959 set_symbol_mapping (symbol
, new
UnresolvedSymbol (target_symbol
, symbol
.name
));
964 void merge_add_process (Symbol container
) {
965 var merged
= new ArrayList
<SymbolInfo
> ();
966 foreach (var name
in current_symbols_info
.get_keys ()) {
967 var colliding
= current_symbols_info
[name
];
968 foreach (var info
in colliding
) {
969 merge (info
, colliding
, merged
);
973 foreach (var infos
in current_symbols_info
.get_values ()) {
974 foreach (var info
in infos
) {
975 if (merged
.contains (info
) || info
.metadata
.get_bool (ArgumentType
.HIDDEN
)) {
978 if (!(current_symbol is Namespace
&& info
.symbol is Method
) && !info
.metadata
.has_argument (ArgumentType
.PARENT
)) {
979 add_symbol_to_container (container
, info
.symbol
);
981 postprocess_symbol (info
.symbol
, info
.metadata
);
986 Metadata
get_current_metadata () {
987 var name
= reader
.name
;
988 var child_name
= reader
.get_attribute ("name");
989 if (child_name
== null) {
990 return Metadata
.empty
;
993 var type
= MetadataType
.GENERIC
;
994 if (name
== "glib:signal") {
995 child_name
= child_name
.replace ("-", "_");
996 type
= MetadataType
.SIGNAL
;
997 } else if (name
== "property") {
998 type
= MetadataType
.PROPERTY
;
1001 return metadata
.match_child (child_name
, type
);
1004 bool push_metadata () {
1006 if (reader
.get_attribute ("introspectable") == "0") {
1009 var new_metadata
= get_current_metadata ();
1010 if (new_metadata
.get_bool (ArgumentType
.SKIP
)) {
1014 metadata_stack
.add (metadata
);
1015 metadata
= new_metadata
;
1016 girdata_stack
.add (girdata
);
1017 girdata
= new HashMap
<string,string> (str_hash
, str_equal
);
1022 void pop_metadata () {
1023 metadata
= metadata_stack
[metadata_stack
.size
- 1];
1024 metadata_stack
.remove_at (metadata_stack
.size
- 1);
1025 girdata
= girdata_stack
[girdata_stack
.size
- 1];
1026 girdata_stack
.remove_at (girdata_stack
.size
- 1);
1029 bool parse_type_arguments_from_string (DataType parent_type
, string type_arguments
, SourceReference? source_reference
= null) {
1030 int type_arguments_length
= (int) type_arguments
.length
;
1031 GLib
.StringBuilder current
= new GLib
.StringBuilder
.sized (type_arguments_length
);
1034 for (var c
= 0 ; c
< type_arguments_length
; c
++) {
1035 if (type_arguments
[c
] == '<' || type_arguments
[c
] == '[') {
1037 current
.append_unichar (type_arguments
[c
]);
1038 } else if (type_arguments
[c
] == '>' || type_arguments
[c
] == ']') {
1040 current
.append_unichar (type_arguments
[c
]);
1041 } else if (type_arguments
[c
] == ',') {
1043 var dt
= parse_type_from_string (current
.str
, true, source_reference
);
1047 parent_type
.add_type_argument (dt
);
1048 current
.truncate ();
1050 current
.append_unichar (type_arguments
[c
]);
1053 current
.append_unichar (type_arguments
[c
]);
1057 var dt
= parse_type_from_string (current
.str
, true, source_reference
);
1061 parent_type
.add_type_argument (dt
);
1066 DataType?
parse_type_from_string (string type_string
, bool owned_by_default
, SourceReference? source_reference
= null) {
1067 if (type_from_string_regex
== null) {
1069 type_from_string_regex
= new GLib
.Regex ("^(?:(owned|unowned|weak) +)?([0-9a-zA-Z_\\.]+)(?:<(.+)>)?(\\*+)?(\\[,*\\])?(\\?)?$", GLib
.RegexCompileFlags
.ANCHORED
| GLib
.RegexCompileFlags
.DOLLAR_ENDONLY
| GLib
.RegexCompileFlags
.OPTIMIZE
);
1070 } catch (GLib
.RegexError e
) {
1071 GLib
.error ("Unable to compile regex: %s", e
.message
);
1075 GLib
.MatchInfo match
;
1076 if (!type_from_string_regex
.match (type_string
, 0, out match
)) {
1077 Report
.error (source_reference
, "unable to parse type");
1081 DataType? type
= null;
1083 var ownership_data
= match
.fetch (1);
1084 var type_name
= match
.fetch (2);
1085 var type_arguments_data
= match
.fetch (3);
1086 var pointers_data
= match
.fetch (4);
1087 var array_data
= match
.fetch (5);
1088 var nullable_data
= match
.fetch (6);
1090 var nullable
= nullable_data
!= null && nullable_data
.length
> 0;
1092 if (ownership_data
== null && type_name
== "void") {
1093 if (array_data
== null && !nullable
) {
1094 type
= new
VoidType (source_reference
);
1095 if (pointers_data
!= null) {
1096 for (int i
=0; i
< pointers_data
.length
; i
++) {
1097 type
= new
PointerType (type
);
1102 Report
.error (source_reference
, "invalid void type");
1107 bool value_owned
= owned_by_default
;
1109 if (ownership_data
== "owned") {
1110 if (owned_by_default
) {
1111 Report
.error (source_reference
, "unexpected `owned' keyword");
1115 } else if (ownership_data
== "unowned") {
1116 if (owned_by_default
) {
1119 Report
.error (source_reference
, "unexpected `unowned' keyword");
1124 var sym
= parse_symbol_from_string (type_name
, source_reference
);
1128 type
= new UnresolvedType
.from_symbol (sym
, source_reference
);
1130 if (type_arguments_data
!= null && type_arguments_data
.length
> 0) {
1131 if (!parse_type_arguments_from_string (type
, type_arguments_data
, source_reference
)) {
1136 if (pointers_data
!= null) {
1137 for (int i
=0; i
< pointers_data
.length
; i
++) {
1138 type
= new
PointerType (type
);
1142 if (array_data
!= null) {
1143 type
= new
ArrayType (type
, (int) array_data
.length
- 1, source_reference
);
1146 type
.nullable
= nullable
;
1147 type
.value_owned
= value_owned
;
1151 string?
element_get_string (string attribute_name
, ArgumentType arg_type
) {
1152 var str
= metadata
.get_string (arg_type
);
1154 str
= reader
.get_attribute (attribute_name
);
1160 * The changed is a faster way to check whether the type has changed and it may affect the C declaration.
1161 * If type arguments change, the C declaration is not affected.
1163 DataType?
element_get_type (DataType orig_type
, bool owned_by_default
, out bool changed
= null) {
1165 var type
= orig_type
;
1167 if (metadata
.has_argument (ArgumentType
.TYPE
)) {
1168 var new_type
= parse_type_from_string (metadata
.get_string (ArgumentType
.TYPE
), owned_by_default
, metadata
.get_source_reference (ArgumentType
.TYPE
));
1173 if (type is VoidType
) {
1177 if (metadata
.has_argument (ArgumentType
.TYPE_ARGUMENTS
)) {
1178 type
.remove_all_type_arguments ();
1179 parse_type_arguments_from_string (type
, metadata
.get_string (ArgumentType
.TYPE_ARGUMENTS
), metadata
.get_source_reference (ArgumentType
.TYPE_ARGUMENTS
));
1182 if (metadata
.get_bool (ArgumentType
.ARRAY
)) {
1183 type
= new
ArrayType (type
, 1, type
.source_reference
);
1187 if (owned_by_default
) {
1188 if (metadata
.has_argument (ArgumentType
.UNOWNED
)) {
1189 type
.value_owned
= !metadata
.get_bool (ArgumentType
.UNOWNED
);
1192 if (metadata
.has_argument (ArgumentType
.OWNED
)) {
1193 type
.value_owned
= metadata
.get_bool (ArgumentType
.OWNED
);
1196 if (metadata
.has_argument (ArgumentType
.NULLABLE
)) {
1197 type
.nullable
= metadata
.get_bool (ArgumentType
.NULLABLE
);
1203 string?
element_get_name (bool remap
= false) {
1204 var name
= reader
.get_attribute ("name");
1205 var orig_name
= name
;
1206 var pattern
= metadata
.get_string (ArgumentType
.NAME
);
1207 if (pattern
!= null) {
1209 var regex
= new
Regex (pattern
, RegexCompileFlags
.ANCHORED
, RegexMatchFlags
.ANCHORED
);
1210 GLib
.MatchInfo match
;
1211 if (!regex
.match (name
, 0, out match
)) {
1214 var matched
= match
.fetch (1);
1215 if (matched
!= null && matched
.length
> 0) {
1225 if (name
!= null && name
.has_suffix ("Enum")) {
1226 name
= name
.substring (0, name
.length
- "Enum".length
);
1229 if (name
!= orig_name
&& remap
) {
1230 set_symbol_mapping (parse_symbol_from_string (orig_name
), parse_symbol_from_string (name
));
1236 void parse_repository () {
1237 start_element ("repository");
1238 if (reader
.get_attribute ("version") != GIR_VERSION
) {
1239 Report
.error (get_current_src (), "unsupported GIR version %s (supported: %s)".printf (reader
.get_attribute ("version"), GIR_VERSION
));
1243 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1244 if (reader
.name
== "namespace") {
1245 var ns
= parse_namespace ();
1247 context
.root
.add_namespace (ns
);
1249 } else if (reader
.name
== "include") {
1251 } else if (reader
.name
== "package") {
1252 var pkg
= parse_package ();
1253 if (context
.has_package (pkg
)) {
1254 // package already provided elsewhere, stop parsing this GIR
1257 context
.add_package (pkg
);
1259 } else if (reader
.name
== "c:include") {
1263 Report
.error (get_current_src (), "unknown child element `%s' in `repository'".printf (reader
.name
));
1267 end_element ("repository");
1270 void parse_include () {
1271 start_element ("include");
1272 var pkg
= reader
.get_attribute ("name");
1273 var version
= reader
.get_attribute ("version");
1274 if (version
!= null) {
1275 pkg
= "%s-%s".printf (pkg
, version
);
1277 // add the package to the queue
1278 context
.add_external_package (pkg
);
1280 end_element ("include");
1283 string parse_package () {
1284 start_element ("package");
1285 var pkg
= reader
.get_attribute ("name");
1287 end_element ("package");
1291 void parse_c_include () {
1292 start_element ("c:include");
1293 cheader_filenames
+= reader
.get_attribute ("name");
1295 end_element ("c:include");
1298 void skip_element () {
1303 if (current_token
== MarkupTokenType
.START_ELEMENT
) {
1305 } else if (current_token
== MarkupTokenType
.END_ELEMENT
) {
1307 } else if (current_token
== MarkupTokenType
.EOF
) {
1308 Report
.error (get_current_src (), "unexpected end of file");
1315 Namespace?
parse_namespace () {
1316 start_element ("namespace");
1318 bool new_namespace
= false;
1319 string? cprefix
= reader
.get_attribute ("c:identifier-prefixes");
1320 string namespace_name
= cprefix
;
1321 string gir_namespace
= reader
.get_attribute ("name");
1322 string gir_version
= reader
.get_attribute ("version");
1323 if (namespace_name
== null) {
1324 namespace_name
= gir_namespace
;
1326 current_source_file
.gir_namespace
= gir_namespace
;
1327 current_source_file
.gir_version
= gir_version
;
1329 var ns_metadata
= metadata
.match_child (gir_namespace
);
1330 if (ns_metadata
.has_argument (ArgumentType
.NAME
)) {
1331 namespace_name
= ns_metadata
.get_string (ArgumentType
.NAME
);
1334 var ns
= context
.root
.scope
.lookup (namespace_name
) as Namespace
;
1336 ns
= new
Namespace (namespace_name
, get_current_src ());
1337 new_namespace
= true;
1339 if (ns
.external_package
) {
1340 ns
.attributes
= null;
1341 ns
.source_reference
= get_current_src ();
1345 if (gir_namespace
!= ns
.name
) {
1346 set_symbol_mapping (new
UnresolvedSymbol (null, gir_namespace
), ns
);
1349 if (cprefix
!= null) {
1350 ns
.add_cprefix (cprefix
);
1351 ns
.set_lower_case_cprefix (Symbol
.camel_case_to_lower_case (cprefix
) + "_");
1354 if (ns_metadata
.has_argument (ArgumentType
.CHEADER_FILENAME
)) {
1355 var val
= ns_metadata
.get_string (ArgumentType
.CHEADER_FILENAME
);
1356 foreach (string filename
in val
.split (",")) {
1357 ns
.add_cheader_filename (filename
);
1360 foreach (string c_header
in cheader_filenames
) {
1361 ns
.add_cheader_filename (c_header
);
1366 var current_namespace_methods
= namespace_methods
[ns
];
1367 if (current_namespace_methods
== null) {
1368 current_namespace_methods
= new ArrayList
<Method
> ();
1369 namespace_methods
[ns
] = current_namespace_methods
;
1371 var old_symbols_info
= current_symbols_info
;
1372 var old_symbol
= current_symbol
;
1373 current_symbols_info
= new HashMap
<string,ArrayList
<SymbolInfo
>> (str_hash
, str_equal
);
1374 current_symbol
= ns
;
1375 gtype_callbacks
= new HashMap
<UnresolvedSymbol
,ArrayList
<Delegate
>> (unresolved_symbol_hash
, unresolved_symbol_equal
);
1376 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1377 if (!push_metadata ()) {
1382 if (reader
.name
== "alias") {
1383 var alias
= parse_alias ();
1384 aliases
.add (alias
);
1385 } else if (reader
.name
== "enumeration") {
1386 if (reader
.get_attribute ("glib:error-quark") != null) {
1387 add_symbol_info (parse_error_domain ());
1389 add_symbol_info (parse_enumeration ());
1391 } else if (reader
.name
== "bitfield") {
1392 add_symbol_info (parse_bitfield ());
1393 } else if (reader
.name
== "function") {
1394 var method
= parse_method ("function");
1395 add_symbol_info (method
);
1396 current_namespace_methods
.add (method
);
1397 } else if (reader
.name
== "callback") {
1398 add_symbol_info (parse_callback ());
1399 } else if (reader
.name
== "record") {
1400 if (reader
.get_attribute ("glib:get-type") != null) {
1401 add_symbol_info (parse_boxed ("record"));
1403 add_symbol_info (parse_record ());
1405 } else if (reader
.name
== "class") {
1406 add_symbol_info (parse_class ());
1407 } else if (reader
.name
== "interface") {
1408 var iface
= parse_interface ();
1409 add_symbol_info (iface
);
1410 interfaces
.add (iface
);
1411 } else if (reader
.name
== "glib:boxed") {
1412 add_symbol_info (parse_boxed ("glib:boxed"));
1413 } else if (reader
.name
== "union") {
1414 add_symbol_info (parse_union ());
1415 } else if (reader
.name
== "constant") {
1416 add_symbol_info (parse_constant ());
1419 Report
.error (get_current_src (), "unknown child element `%s' in `namespace'".printf (reader
.name
));
1425 end_element ("namespace");
1427 merge_add_process (ns
);
1428 current_symbols_info
= old_symbols_info
;
1429 current_symbol
= old_symbol
;
1430 postprocess_gtype_callbacks (ns
);
1432 if (!new_namespace
) {
1439 Alias
parse_alias () {
1440 // alias has no type information
1441 start_element ("alias");
1442 var alias
= new
Alias ();
1443 alias
.source_reference
= get_current_src ();
1444 alias
.name
= reader
.get_attribute ("name");
1445 alias
.parent_symbol
= current_symbol
;
1448 alias
.base_type
= element_get_type (parse_type (null, null, true), true);
1450 end_element ("alias");
1454 private void calculate_common_prefix (ref string common_prefix
, string cname
) {
1455 if (common_prefix
== null) {
1456 common_prefix
= cname
;
1457 while (common_prefix
.length
> 0 && !common_prefix
.has_suffix ("_")) {
1458 // FIXME: could easily be made faster
1459 common_prefix
= common_prefix
.substring (0, common_prefix
.length
- 1);
1462 while (!cname
.has_prefix (common_prefix
)) {
1463 common_prefix
= common_prefix
.substring (0, common_prefix
.length
- 1);
1466 while (common_prefix
.length
> 0 && (!common_prefix
.has_suffix ("_") ||
1467 (cname
.get_char (common_prefix
.length
).isdigit ()) && (cname
.length
- common_prefix
.length
) <= 1)) {
1468 // enum values may not consist solely of digits
1469 common_prefix
= common_prefix
.substring (0, common_prefix
.length
- 1);
1473 Enum
parse_enumeration () {
1474 start_element ("enumeration");
1476 var en
= new
Enum (element_get_name (), get_current_src ());
1477 en
.access
= SymbolAccessibility
.PUBLIC
;
1479 string enum_cname
= reader
.get_attribute ("c:type");
1480 if (enum_cname
!= null) {
1481 en
.set_cname (enum_cname
);
1486 string common_prefix
= null;
1488 var old_symbol
= current_symbol
;
1489 current_symbol
= en
;
1490 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1491 if (!push_metadata ()) {
1496 if (reader
.name
== "member") {
1497 var ev
= parse_enumeration_member ();
1499 calculate_common_prefix (ref common_prefix
, ev
.get_cname ());
1502 Report
.error (get_current_src (), "unknown child element `%s' in `enumaration'".printf (reader
.name
));
1509 en
.set_cprefix (common_prefix
);
1511 end_element ("enumeration");
1512 current_symbol
= old_symbol
;
1516 ErrorDomain
parse_error_domain () {
1517 start_element ("enumeration");
1519 var ed
= new
ErrorDomain (element_get_name (true), get_current_src ());
1520 ed
.access
= SymbolAccessibility
.PUBLIC
;
1522 string enum_cname
= reader
.get_attribute ("c:type");
1523 if (enum_cname
!= null) {
1524 ed
.set_cname (enum_cname
);
1529 string common_prefix
= null;
1530 var old_symbol
= current_symbol
;
1531 current_symbol
= ed
;
1532 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1533 if (!push_metadata ()) {
1538 if (reader
.name
== "member") {
1539 ErrorCode ec
= parse_error_member ();
1541 calculate_common_prefix (ref common_prefix
, ec
.get_cname ());
1544 Report
.error (get_current_src (), "unknown child element `%s' in `enumeration'".printf (reader
.name
));
1551 ed
.set_cprefix (common_prefix
);
1553 end_element ("enumeration");
1554 current_symbol
= old_symbol
;
1558 Enum
parse_bitfield () {
1559 start_element ("bitfield");
1560 var en
= new
Enum (reader
.get_attribute ("name"), get_current_src ());
1561 en
.access
= SymbolAccessibility
.PUBLIC
;
1563 var old_symbol
= current_symbol
;
1564 current_symbol
= en
;
1565 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1566 if (!push_metadata ()) {
1571 if (reader
.name
== "member") {
1572 en
.add_value (parse_enumeration_member ());
1575 Report
.error (get_current_src (), "unknown child element `%s' in `bitfield'".printf (reader
.name
));
1581 end_element ("bitfield");
1582 current_symbol
= en
;
1586 EnumValue
parse_enumeration_member () {
1587 start_element ("member");
1588 var ev
= new
EnumValue (reader
.get_attribute ("name").up ().replace ("-", "_"), null, get_current_src ());
1589 ev
.set_cname (reader
.get_attribute ("c:identifier"));
1591 end_element ("member");
1595 ErrorCode
parse_error_member () {
1596 start_element ("member");
1599 string name
= reader
.get_attribute ("name").up ().replace ("-", "_");
1600 string value
= reader
.get_attribute ("value");
1601 if (value
!= null) {
1602 ec
= new ErrorCode
.with_value (name
, new
IntegerLiteral (value
));
1604 ec
= new
ErrorCode (name
);
1608 end_element ("member");
1612 DataType
parse_return_value (out string? ctype
= null) {
1613 start_element ("return-value");
1614 string transfer
= reader
.get_attribute ("transfer-ownership");
1615 string allow_none
= reader
.get_attribute ("allow-none");
1617 var transfer_elements
= transfer
== "full";
1618 var type
= &ctype
!= null ?
parse_type(out ctype
, null, transfer_elements
) : parse_type (null, null, transfer_elements
);
1619 if (transfer
== "full" || transfer
== "container") {
1620 type
.value_owned
= true;
1622 if (allow_none
== "1") {
1623 type
.nullable
= true;
1625 end_element ("return-value");
1629 Parameter
parse_parameter (out int array_length_idx
= null, out int closure_idx
= null, out int destroy_idx
= null, out string? scope
= null, string? default_name
= null) {
1632 if (&array_length_idx
!= null) {
1633 array_length_idx
= -1;
1635 if (&closure_idx
!= null) {
1638 if (&destroy_idx
!= null) {
1642 start_element ("parameter");
1643 string name
= reader
.get_attribute ("name");
1645 name
= default_name
;
1647 string direction
= null;
1648 if (metadata
.has_argument (ArgumentType
.OUT
)) {
1649 if (metadata
.get_bool (ArgumentType
.OUT
)) {
1652 } else if (metadata
.has_argument (ArgumentType
.REF
)) {
1653 if (metadata
.get_bool (ArgumentType
.REF
)) {
1654 direction
= "inout";
1657 direction
= reader
.get_attribute ("direction");
1659 string transfer
= reader
.get_attribute ("transfer-ownership");
1660 string allow_none
= reader
.get_attribute ("allow-none");
1662 if (&scope
!= null) {
1663 scope
= reader
.get_attribute ("scope");
1666 string closure
= reader
.get_attribute ("closure");
1667 string destroy
= reader
.get_attribute ("destroy");
1668 if (closure
!= null && &closure_idx
!= null) {
1669 closure_idx
= int.parse (closure
);
1671 if (destroy
!= null && &destroy_idx
!= null) {
1672 destroy_idx
= int.parse (destroy
);
1676 if (reader
.name
== "varargs") {
1677 start_element ("varargs");
1679 param
= new Parameter
.with_ellipsis (get_current_src ());
1680 end_element ("varargs");
1683 var type
= parse_type (out ctype
, out array_length_idx
, transfer
== "full");
1685 type
= element_get_type (type
, false, out changed
);
1687 // discard ctype, duplicated information
1691 if (type is ArrayType
&& metadata
.has_argument (ArgumentType
.ARRAY_LENGTH_POS
)) {
1692 array_length_idx
= metadata
.get_integer (ArgumentType
.ARRAY_LENGTH_POS
);
1695 if (transfer
== "full" || transfer
== "container" || destroy
!= null) {
1696 type
.value_owned
= true;
1698 if (allow_none
== "1") {
1699 type
.nullable
= true;
1701 param
= new
Parameter (name
, type
, get_current_src ());
1702 param
.ctype
= ctype
;
1703 if (direction
== "out") {
1704 param
.direction
= ParameterDirection
.OUT
;
1705 } else if (direction
== "inout") {
1706 param
.direction
= ParameterDirection
.REF
;
1708 param
.initializer
= metadata
.get_expression (ArgumentType
.DEFAULT
);
1710 end_element ("parameter");
1714 DataType
parse_type (out string? ctype
= null, out int array_length_index
= null, bool transfer_elements
= false, out bool no_array_length
= null, out bool array_null_terminated
= null) {
1715 bool is_array
= false;
1716 string type_name
= reader
.get_attribute ("name");
1718 if (&array_length_index
!= null) {
1719 array_length_index
= -1;
1722 if (reader
.name
== "array") {
1724 start_element ("array");
1726 if (!(type_name
== "GLib.Array" || type_name
== "GLib.PtrArray")) {
1727 if (reader
.get_attribute ("length") != null
1728 && &array_length_index
!= null) {
1729 array_length_index
= int.parse (reader
.get_attribute ("length"));
1732 var element_type
= parse_type ();
1733 end_element ("array");
1734 return new
ArrayType (element_type
, 1, null);
1736 } else if (reader
.name
== "callback"){
1737 var callback = parse_callback ();
1738 return new
DelegateType (callback);
1740 start_element ("type");
1743 if (&ctype
!= null) {
1744 ctype
= reader
.get_attribute("c:type");
1749 if (type_name
== "GLib.PtrArray"
1750 && current_token
== MarkupTokenType
.START_ELEMENT
) {
1751 type_name
= "GLib.GenericArray";
1754 DataType type
= parse_type_from_gir_name (type_name
, out no_array_length
, out array_null_terminated
, ctype
);
1756 // type arguments / element types
1757 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1758 var element_type
= parse_type ();
1759 element_type
.value_owned
= transfer_elements
;
1760 type
.add_type_argument (element_type
);
1763 end_element (is_array ?
"array" : "type");
1767 DataType
parse_type_from_gir_name (string type_name
, out bool no_array_length
= null, out bool array_null_terminated
= null, string? ctype
= null) {
1768 if (&no_array_length
!= null) {
1769 no_array_length
= false;
1771 if (&array_null_terminated
!= null) {
1772 array_null_terminated
= false;
1776 if (type_name
== "none") {
1777 type
= new
VoidType (get_current_src ());
1778 } else if (type_name
== "gpointer") {
1779 type
= new
PointerType (new
VoidType (get_current_src ()), get_current_src ());
1780 } else if (type_name
== "GObject.Strv") {
1781 type
= new
ArrayType (new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, "string")), 1, get_current_src ());
1782 if (&no_array_length
!= null) {
1783 no_array_length
= true;
1785 if (&array_null_terminated
!= null) {
1786 array_null_terminated
= true;
1789 bool known_type
= true;
1790 if (type_name
== "utf8") {
1791 type_name
= "string";
1792 } else if (type_name
== "gboolean") {
1794 } else if (type_name
== "gchar") {
1796 } else if (type_name
== "gshort") {
1797 type_name
= "short";
1798 } else if (type_name
== "gushort") {
1799 type_name
= "ushort";
1800 } else if (type_name
== "gint") {
1802 } else if (type_name
== "guint") {
1804 } else if (type_name
== "glong") {
1805 if (ctype
== "gssize") {
1806 type_name
= "ssize_t";
1810 } else if (type_name
== "gulong") {
1811 if (ctype
== "gsize") {
1812 type_name
= "size_t";
1814 type_name
= "ulong";
1816 } else if (type_name
== "gint8") {
1818 } else if (type_name
== "guint8") {
1819 type_name
= "uint8";
1820 } else if (type_name
== "gint16") {
1821 type_name
= "int16";
1822 } else if (type_name
== "guint16") {
1823 type_name
= "uint16";
1824 } else if (type_name
== "gint32") {
1825 type_name
= "int32";
1826 } else if (type_name
== "guint32") {
1827 type_name
= "uint32";
1828 } else if (type_name
== "gint64") {
1829 type_name
= "int64";
1830 } else if (type_name
== "guint64") {
1831 type_name
= "uint64";
1832 } else if (type_name
== "gfloat") {
1833 type_name
= "float";
1834 } else if (type_name
== "gdouble") {
1835 type_name
= "double";
1836 } else if (type_name
== "filename") {
1837 type_name
= "string";
1838 } else if (type_name
== "GLib.offset") {
1839 type_name
= "int64";
1840 } else if (type_name
== "gsize") {
1841 type_name
= "size_t";
1842 } else if (type_name
== "gssize") {
1843 type_name
= "ssize_t";
1844 } else if (type_name
== "GType") {
1845 type_name
= "GLib.Type";
1846 } else if (type_name
== "GLib.String") {
1847 type_name
= "GLib.StringBuilder";
1848 } else if (type_name
== "GObject.Class") {
1849 type_name
= "GLib.ObjectClass";
1850 } else if (type_name
== "GLib.unichar") {
1851 type_name
= "unichar";
1852 } else if (type_name
== "GLib.Data") {
1853 type_name
= "GLib.Datalist";
1854 } else if (type_name
== "Atk.ImplementorIface") {
1855 type_name
= "Atk.Implementor";
1859 var sym
= parse_symbol_from_string (type_name
, get_current_src ());
1860 type
= new UnresolvedType
.from_symbol (sym
, get_current_src ());
1862 unresolved_gir_symbols
.add (sym
);
1869 Struct
parse_record () {
1870 start_element ("record");
1871 var st
= new
Struct (reader
.get_attribute ("name"), get_current_src ());
1873 st
.access
= SymbolAccessibility
.PUBLIC
;
1875 string cname
= reader
.get_attribute ("c:type");
1876 if (cname
!= null) {
1877 st
.set_cname (cname
);
1880 current_gtype_struct_for
= reader
.get_attribute ("glib:is-gtype-struct-for");
1881 if (current_gtype_struct_for
!= null) {
1882 girdata
["glib:is-gtype-struct-for"] = current_gtype_struct_for
;
1886 var old_symbols_info
= current_symbols_info
;
1887 var old_symbol
= current_symbol
;
1888 current_symbols_info
= new HashMap
<string,ArrayList
<SymbolInfo
>> (str_hash
, str_equal
);
1889 current_symbol
= st
;
1890 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1891 if (!push_metadata ()) {
1896 if (reader
.name
== "field") {
1897 if (reader
.get_attribute ("name") != "priv") {
1898 add_symbol_info (parse_field ());
1902 } else if (reader
.name
== "constructor") {
1903 parse_constructor ();
1904 } else if (reader
.name
== "method") {
1905 add_symbol_info (parse_method ("method"));
1906 } else if (reader
.name
== "union") {
1907 Struct s
= parse_union ();
1908 var s_fields
= s
.get_fields ();
1909 foreach (var f
in s_fields
) {
1910 f
.set_cname (s
.get_cname () + "." + f
.get_cname ());
1911 f
.name
= s
.name
+ "_" + f
.name
;
1916 Report
.error (get_current_src (), "unknown child element `%s' in `record'".printf (reader
.name
));
1922 end_element ("record");
1924 merge_add_process (st
);
1925 current_symbols_info
= old_symbols_info
;
1926 current_symbol
= old_symbol
;
1927 current_gtype_struct_for
= null;
1932 Class
parse_class () {
1933 start_element ("class");
1934 var name
= element_get_name ();
1935 string cname
= reader
.get_attribute ("c:type");
1936 string parent
= reader
.get_attribute ("parent");
1937 var cl
= current_symbol
.scope
.lookup (name
) as Class
;
1939 cl
= new
Class (name
, get_current_src ());
1940 cl
.access
= SymbolAccessibility
.PUBLIC
;
1943 if (cname
!= null) {
1944 cl
.set_cname (cname
);
1947 if (parent
!= null) {
1948 cl
.add_base_type (parse_type_from_gir_name (parent
));
1952 var first_field
= true;
1953 var old_symbols_info
= current_symbols_info
;
1954 current_symbols_info
= new HashMap
<string,ArrayList
<SymbolInfo
>> (str_hash
, str_equal
);
1955 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1956 if (!push_metadata ()) {
1961 if (reader
.name
== "implements") {
1962 start_element ("implements");
1963 cl
.add_base_type (parse_type_from_gir_name (reader
.get_attribute ("name")));
1965 end_element ("implements");
1966 } else if (reader
.name
== "constant") {
1967 add_symbol_info (parse_constant ());
1968 } else if (reader
.name
== "field") {
1969 if (first_field
&& parent
!= null) {
1970 // first field is guaranteed to be the parent instance
1973 var field
= parse_field ();
1974 if (field
.name
!= "priv") {
1975 add_symbol_info (field
);
1978 first_field
= false;
1979 } else if (reader
.name
== "property") {
1980 add_symbol_info (parse_property ());
1981 } else if (reader
.name
== "constructor") {
1982 add_symbol_info (parse_constructor (cname
));
1983 } else if (reader
.name
== "function") {
1984 add_symbol_info (parse_method ("function"));
1985 } else if (reader
.name
== "method") {
1986 add_symbol_info (parse_method ("method"));
1987 } else if (reader
.name
== "virtual-method") {
1988 add_symbol_info (parse_method ("virtual-method"));
1989 } else if (reader
.name
== "union") {
1990 Struct s
= parse_union ();
1991 var s_fields
= s
.get_fields ();
1992 foreach (var f
in s_fields
) {
1993 f
.set_cname (s
.get_cname () + "." + f
.get_cname ());
1994 f
.name
= s
.name
+ "_" + f
.name
;
1995 add_symbol_info (f
);
1997 } else if (reader
.name
== "glib:signal") {
1998 add_symbol_info (parse_signal ());
2001 Report
.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader
.name
));
2008 merge_add_process (cl
);
2009 current_symbols_info
= old_symbols_info
;
2011 handle_async_methods (cl
);
2013 end_element ("class");
2017 Interface
parse_interface () {
2018 start_element ("interface");
2019 var iface
= new
Interface (element_get_name (), get_current_src ());
2020 iface
.access
= SymbolAccessibility
.PUBLIC
;
2021 iface
.external
= true;
2023 string cname
= reader
.get_attribute ("c:type");
2024 if (cname
!= null) {
2025 iface
.set_cname (cname
);
2029 var old_symbol
= current_symbol
;
2030 var old_symbols_info
= current_symbols_info
;
2031 current_symbols_info
= new HashMap
<string,ArrayList
<SymbolInfo
>> (str_hash
, str_equal
);
2032 current_symbol
= iface
;
2033 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2034 if (!push_metadata ()) {
2039 if (reader
.name
== "prerequisite") {
2040 start_element ("prerequisite");
2041 iface
.add_prerequisite (parse_type_from_gir_name (reader
.get_attribute ("name")));
2043 end_element ("prerequisite");
2044 } else if (reader
.name
== "field") {
2045 add_symbol_info (parse_field ());
2046 } else if (reader
.name
== "property") {
2047 add_symbol_info (parse_property ());
2048 } else if (reader
.name
== "virtual-method") {
2049 add_symbol_info (parse_method ("virtual-method"));
2050 } else if (reader
.name
== "function") {
2051 add_symbol_info (parse_method ("function"));
2052 } else if (reader
.name
== "method") {
2053 add_symbol_info (parse_method ("method"));
2054 } else if (reader
.name
== "glib:signal") {
2055 add_symbol_info (parse_signal ());
2058 Report
.error (get_current_src (), "unknown child element `%s' in `interface'".printf (reader
.name
));
2065 merge_add_process (iface
);
2066 current_symbol
= old_symbol
;
2067 current_symbols_info
= old_symbols_info
;
2069 handle_async_methods (iface
);
2071 end_element ("interface");
2075 void handle_async_methods (ObjectTypeSymbol type_symbol
) {
2076 var methods
= type_symbol
.get_methods ();
2077 for (int method_n
= 0 ; method_n
< methods
.size
; method_n
++) {
2078 var m
= methods
.get (method_n
);
2081 string finish_method_base
;
2082 if (m
.name
.has_suffix ("_async")) {
2083 finish_method_base
= m
.name
.substring (0, m
.name
.length
- "_async".length
);
2085 finish_method_base
= m
.name
;
2087 var finish_method
= type_symbol
.scope
.lookup (finish_method_base
+ "_finish") as Method
;
2089 // check if the method is using non-standard finish method name
2090 if (finish_method
== null) {
2091 var method_cname
= m
.get_finish_cname ();
2092 foreach (Method method
in type_symbol
.get_methods ()) {
2093 if (method
.get_cname () == method_cname
) {
2094 finish_method
= method
;
2100 if (finish_method
!= null) {
2101 m
.return_type
= finish_method
.return_type
.copy ();
2102 m
.no_array_length
= finish_method
.no_array_length
;
2103 m
.array_null_terminated
= finish_method
.array_null_terminated
;
2104 foreach (var param
in finish_method
.get_parameters ()) {
2105 if (param
.direction
== ParameterDirection
.OUT
) {
2106 var async_param
= param
.copy ();
2107 if (m
.scope
.lookup (param
.name
) != null) {
2108 // parameter name conflict
2109 async_param
.name
+= "_out";
2111 m
.add_parameter (async_param
);
2114 foreach (DataType error_type
in finish_method
.get_error_types ()) {
2115 m
.add_error_type (error_type
.copy ());
2117 if (methods
.index_of (finish_method
) < method_n
) {
2120 type_symbol
.scope
.remove (finish_method
.name
);
2121 methods
.remove (finish_method
);
2127 Field
parse_field () {
2128 start_element ("field");
2129 string name
= reader
.get_attribute ("name");
2130 string allow_none
= reader
.get_attribute ("allow-none");
2132 var type
= parse_type ();
2133 type
= element_get_type (type
, true);
2134 if (type is DelegateType
&& current_gtype_struct_for
!= null) {
2136 var gtype_struct_for
= parse_symbol_from_string (current_gtype_struct_for
);
2137 ArrayList
<Delegate
> callbacks
= gtype_callbacks
.get (gtype_struct_for
);
2138 if (callbacks
== null) {
2139 callbacks
= new ArrayList
<Delegate
> ();
2140 gtype_callbacks
.set (gtype_struct_for
, callbacks
);
2142 callbacks
.add (((DelegateType
) type
).delegate_symbol
);
2144 var field
= new
Field (name
, type
, null, get_current_src ());
2145 field
.access
= SymbolAccessibility
.PUBLIC
;
2146 field
.no_array_length
= true;
2147 if (allow_none
== "1") {
2148 type
.nullable
= true;
2150 end_element ("field");
2154 Property
parse_property () {
2155 start_element ("property");
2156 string name
= reader
.get_attribute ("name").replace ("-", "_");
2157 string readable
= reader
.get_attribute ("readable");
2158 string writable
= reader
.get_attribute ("writable");
2159 string construct_
= reader
.get_attribute ("construct");
2160 string construct_only
= reader
.get_attribute ("construct-only");
2162 bool no_array_length
;
2163 bool array_null_terminated
;
2164 var type
= parse_type (null, null, false, out no_array_length
, out array_null_terminated
);
2165 var prop
= new
Property (name
, type
, null, null, get_current_src ());
2166 prop
.access
= SymbolAccessibility
.PUBLIC
;
2167 prop
.external
= true;
2168 prop
.no_accessor_method
= true;
2169 prop
.no_array_length
= no_array_length
;
2170 prop
.array_null_terminated
= array_null_terminated
;
2171 if (readable
!= "0") {
2172 prop
.get_accessor
= new
PropertyAccessor (true, false, false, prop
.property_type
.copy (), null, null);
2174 if (writable
== "1" || construct_only
== "1") {
2175 prop
.set_accessor
= new
PropertyAccessor (false, (construct_only
!= "1") && (writable
== "1"), (construct_only
== "1") || (construct_
== "1"), prop
.property_type
.copy (), null, null);
2177 end_element ("property");
2181 Delegate
parse_callback () {
2182 return this
.parse_function ("callback") as Delegate
;
2185 Method
parse_constructor (string? parent_ctype
= null) {
2186 start_element ("constructor");
2188 string throws_string
= reader
.get_attribute ("throws");
2189 string cname
= reader
.get_attribute ("c:identifier");
2190 var m
= new
CreationMethod (null, element_get_name (), get_current_src ());
2191 m
.access
= SymbolAccessibility
.PUBLIC
;
2192 m
.has_construct_function
= false;
2194 if (m
.name
== "new") {
2196 } else if (m
.name
.has_prefix ("new_")) {
2197 m
.name
= m
.name
.substring ("new_".length
);
2199 if (cname
!= null) {
2200 m
.set_cname (cname
);
2205 parse_return_value (out ctype
);
2206 if (ctype
!= null && (parent_ctype
== null || ctype
!= parent_ctype
+ "*")) {
2207 m
.custom_return_type_cname
= ctype
;
2210 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "parameters") {
2211 start_element ("parameters");
2213 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2214 if (!push_metadata ()) {
2219 m
.add_parameter (parse_parameter ());
2223 end_element ("parameters");
2226 if (throws_string
== "1") {
2227 m
.add_error_type (new
ErrorType (null, null));
2229 end_element ("constructor");
2234 public MethodInfo (Parameter param
, int array_length_idx
, int closure_idx
, int destroy_idx
) {
2236 this
.array_length_idx
= array_length_idx
;
2237 this
.closure_idx
= closure_idx
;
2238 this
.destroy_idx
= destroy_idx
;
2239 this
.vala_idx
= 0.0F
;
2243 public Parameter param
;
2244 public float vala_idx
;
2245 public int array_length_idx
;
2246 public int closure_idx
;
2247 public int destroy_idx
;
2251 Symbol
parse_function (string element_name
) {
2252 start_element (element_name
);
2253 string name
= element_get_name ();
2254 string cname
= reader
.get_attribute ("c:identifier");
2255 string throws_string
= reader
.get_attribute ("throws");
2256 string invoker
= reader
.get_attribute ("invoker");
2258 DataType return_type
;
2259 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "return-value") {
2260 return_type
= parse_return_value ();
2262 return_type
= new
VoidType ();
2264 return_type
= element_get_type (return_type
, true);
2268 if (element_name
== "callback") {
2269 s
= new
Delegate (name
, return_type
, get_current_src ());
2271 s
= new
Method (name
, return_type
, get_current_src ());
2274 s
.access
= SymbolAccessibility
.PUBLIC
;
2275 if (cname
!= null) {
2277 ((Method
) s
).set_cname (cname
);
2279 ((Delegate
) s
).set_cname (cname
);
2285 if (element_name
== "virtual-method" || element_name
== "callback") {
2287 ((Method
) s
).is_virtual
= true;
2288 if (invoker
== null && !metadata
.has_argument (ArgumentType
.VFUNC_NAME
)) {
2289 s
.attributes
.append (new
Attribute ("NoWrapper", s
.source_reference
));
2293 if (invoker
!= null) {
2296 } else if (element_name
== "function") {
2297 ((Method
) s
).binding
= MemberBinding
.STATIC
;
2301 var method
= (Method
) s
;
2302 if (metadata
.has_argument (ArgumentType
.VIRTUAL
)) {
2303 method
.is_virtual
= metadata
.get_bool (ArgumentType
.VIRTUAL
);
2304 method
.is_abstract
= false;
2305 } else if (metadata
.has_argument (ArgumentType
.ABSTRACT
)) {
2306 method
.is_abstract
= metadata
.get_bool (ArgumentType
.ABSTRACT
);
2307 method
.is_virtual
= false;
2309 method
.vfunc_name
= metadata
.get_string (ArgumentType
.VFUNC_NAME
);
2312 var parameters
= new ArrayList
<MethodInfo
> ();
2313 var array_length_parameters
= new ArrayList
<int> ();
2314 var closure_parameters
= new ArrayList
<int> ();
2315 var destroy_parameters
= new ArrayList
<int> ();
2316 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "parameters") {
2317 start_element ("parameters");
2320 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2321 if (!push_metadata ()) {
2326 int array_length_idx
, closure_idx
, destroy_idx
;
2328 string default_param_name
= null;
2329 default_param_name
= "arg%d".printf (parameters
.size
);
2330 var param
= parse_parameter (out array_length_idx
, out closure_idx
, out destroy_idx
, out scope
, default_param_name
);
2331 if (array_length_idx
!= -1) {
2332 array_length_parameters
.add (array_length_idx
);
2334 if (closure_idx
!= -1) {
2335 closure_parameters
.add (closure_idx
);
2337 if (destroy_idx
!= -1) {
2338 destroy_parameters
.add (destroy_idx
);
2341 var info
= new
MethodInfo(param
, array_length_idx
, closure_idx
, destroy_idx
);
2343 if (s is Method
&& scope
== "async") {
2344 var unresolved_type
= param
.variable_type as UnresolvedType
;
2345 if (unresolved_type
!= null && unresolved_type
.unresolved_symbol
.name
== "AsyncReadyCallback") {
2346 // GAsync-style method
2347 ((Method
) s
).coroutine
= true;
2352 parameters
.add (info
);
2355 end_element ("parameters");
2360 foreach (MethodInfo info
in parameters
) {
2361 if (s is Delegate
&& info
.closure_idx
== i
) {
2362 var d
= (Delegate
) s
;
2363 d
.has_target
= true;
2364 d
.cinstance_parameter_position
= (float) j
- 0.1;
2366 } else if (info
.keep
2367 && !array_length_parameters
.contains (i
)
2368 && !closure_parameters
.contains (i
)
2369 && !destroy_parameters
.contains (i
)) {
2370 info
.vala_idx
= (float) j
;
2373 /* interpolate for vala_idx between this and last*/
2374 float last_idx
= 0.0F
;
2376 last_idx
= parameters
[last
].vala_idx
;
2378 for (int k
=last
+1; k
< i
; k
++) {
2379 parameters
[k
].vala_idx
= last_idx
+ (((j
- last_idx
) / (i
-last
)) * (k
-last
));
2385 // make sure that vala_idx is always set
2386 // the above if branch does not set vala_idx for
2387 // hidden parameters at the end of the parameter list
2388 info
.vala_idx
= (j
- 1) + (i
- last
) * 0.1F
;
2393 foreach (MethodInfo info
in parameters
) {
2396 /* add_parameter sets carray_length_parameter_position and cdelegate_target_parameter_position
2399 ((Method
) s
).add_parameter (info
.param
);
2401 ((Delegate
) s
).add_parameter (info
.param
);
2404 if (info
.array_length_idx
!= -1) {
2405 if ((info
.array_length_idx
) >= parameters
.size
) {
2406 Report
.error (get_current_src (), "invalid array_length index");
2409 info
.param
.carray_length_parameter_position
= parameters
[info
.array_length_idx
].vala_idx
;
2410 info
.param
.set_array_length_cname (parameters
[info
.array_length_idx
].param
.name
);
2412 if (info
.param
.variable_type is ArrayType
&& info
.array_length_idx
== -1) {
2413 info
.param
.no_array_length
= true;
2416 if (info
.closure_idx
!= -1) {
2417 if ((info
.closure_idx
) >= parameters
.size
) {
2418 Report
.error (get_current_src (), "invalid closure index");
2421 info
.param
.cdelegate_target_parameter_position
= parameters
[info
.closure_idx
].vala_idx
;
2423 if (info
.destroy_idx
!= -1) {
2424 if (info
.destroy_idx
>= parameters
.size
) {
2425 Report
.error (get_current_src (), "invalid destroy index");
2428 info
.param
.cdestroy_notify_parameter_position
= parameters
[info
.destroy_idx
].vala_idx
;
2433 if (throws_string
== "1") {
2434 s
.add_error_type (new
ErrorType (null, null));
2436 end_element (element_name
);
2440 Method
parse_method (string element_name
) {
2441 return this
.parse_function (element_name
) as Method
;
2444 Signal
parse_signal () {
2445 start_element ("glib:signal");
2446 string name
= reader
.get_attribute ("name").replace ("-", "_");
2448 DataType return_type
;
2449 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "return-value") {
2450 return_type
= parse_return_value ();
2452 return_type
= new
VoidType ();
2454 var sig
= new
Signal (name
, return_type
, get_current_src ());
2455 sig
.access
= SymbolAccessibility
.PUBLIC
;
2456 sig
.external
= true;
2457 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "parameters") {
2458 start_element ("parameters");
2460 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2461 if (!push_metadata ()) {
2466 sig
.add_parameter (parse_parameter ());
2470 end_element ("parameters");
2472 end_element ("glib:signal");
2476 Class
parse_boxed (string element_name
) {
2477 start_element (element_name
);
2478 string name
= reader
.get_attribute ("name");
2480 name
= reader
.get_attribute ("glib:name");
2482 var cl
= new
Class (name
, get_current_src ());
2483 cl
.access
= SymbolAccessibility
.PUBLIC
;
2485 cl
.is_compact
= true;
2487 string cname
= reader
.get_attribute ("c:type");
2488 if (cname
!= null) {
2489 cl
.set_cname (cname
);
2492 cl
.set_type_id ("%s ()".printf (reader
.get_attribute ("glib:get-type")));
2493 cl
.set_free_function ("g_boxed_free");
2494 cl
.set_dup_function ("g_boxed_copy");
2497 var old_symbols_info
= current_symbols_info
;
2498 var old_symbol
= current_symbol
;
2499 current_symbols_info
= new HashMap
<string,ArrayList
<SymbolInfo
>> (str_hash
, str_equal
);
2500 current_symbol
= cl
;
2501 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2502 if (!push_metadata ()) {
2507 if (reader
.name
== "field") {
2508 add_symbol_info (parse_field ());
2509 } else if (reader
.name
== "constructor") {
2510 parse_constructor ();
2511 } else if (reader
.name
== "method") {
2512 add_symbol_info (parse_method ("method"));
2515 Report
.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader
.name
));
2521 end_element (element_name
);
2523 merge_add_process (cl
);
2524 current_symbols_info
= old_symbols_info
;
2525 current_symbol
= old_symbol
;
2530 Struct
parse_union () {
2531 start_element ("union");
2532 var st
= new
Struct (reader
.get_attribute ("name"), get_current_src ());
2533 st
.access
= SymbolAccessibility
.PUBLIC
;
2537 var old_symbol
= current_symbol
;
2538 current_symbol
= st
;
2539 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2540 if (!push_metadata ()) {
2545 if (reader
.name
== "field") {
2546 st
.add_field (parse_field ());
2547 } else if (reader
.name
== "constructor") {
2548 parse_constructor ();
2549 } else if (reader
.name
== "method") {
2550 st
.add_method (parse_method ("method"));
2551 } else if (reader
.name
== "record") {
2552 Struct s
= parse_record ();
2553 var fs
= s
.get_fields ();
2554 foreach (var f
in fs
) {
2555 f
.set_cname (s
.get_cname () + "." + f
.get_cname ());
2556 f
.name
= s
.name
+ "_" + f
.name
;
2561 Report
.error (get_current_src (), "unknown child element `%s' in `union'".printf (reader
.name
));
2568 end_element ("union");
2569 current_symbol
= old_symbol
;
2574 Constant
parse_constant () {
2575 start_element ("constant");
2576 string name
= element_get_name ();
2578 var type
= parse_type ();
2579 var c
= new
Constant (name
, type
, null, get_current_src ());
2580 c
.access
= SymbolAccessibility
.PUBLIC
;
2582 end_element ("constant");
2587 void report_unused_metadata (Metadata metadata
) {
2588 if (metadata
== Metadata
.empty
) {
2592 if (metadata
.args
.size
== 0 && metadata
.children
.size
== 0) {
2593 Report
.warning (metadata
.source_reference
, "empty metadata");
2597 foreach (var arg_type
in metadata
.args
.get_keys ()) {
2598 var arg
= metadata
.args
[arg_type
];
2600 // if metadata is used and argument is not, then it's a unexpected argument
2601 Report
.warning (arg
.source_reference
, "argument never used");
2605 foreach (var child
in metadata
.children
) {
2607 Report
.warning (child
.source_reference
, "metadata never used");
2609 report_unused_metadata (child
);
2616 void resolve_gir_symbols () {
2617 // we are remapping unresolved symbols, so create them from concrete symbols
2618 foreach (var map_from
in concrete_symbols_map
.get_keys ()) {
2619 unresolved_symbols_map
[get_unresolved_symbol(map_from
)] = concrete_symbols_map
[map_from
];
2622 // gir has simple namespaces, we won't get deeper than 2 levels here, except reparenting
2623 foreach (var map_from
in unresolved_gir_symbols
) {
2624 while (map_from
!= null) {
2625 var map_to
= unresolved_symbols_map
[map_from
];
2626 if (map_to
!= null) {
2627 // remap the original symbol to match the target
2628 map_from
.inner
= null;
2629 map_from
.name
= map_to
.name
;
2630 if (map_to is UnresolvedSymbol
) {
2631 var umap_to
= (UnresolvedSymbol
) map_to
;
2632 while (umap_to
.inner
!= null) {
2633 umap_to
= umap_to
.inner
;
2634 map_from
.inner
= new
UnresolvedSymbol (null, umap_to
.name
);
2635 map_from
= map_from
.inner
;
2638 while (map_to
.parent_symbol
!= null && map_to
.parent_symbol
!= context
.root
) {
2639 map_to
= map_to
.parent_symbol
;
2640 map_from
.inner
= new
UnresolvedSymbol (null, map_to
.name
);
2641 map_from
= map_from
.inner
;
2646 map_from
= map_from
.inner
;
2651 Symbol?
resolve_symbol (Scope parent_scope
, UnresolvedSymbol unresolved_symbol
) {
2652 // simple symbol resolver, enough for gir
2653 if (unresolved_symbol
.inner
== null) {
2654 var scope
= parent_scope
;
2655 while (scope
!= null) {
2656 var sym
= scope
.lookup (unresolved_symbol
.name
);
2660 scope
= scope
.parent_scope
;
2663 var inner
= resolve_symbol (parent_scope
, unresolved_symbol
.inner
);
2664 if (inner
!= null) {
2665 return inner
.scope
.lookup (unresolved_symbol
.name
);
2671 void postprocess_interfaces () {
2672 foreach (var iface
in interfaces
) {
2673 /* Temporarily workaround G-I bug not adding GLib.Object prerequisite:
2674 ensure we have at least one instantiable prerequisite */
2675 bool has_instantiable_prereq
= false;
2676 foreach (DataType prereq
in iface
.get_prerequisites ()) {
2678 if (prereq is UnresolvedType
) {
2679 var unresolved_symbol
= ((UnresolvedType
) prereq
).unresolved_symbol
;
2680 sym
= resolve_symbol (iface
.parent_symbol
.scope
, unresolved_symbol
);
2682 sym
= prereq
.data_type
;
2685 has_instantiable_prereq
= true;
2690 if (!has_instantiable_prereq
) {
2691 iface
.add_prerequisite (new
ObjectType ((ObjectTypeSymbol
) glib_ns
.scope
.lookup ("Object")));
2696 void postprocess_reparenting () {
2697 foreach (UnresolvedSymbol target_unresolved_symbol
in symbol_reparent_map
.get_keys ()) {
2698 var target_symbol
= resolve_symbol (context
.root
.scope
, target_unresolved_symbol
);
2699 if (target_symbol
== null) {
2700 // create namespaces backward
2701 var sym
= target_unresolved_symbol
;
2702 var ns
= new
Namespace (sym
.name
, sym
.source_reference
);
2705 while (sym
!= null) {
2706 var res
= resolve_symbol (context
.root
.scope
, sym
);
2707 if (res
!= null && !(res is Namespace
)) {
2711 var parent
= res as Namespace
;
2713 parent
= new
Namespace (sym
.name
, sym
.source_reference
);
2715 if (parent
.scope
.lookup (ns
.name
) == null) {
2716 parent
.add_namespace (ns
);
2721 if (result
!= null && sym
== null && context
.root
.scope
.lookup (ns
.name
) == null) {
2722 // a new root namespace, helpful for a possible non-gobject gir?
2723 context
.root
.add_namespace (ns
);
2725 target_symbol
= result
;
2727 if (target_symbol
== null) {
2728 Report
.error (null, "unable to reparent into `%s'".printf (target_unresolved_symbol
.to_string ()));
2731 var symbols
= symbol_reparent_map
[target_unresolved_symbol
];
2732 foreach (var symbol
in symbols
) {
2733 add_symbol_to_container (target_symbol
, symbol
);
2738 void postprocess_gtype_callbacks (Namespace ns
) {
2739 foreach (UnresolvedSymbol gtype_struct_for
in gtype_callbacks
.get_keys ()) {
2740 // parent symbol is the record, therefore use parent of parent symbol
2741 var gtype
= resolve_symbol (ns
.scope
, gtype_struct_for
) as ObjectTypeSymbol
;
2742 if (gtype
== null) {
2743 Report
.error (null, "unknown symbol `%s' while postprocessing callbacks".printf (gtype_struct_for
.name
));
2746 ArrayList
<Delegate
> callbacks
= gtype_callbacks
.get (gtype_struct_for
);
2747 foreach (Delegate d
in callbacks
) {
2748 var symbol
= gtype
.scope
.lookup (d
.name
);
2749 if (symbol
== null) {
2751 } else if (symbol is Method
) {
2752 var meth
= (Method
) symbol
;
2753 if (gtype is Class
) {
2754 meth
.is_virtual
= true;
2755 } else if (gtype is Interface
) {
2756 meth
.is_abstract
= true;
2758 } else if (symbol is Signal
) {
2759 var sig
= (Signal
) symbol
;
2760 sig
.is_virtual
= true;
2761 assume_parameter_names (sig
, d
);
2762 } else if (symbol is Property
) {
2763 var prop
= (Property
) symbol
;
2764 prop
.is_virtual
= true;
2766 Report
.error (get_current_src (), "unknown member type `%s' in `%s'".printf (d
.name
, gtype
.name
));
2772 void postprocess_aliases () {
2773 /* this is unfortunate because <alias> tag has no type information, thus we have
2774 to guess it from the target */
2775 foreach (var alias
in aliases
) {
2776 DataType base_type
= null;
2777 Symbol type_sym
= null;
2778 if (alias
.base_type is UnresolvedType
) {
2779 base_type
= alias
.base_type
;
2780 type_sym
= resolve_symbol (alias
.parent_symbol
.scope
, ((UnresolvedType
) base_type
).unresolved_symbol
);
2781 } else if (!(alias
.base_type is VoidType
)) {
2782 base_type
= alias
.base_type
;
2783 type_sym
= base_type
.data_type
;
2786 if (base_type
== null || type_sym
== null || type_sym is Struct
) {
2787 var st
= new
Struct (alias
.name
, alias
.source_reference
);
2788 st
.access
= SymbolAccessibility
.PUBLIC
;
2789 if (base_type
!= null) {
2790 // threat target="none" as a new struct
2791 st
.base_type
= base_type
;
2794 add_symbol_to_container (alias
.parent_symbol
, st
);
2795 } else if (type_sym is Class
) {
2796 var cl
= new
Class (alias
.name
, alias
.source_reference
);
2797 cl
.access
= SymbolAccessibility
.PUBLIC
;
2798 if (base_type
!= null) {
2799 cl
.add_base_type (base_type
);
2802 add_symbol_to_container (alias
.parent_symbol
, cl
);
2807 void find_static_method_parent (string cname
, Symbol current
, ref Symbol best
, ref double match
, double match_char
) {
2808 var old_best
= best
;
2809 if (current
.scope
.get_symbol_table () != null) {
2810 foreach (var child
in current
.scope
.get_symbol_table().get_values ()) {
2811 if (child is Struct
|| child is ObjectTypeSymbol
|| child is Namespace
) {
2812 find_static_method_parent (cname
, child
, ref best
, ref match
, match_char
);
2816 if (best
!= old_best
) {
2821 var current_cprefix
= current
.get_lower_case_cprefix ();
2822 if (cname
.has_prefix (current_cprefix
)) {
2823 var current_match
= match_char
* current_cprefix
.length
;
2824 if (current_match
> match
) {
2825 match
= current_match
;
2831 void postprocess_namespace_methods () {
2832 /* transform static methods into instance methods if possible.
2833 In most of cases this is a .gir fault we are going to fix */
2834 foreach (var ns
in namespace_methods
.get_keys ()) {
2835 var ns_cprefix
= ns
.get_lower_case_cprefix ();
2836 var methods
= namespace_methods
[ns
];
2837 foreach (var method
in methods
) {
2838 if (method
.parent_symbol
!= null) {
2839 // fixed earlier by metadata
2843 var cname
= method
.get_cname ();
2845 Parameter first_param
= null;
2846 if (method
.get_parameters ().size
> 0) {
2847 first_param
= method
.get_parameters()[0];
2849 if (first_param
!= null && first_param
.variable_type is UnresolvedType
) {
2850 // check if it's a missed instance method (often happens for structs)
2851 var parent
= resolve_symbol (ns
.scope
, ((UnresolvedType
) first_param
.variable_type
).unresolved_symbol
);
2852 if (parent
!= null && (parent is Struct
|| parent is ObjectTypeSymbol
|| parent is Namespace
)
2853 && cname
.has_prefix (parent
.get_lower_case_cprefix ())) {
2855 var new_name
= method
.name
.substring (parent
.get_lower_case_cprefix().length
- ns_cprefix
.length
);
2856 if (parent
.scope
.lookup (new_name
) == null) {
2857 method
.name
= new_name
;
2858 method
.get_parameters().remove_at (0);
2859 method
.binding
= MemberBinding
.INSTANCE
;
2860 add_symbol_to_container (parent
, method
);
2862 ns
.add_method (method
);
2870 find_static_method_parent (cname
, ns
, ref parent
, ref match
, 1.0/cname
.length
);
2871 var new_name
= method
.name
.substring (parent
.get_lower_case_cprefix().length
- ns_cprefix
.length
);
2872 if (parent
.scope
.lookup (new_name
) == null) {
2873 method
.name
= new_name
;
2874 add_symbol_to_container (parent
, method
);
2876 ns
.add_method (method
);
2882 /* Hash and equal functions */
2884 static uint unresolved_symbol_hash (void *ptr
) {
2885 var sym
= (UnresolvedSymbol
) ptr
;
2886 var builder
= new
StringBuilder ();
2887 while (sym
!= null) {
2888 builder
.append (sym
.name
);
2891 return builder
.str
.hash ();
2894 static bool unresolved_symbol_equal (void *ptr1
, void *ptr2
) {
2895 var sym1
= (UnresolvedSymbol
) ptr1
;
2896 var sym2
= (UnresolvedSymbol
) ptr2
;
2897 while (sym1
!= sym2
) {
2898 if (sym1
== null || sym2
== null) {
2901 if (sym1
.name
!= sym2
.name
) {