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
36 * Best hacking practices:
37 * - Keep GIR parsing bloat-free, it must contain the logic
38 * - Prefer being clean / short over performance
39 * - Try to make things common as much as possible
40 * - Prefer replace/merge after parse rather than a bunch of if-then-else and hardcoding
41 * - Prefer postprocessing over hardcoding the parser
43 public class Vala
.GirParser
: CodeVisitor
{
70 public static ArgumentType?
from_string (string name
) {
71 var enum_class
= (EnumClass
) typeof(ArgumentType
).class_ref ();
72 var nick
= name
.replace ("_", "-");
73 unowned GLib
.EnumValue? enum_value
= enum_class
.get_value_by_nick (nick
);
74 if (enum_value
!= null) {
75 ArgumentType value
= (ArgumentType
) enum_value
.value
;
83 public Expression expression
;
84 public SourceReference source_reference
;
86 public bool used
= false;
88 public Argument (Expression expression
, SourceReference? source_reference
= null) {
89 this
.expression
= expression
;
90 this
.source_reference
= source_reference
;
94 class MetadataSet
: Metadata
{
95 public MetadataSet (MetadataType type
) {
99 public void add_sibling (Metadata metadata
) {
100 foreach (var child
in metadata
.children
) {
103 // merge arguments and take precedence
104 foreach (var key
in metadata
.args
.get_keys ()) {
105 args
[key
] = metadata
.args
[key
];
111 private static Metadata _empty
= null;
112 public static Metadata empty
{
114 if (_empty
== null) {
115 _empty
= new
Metadata ("");
121 public string pattern
;
122 public PatternSpec pattern_spec
;
123 public MetadataType type
;
124 public SourceReference source_reference
;
126 public bool used
= false;
127 public Vala
.Map
<ArgumentType
,Argument
> args
= new HashMap
<ArgumentType
,Argument
> ();
128 public ArrayList
<Metadata
> children
= new ArrayList
<Metadata
> ();
130 public Metadata (string pattern
, MetadataType type
= MetadataType
.GENERIC
, SourceReference? source_reference
= null) {
131 this
.pattern
= pattern
;
132 this
.pattern_spec
= new
PatternSpec (pattern
);
134 this
.source_reference
= source_reference
;
137 public void add_child (Metadata metadata
) {
138 children
.add (metadata
);
141 public Metadata?
get_child (string pattern
, MetadataType type
= MetadataType
.GENERIC
) {
142 foreach (var metadata
in children
) {
143 if (metadata
.type
== type
&& metadata
.pattern
== pattern
) {
150 public Metadata
match_child (string name
, MetadataType type
= MetadataType
.GENERIC
) {
151 var result
= Metadata
.empty
;
152 foreach (var metadata
in children
) {
153 if (metadata
.type
== type
&& metadata
.pattern_spec
.match_string (name
)) {
154 metadata
.used
= true;
155 if (result
== Metadata
.empty
) {
159 var ms
= result as MetadataSet
;
162 ms
= new
MetadataSet (type
);
163 ms
.add_sibling (result
);
165 ms
.add_sibling (metadata
);
173 public void add_argument (ArgumentType key
, Argument value
) {
174 args
.set (key
, value
);
177 public bool has_argument (ArgumentType key
) {
178 return args
.contains (key
);
181 public Expression?
get_expression (ArgumentType arg
) {
182 var val
= args
.get (arg
);
185 return val
.expression
;
190 public string?
get_string (ArgumentType arg
) {
191 var lit
= get_expression (arg
) as StringLiteral
;
198 public int get_integer (ArgumentType arg
) {
199 var lit
= get_expression (arg
) as IntegerLiteral
;
201 return lit
.value
.to_int ();
207 public double get_double (ArgumentType arg
) {
208 var expr
= get_expression (arg
);
209 if (expr is RealLiteral
) {
210 var lit
= (RealLiteral
) expr
;
211 return lit
.value
.to_double ();
212 } else if (expr is IntegerLiteral
) {
213 var lit
= (IntegerLiteral
) expr
;
214 return lit
.value
.to_int ();
219 public bool get_bool (ArgumentType arg
) {
220 var lit
= get_expression (arg
) as BooleanLiteral
;
227 public SourceReference?
get_source_reference (ArgumentType arg
) {
228 var val
= args
.get (arg
);
230 return val
.source_reference
;
236 class MetadataParser
{
239 * metadata ::= [ rule [ '\n' relativerule ]* ]
240 * rule ::= pattern ' ' [ args ]
241 * relativerule ::= [ access ] rule
242 * pattern ::= identifier [ access identifier ]*
243 * access ::= '.' | ':' | '::'
245 private Metadata tree
= new
Metadata ("");
246 private Scanner scanner
;
247 private SourceLocation begin
;
248 private SourceLocation end
;
249 private SourceLocation old_end
;
250 private TokenType current
;
251 private Metadata parent_metadata
;
253 public MetadataParser () {
257 SourceReference
get_current_src () {
258 return new
SourceReference (scanner
.source_file
, begin
.line
, begin
.column
, end
.line
, end
.column
);
261 SourceReference
get_src (SourceLocation begin
) {
262 return new
SourceReference (scanner
.source_file
, begin
.line
, begin
.column
, end
.line
, end
.column
);
265 public Metadata
parse_metadata (SourceFile metadata_file
) {
266 scanner
= new
Scanner (metadata_file
);
268 while (current
!= TokenType
.EOF
) {
269 if (!parse_rule ()) {
270 return Metadata
.empty
;
278 current
= scanner
.read_token (out begin
, out end
);
283 return old_end
.pos
!= begin
.pos
;
286 bool has_newline () {
287 return old_end
.line
!= begin
.line
;
290 string get_string () {
291 return ((string) begin
.pos
).ndup ((end
.pos
- begin
.pos
));
294 MetadataType?
parse_metadata_access () {
298 return MetadataType
.GENERIC
;
299 case TokenType
.COLON
:
300 if (next () == TokenType
.COLON
) {
302 return MetadataType
.SIGNAL
;
304 return MetadataType
.PROPERTY
;
310 string?
parse_identifier (out SourceReference source_reference
, bool is_glob
) {
311 var begin
= this
.begin
;
312 var builder
= new
StringBuilder ();
314 if (is_glob
&& current
== TokenType
.STAR
) {
315 builder
.append_c ('*');
319 case TokenType
.IDENTIFIER
:
320 case TokenType
.UNOWNED
:
321 case TokenType
.OWNED
:
324 case TokenType
.DEFAULT
:
333 builder
.append (str
);
335 source_reference
= get_src (begin
);
337 } while (!has_space ());
339 if (builder
.str
== "") {
341 Report
.error (get_src (begin
), "expected pattern");
343 Report
.error (get_src (begin
), "expected identifier");
350 Metadata?
parse_pattern () {
352 bool is_relative
= false;
353 MetadataType? type
= MetadataType
.GENERIC
;
354 if (current
== TokenType
.IDENTIFIER
|| current
== TokenType
.STAR
) {
356 parent_metadata
= tree
;
359 type
= parse_metadata_access ();
364 Report
.error (get_current_src (), "expected pattern, `.', `:' or `::'");
368 if (parent_metadata
== null) {
369 Report
.error (get_current_src (), "cannot determinate parent metadata");
374 var pattern
= parse_identifier (out src
, true);
375 if (pattern
== null) {
378 metadata
= parent_metadata
.get_child (pattern
, type
);
379 if (metadata
== null) {
380 metadata
= new
Metadata (pattern
, type
, src
);
381 parent_metadata
.add_child (metadata
);
384 while (current
!= TokenType
.EOF
&& !has_space ()) {
385 type
= parse_metadata_access ();
387 Report
.error (get_current_src (), "expected `.', `:' or `::'");
391 pattern
= parse_identifier (out src
, true);
392 if (pattern
== null) {
395 var child
= metadata
.get_child (pattern
, type
);
397 child
= new
Metadata (pattern
, type
, src
);
398 metadata
.add_child (child
);
403 parent_metadata
= metadata
;
409 Expression?
parse_literal () {
410 var src
= get_current_src ();
411 Expression expr
= null;
414 expr
= new
BooleanLiteral (true, src
);
416 case TokenType
.FALSE
:
417 expr
= new
BooleanLiteral (false, src
);
419 case TokenType
.INTEGER_LITERAL
:
420 expr
= new
IntegerLiteral (get_string (), src
);
422 case TokenType
.REAL_LITERAL
:
423 expr
= new
RealLiteral (get_string (), src
);
425 case TokenType
.STRING_LITERAL
:
426 expr
= new
StringLiteral (get_string (), src
);
429 Report
.error (src
, "expected literal");
436 bool parse_args (Metadata metadata
) {
437 while (current
!= TokenType
.EOF
&& has_space () && !has_newline ()) {
439 var id
= parse_identifier (out src
, false);
443 var arg_type
= ArgumentType
.from_string (id
);
444 if (arg_type
== null) {
445 Report
.error (src
, "unknown argument");
449 if (current
!= TokenType
.ASSIGN
) {
451 metadata
.add_argument (arg_type
, new
Argument (new
BooleanLiteral (true, src
), src
));
456 Expression expr
= parse_literal ();
460 metadata
.add_argument (arg_type
, new
Argument (expr
, src
));
468 var metadata
= parse_pattern ();
469 if (metadata
== null) {
473 if (current
== TokenType
.EOF
|| old_end
.line
!= end
.line
) {
477 return parse_args (metadata
);
482 public Symbol symbol
;
483 public Metadata metadata
;
486 class CallbackScope
{
487 public Namespace parent_namespace
;
488 public UnresolvedSymbol gtype_struct_for
;
493 public DataType base_type
;
494 public Namespace parent_namespace
;
495 public SourceReference source_reference
;
498 static GLib
.Regex type_from_string_regex
;
505 SourceFile current_source_file
;
506 Namespace current_namespace
;
507 string current_gtype_struct_for
;
508 SourceLocation begin
;
510 MarkupTokenType current_token
;
512 string[] cheader_filenames
;
514 ArrayList
<Metadata
> metadata_stack
;
517 HashMap
<string,ArrayList
<SymbolInfo
>> current_symbols_info
;
519 HashMap
<UnresolvedSymbol
,Symbol
> unresolved_symbols_map
= new HashMap
<UnresolvedSymbol
,Symbol
> (unresolved_symbol_hash
, unresolved_symbol_equal
);
520 HashMap
<Symbol
,Symbol
> concrete_symbols_map
= new HashMap
<Symbol
,Symbol
> ();
522 ArrayList
<UnresolvedSymbol
> unresolved_gir_symbols
= new ArrayList
<UnresolvedSymbol
> ();
523 HashMap
<UnresolvedSymbol
,ArrayList
<Symbol
>> symbol_reparent_map
= new HashMap
<UnresolvedSymbol
,ArrayList
<Symbol
>> (unresolved_symbol_hash
, unresolved_symbol_equal
);
524 HashMap
<Namespace
,ArrayList
<Method
>> namespace_methods
= new HashMap
<Namespace
,ArrayList
<Method
>> ();
525 HashMap
<CallbackScope
,ArrayList
<Delegate
>> gtype_callbacks
= new HashMap
<CallbackScope
,ArrayList
<Delegate
>> (callback_scope_hash
, callback_scope_equal
);
526 ArrayList
<Alias
> aliases
= new ArrayList
<Alias
> ();
529 * Parses all .gir source files in the specified code
530 * context and builds a code tree.
532 * @param context a code context
534 public void parse (CodeContext context
) {
535 this
.context
= context
;
536 glib_ns
= context
.root
.scope
.lookup ("GLib") as Namespace
;
537 context
.accept (this
);
539 resolve_gir_symbols ();
541 postprocess_reparenting ();
542 postprocess_gtype_callbacks ();
543 postprocess_aliases ();
544 postprocess_namespace_methods ();
547 public override void visit_source_file (SourceFile source_file
) {
548 // collect gir namespaces
549 foreach (var node
in source_file
.get_nodes ()) {
550 if (node is Namespace
) {
551 var ns
= (Namespace
) node
;
552 var gir_namespace
= source_file
.gir_namespace
;
553 if (gir_namespace
== null) {
554 var a
= ns
.get_attribute ("CCode");
555 if (a
!= null && a
.has_argument ("gir_namespace")) {
556 gir_namespace
= a
.get_string ("gir_namespace");
559 if (gir_namespace
!= null && gir_namespace
!= ns
.name
) {
560 var map_from
= new
UnresolvedSymbol (null, gir_namespace
);
561 set_symbol_mapping (map_from
, ns
);
567 if (source_file
.filename
.has_suffix (".gir")) {
568 parse_file (source_file
);
572 public void parse_file (SourceFile source_file
) {
574 metadata_stack
= new ArrayList
<Metadata
> ();
575 metadata
= Metadata
.empty
;
576 string metadata_filename
= "%s.metadata".printf (source_file
.filename
.ndup (source_file
.filename
.length
- ".gir".length
));
577 if (FileUtils
.test (metadata_filename
, FileTest
.EXISTS
)) {
578 var metadata_parser
= new
MetadataParser ();
579 var metadata_file
= new
SourceFile (context
, source_file
.file_type
, metadata_filename
);
580 context
.add_source_file (metadata_file
);
581 metadata
= metadata_parser
.parse_metadata (metadata_file
);
584 this
.current_source_file
= source_file
;
585 reader
= new
MarkupReader (source_file
.filename
);
594 report_unused_metadata (metadata
);
597 this
.current_source_file
= null;
601 current_token
= reader
.read_token (out begin
, out end
);
603 // Skip *all* <doc> tags
604 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "doc")
608 void start_element (string name
) {
609 if (current_token
!= MarkupTokenType
.START_ELEMENT
|| reader
.name
!= name
) {
611 Report
.error (get_current_src (), "expected start element of `%s'".printf (name
));
615 void end_element (string name
) {
616 if (current_token
!= MarkupTokenType
.END_ELEMENT
|| reader
.name
!= name
) {
618 Report
.error (get_current_src (), "expected end element of `%s'".printf (name
));
623 SourceReference
get_current_src () {
624 return new
SourceReference (this
.current_source_file
, begin
.line
, begin
.column
, end
.line
, end
.column
);
627 const string GIR_VERSION
= "1.2";
629 void add_symbol_to_container (Symbol container
, Symbol sym
) {
630 if (container is Class
) {
631 unowned Class cl
= (Class
) container
;
634 cl
.add_class ((Class
) sym
);
635 } else if (sym is Constant
) {
636 cl
.add_constant ((Constant
) sym
);
637 } else if (sym is Enum
) {
638 cl
.add_enum ((Enum
) sym
);
639 } else if (sym is Field
) {
640 cl
.add_field ((Field
) sym
);
641 } else if (sym is Method
) {
642 cl
.add_method ((Method
) sym
);
643 } else if (sym is Property
) {
644 cl
.add_property ((Property
) sym
);
645 } else if (sym is Signal
) {
646 cl
.add_signal ((Signal
) sym
);
647 } else if (sym is Struct
) {
648 cl
.add_struct ((Struct
) sym
);
650 } else if (container is Enum
) {
651 unowned Enum en
= (Enum
) container
;
653 if (sym is EnumValue
) {
654 en
.add_value ((EnumValue
) sym
);
655 } else if (sym is Constant
) {
656 en
.add_constant ((Constant
) sym
);
657 } else if (sym is Method
) {
658 en
.add_method ((Method
) sym
);
660 } else if (container is Interface
) {
661 unowned Interface iface
= (Interface
) container
;
664 iface
.add_class ((Class
) sym
);
665 } else if (sym is Constant
) {
666 iface
.add_constant ((Constant
) sym
);
667 } else if (sym is Enum
) {
668 iface
.add_enum ((Enum
) sym
);
669 } else if (sym is Field
) {
670 iface
.add_field ((Field
) sym
);
671 } else if (sym is Method
) {
672 iface
.add_method ((Method
) sym
);
673 } else if (sym is Property
) {
674 iface
.add_property ((Property
) sym
);
675 } else if (sym is Signal
) {
676 iface
.add_signal ((Signal
) sym
);
677 } else if (sym is Struct
) {
678 iface
.add_struct ((Struct
) sym
);
680 } else if (container is Namespace
) {
681 unowned Namespace ns
= (Namespace
) container
;
683 if (sym is Namespace
) {
684 ns
.add_namespace ((Namespace
) sym
);
685 } else if (sym is Class
) {
686 ns
.add_class ((Class
) sym
);
687 } else if (sym is Constant
) {
688 ns
.add_constant ((Constant
) sym
);
689 } else if (sym is Delegate
) {
690 ns
.add_delegate ((Delegate
) sym
);
691 } else if (sym is Enum
) {
692 ns
.add_enum ((Enum
) sym
);
693 } else if (sym is ErrorDomain
) {
694 ns
.add_error_domain ((ErrorDomain
) sym
);
695 } else if (sym is Field
) {
696 ns
.add_field ((Field
) sym
);
697 } else if (sym is Interface
) {
698 ns
.add_interface ((Interface
) sym
);
699 } else if (sym is Method
) {
700 ns
.add_method ((Method
) sym
);
701 } else if (sym is Namespace
) {
702 ns
.add_namespace ((Namespace
) sym
);
703 } else if (sym is Struct
) {
704 ns
.add_struct ((Struct
) sym
);
706 } else if (container is Struct
) {
707 unowned Struct st
= (Struct
) container
;
709 if (sym is Constant
) {
710 st
.add_constant ((Constant
) sym
);
711 } else if (sym is Field
) {
712 st
.add_field ((Field
) sym
);
713 } else if (sym is Method
) {
714 st
.add_method ((Method
) sym
);
715 } else if (sym is Property
) {
716 st
.add_property ((Property
) sym
);
719 Report
.error (sym
.source_reference
, "impossible to add to container `%s'".printf (container
.name
));
723 UnresolvedSymbol?
parse_symbol_from_string (string symbol_string
, SourceReference? source_reference
= null) {
724 UnresolvedSymbol? sym
= null;
725 foreach (unowned
string s
in symbol_string
.split (".")) {
726 sym
= new
UnresolvedSymbol (sym
, s
, source_reference
);
729 Report
.error (source_reference
, "a symbol must be specified");
734 UnresolvedSymbol
get_unresolved_symbol (Symbol symbol
) {
735 if (symbol is UnresolvedSymbol
) {
736 return (UnresolvedSymbol
) symbol
;
738 var sym
= new
UnresolvedSymbol (null, symbol
.name
);
740 var cur
= symbol
.parent_node as Symbol
;
741 while (cur
!= null && cur
.name
!= null) {
742 sym
= new
UnresolvedSymbol (sym
, cur
.name
);
743 cur
= cur
.parent_node as Symbol
;
748 void set_symbol_mapping (Symbol map_from
, Symbol map_to
) {
749 // last mapping is the most up-to-date
750 if (map_from is UnresolvedSymbol
) {
751 unresolved_symbols_map
[(UnresolvedSymbol
) map_from
] = map_to
;
753 concrete_symbols_map
[map_from
] = map_to
;
757 void assume_parameter_names (Signal sig
, Symbol sym
) {
758 Iterator
<Parameter
> iter
;
760 iter
= ((Method
) sym
).get_parameters ().iterator ();
762 iter
= ((Delegate
) sym
).get_parameters ().iterator ();
764 foreach (var param
in sig
.get_parameters ()) {
766 // unreachable for valid GIR
769 param
.name
= iter
.get ().name
;
773 SymbolInfo?
add_symbol_info (Symbol symbol
) {
774 var name
= symbol
.name
;
775 if (symbol is CreationMethod
&& name
== null) {
779 var info
= new
SymbolInfo ();
780 info
.symbol
= symbol
;
781 info
.metadata
= metadata
;
782 var colliding
= current_symbols_info
[name
];
783 if (colliding
== null) {
784 colliding
= new ArrayList
<SymbolInfo
> ();
785 current_symbols_info
[name
] = colliding
;
787 colliding
.add (info
);
791 void merge (SymbolInfo info
, ArrayList
<SymbolInfo
> colliding
, ArrayList
<SymbolInfo
> merged
) {
792 if (info
.symbol is Property
) {
793 foreach (var cinfo
in colliding
) {
794 var sym
= cinfo
.symbol
;
795 if (sym is Signal
|| sym is Field
) {
796 // properties take precedence
798 } else if (sym is Method
) {
799 // assume method is getter
803 var getter_name
= "get_%s".printf (info
.symbol
.name
);
804 if (current_symbols_info
.contains (getter_name
)) {
805 ((Property
) info
.symbol
).no_accessor_method
= false;
807 } else if (info
.symbol is Signal
) {
808 var sig
= (Signal
) info
.symbol
;
809 foreach (var cinfo
in colliding
) {
810 var sym
= cinfo
.symbol
;
812 var method
= (Method
) sym
;
813 if (method
.is_virtual
) {
814 sig
.is_virtual
= true;
816 sig
.has_emitter
= true;
818 assume_parameter_names (sig
, method
);
820 } else if (sym is Field
) {
824 } else if (info
.symbol is Method
&& !(info
.symbol is CreationMethod
)) {
825 var method
= (Method
) info
.symbol
;
826 foreach (var cinfo
in colliding
) {
827 var sym
= cinfo
.symbol
;
828 if (sym
!= method
&& method
.is_virtual
&& sym is Method
) {
829 // assume method is wrapper
833 } else if (info
.symbol is Field
) {
834 foreach (var cinfo
in colliding
) {
835 var sym
= cinfo
.symbol
;
837 // assume method is getter
842 var field
= (Field
) info
.symbol
;
843 if (field
.variable_type is ArrayType
) {
844 SymbolInfo array_length
= null;
845 if (current_symbols_info
.contains ("n_%s".printf (field
.name
))) {
846 array_length
= current_symbols_info
.get ("n_%s".printf (field
.name
)).get (0);
847 } else if (current_symbols_info
.contains ("%s_length".printf (field
.name
))) {
848 array_length
= current_symbols_info
.get ("%s_length".printf (field
.name
)).get (0);
850 if (array_length
!= null) {
852 field
.set_array_length_cname (array_length
.symbol
.name
);
853 field
.no_array_length
= false;
854 merged
.add (array_length
);
860 void postprocess_symbol (Symbol symbol
, Metadata metadata
) {
862 symbol
.replacement
= metadata
.get_string (ArgumentType
.REPLACEMENT
);
863 symbol
.deprecated_since
= element_get_string ("deprecated-version", ArgumentType
.DEPRECATED_SINCE
);
864 symbol
.deprecated
= metadata
.get_bool (ArgumentType
.DEPRECATED
) || symbol
.replacement
!= null || symbol
.deprecated_since
!= null;
866 // mark to be reparented
867 if (metadata
.has_argument (ArgumentType
.PARENT
)) {
868 var target_symbol
= parse_symbol_from_string (metadata
.get_string (ArgumentType
.PARENT
), metadata
.get_source_reference (ArgumentType
.PARENT
));
869 var reparent_list
= symbol_reparent_map
[target_symbol
];
870 if (reparent_list
== null) {
871 reparent_list
= new ArrayList
<Symbol
>();
872 symbol_reparent_map
[target_symbol
] = reparent_list
;
874 reparent_list
.add (symbol
);
876 // if referenceable, map unresolved references to point to the new place
877 if (symbol is Namespace
|| symbol is TypeSymbol
) {
878 set_symbol_mapping (symbol
, new
UnresolvedSymbol (target_symbol
, symbol
.name
));
883 void merge_add_process (Symbol container
) {
884 var merged
= new ArrayList
<SymbolInfo
> ();
885 foreach (var name
in current_symbols_info
.get_keys ()) {
886 var colliding
= current_symbols_info
[name
];
887 foreach (var info
in colliding
) {
888 merge (info
, colliding
, merged
);
892 foreach (var infos
in current_symbols_info
.get_values ()) {
893 foreach (var info
in infos
) {
894 if (merged
.contains (info
) || info
.metadata
.get_bool (ArgumentType
.HIDDEN
)) {
897 if (!info
.metadata
.has_argument (ArgumentType
.PARENT
)) {
898 add_symbol_to_container (container
, info
.symbol
);
900 postprocess_symbol (info
.symbol
, info
.metadata
);
905 Metadata
get_current_metadata () {
906 var name
= reader
.name
;
907 var child_name
= reader
.get_attribute ("name");
908 if (child_name
== null) {
909 return Metadata
.empty
;
912 var type
= MetadataType
.GENERIC
;
913 if (name
== "glib:signal") {
914 type
= MetadataType
.SIGNAL
;
915 } else if (name
== "property") {
916 type
= MetadataType
.PROPERTY
;
919 return metadata
.match_child (child_name
, type
);
922 bool push_metadata () {
924 if (reader
.get_attribute ("introspectable") == "0") {
927 var new_metadata
= get_current_metadata ();
928 if (new_metadata
.get_bool (ArgumentType
.SKIP
)) {
932 metadata_stack
.add (metadata
);
933 metadata
= new_metadata
;
937 void pop_metadata () {
938 metadata
= metadata_stack
[metadata_stack
.size
- 1];
939 metadata_stack
.remove_at (metadata_stack
.size
- 1);
942 bool parse_type_arguments_from_string (DataType parent_type
, string type_arguments
, SourceReference? source_reference
= null) {
943 int type_arguments_length
= (int) type_arguments
.length
;
944 GLib
.StringBuilder current
= new GLib
.StringBuilder
.sized (type_arguments_length
);
947 for (var c
= 0 ; c
< type_arguments_length
; c
++) {
948 if (type_arguments
[c
] == '<' || type_arguments
[c
] == '[') {
950 current
.append_unichar (type_arguments
[c
]);
951 } else if (type_arguments
[c
] == '>' || type_arguments
[c
] == ']') {
953 current
.append_unichar (type_arguments
[c
]);
954 } else if (type_arguments
[c
] == ',') {
956 var dt
= parse_type_from_string (current
.str
, true, source_reference
);
960 parent_type
.add_type_argument (dt
);
963 current
.append_unichar (type_arguments
[c
]);
966 current
.append_unichar (type_arguments
[c
]);
970 var dt
= parse_type_from_string (current
.str
, true, source_reference
);
974 parent_type
.add_type_argument (dt
);
979 DataType?
parse_type_from_string (string type_string
, bool owned_by_default
, SourceReference? source_reference
= null) {
980 if (type_from_string_regex
== null) {
982 type_from_string_regex
= new GLib
.Regex ("^(?:(owned|unowned|weak) +)?([0-9a-zA-Z_\\.]+)(?:<(.+)>)?(\\*+)?(\\[(,*)?\\])?(\\?)?$", GLib
.RegexCompileFlags
.ANCHORED
| GLib
.RegexCompileFlags
.DOLLAR_ENDONLY
| GLib
.RegexCompileFlags
.OPTIMIZE
);
983 } catch (GLib
.RegexError e
) {
984 GLib
.error ("Unable to compile regex: %s", e
.message
);
988 GLib
.MatchInfo match
;
989 if (!type_from_string_regex
.match (type_string
, 0, out match
)) {
990 Report
.error (source_reference
, "unable to parse type");
994 DataType? type
= null;
996 var ownership_data
= match
.fetch (1);
997 var type_name
= match
.fetch (2);
998 var type_arguments_data
= match
.fetch (3);
999 var pointers_data
= match
.fetch (4);
1000 var array_data
= match
.fetch (5);
1001 var nullable_data
= match
.fetch (6);
1003 var nullable
= nullable_data
!= null && nullable_data
.length
> 0;
1005 if (ownership_data
== null && type_name
== "void") {
1006 if (array_data
== null && !nullable
) {
1007 type
= new
VoidType (source_reference
);
1008 if (pointers_data
!= null) {
1009 for (int i
=0; i
< pointers_data
.length
; i
++) {
1010 type
= new
PointerType (type
);
1015 Report
.error (source_reference
, "invalid void type");
1020 bool value_owned
= owned_by_default
;
1022 if (ownership_data
== "owned") {
1023 if (owned_by_default
) {
1024 Report
.error (source_reference
, "unexpected `owned' keyword");
1028 } else if (ownership_data
== "unowned") {
1029 if (owned_by_default
) {
1032 Report
.error (source_reference
, "unexpected `unowned' keyword");
1037 var sym
= parse_symbol_from_string (type_name
, source_reference
);
1041 type
= new UnresolvedType
.from_symbol (sym
, source_reference
);
1043 if (type_arguments_data
!= null && type_arguments_data
.length
> 0) {
1044 if (!parse_type_arguments_from_string (type
, type_arguments_data
, source_reference
)) {
1049 if (pointers_data
!= null) {
1050 for (int i
=0; i
< pointers_data
.length
; i
++) {
1051 type
= new
PointerType (type
);
1055 if (array_data
!= null) {
1056 type
= new
ArrayType (type
, (int) array_data
.length
+ 1, source_reference
);
1059 type
.nullable
= nullable
;
1060 type
.value_owned
= value_owned
;
1064 string?
element_get_string (string attribute_name
, ArgumentType arg_type
) {
1065 var str
= metadata
.get_string (arg_type
);
1067 str
= reader
.get_attribute (attribute_name
);
1072 DataType?
element_get_type (DataType orig_type
, bool owned_by_default
, out bool changed
= null) {
1073 if (&changed
!= null) {
1077 var type
= orig_type
;
1079 if (metadata
.has_argument (ArgumentType
.TYPE
)) {
1080 var new_type
= parse_type_from_string (metadata
.get_string (ArgumentType
.TYPE
), owned_by_default
, metadata
.get_source_reference (ArgumentType
.TYPE
));
1081 if (&changed
!= null) {
1087 if (metadata
.has_argument (ArgumentType
.TYPE_ARGUMENTS
)) {
1088 parse_type_arguments_from_string (type
, metadata
.get_string (ArgumentType
.TYPE_ARGUMENTS
), metadata
.get_source_reference (ArgumentType
.TYPE_ARGUMENTS
));
1089 if (&changed
!= null) {
1094 if (type is VoidType
) {
1098 if (metadata
.get_bool (ArgumentType
.ARRAY
)) {
1099 type
= new
ArrayType (type
, 1, type
.source_reference
);
1100 if (&changed
!= null) {
1105 if (owned_by_default
) {
1106 if (metadata
.has_argument (ArgumentType
.UNOWNED
)) {
1107 type
.value_owned
= !metadata
.get_bool (ArgumentType
.UNOWNED
);
1110 if (metadata
.has_argument (ArgumentType
.OWNED
)) {
1111 type
.value_owned
= metadata
.get_bool (ArgumentType
.OWNED
);
1114 if (metadata
.has_argument (ArgumentType
.NULLABLE
)) {
1115 type
.nullable
= metadata
.get_bool (ArgumentType
.NULLABLE
);
1121 string?
element_get_name (string attribute_name
= "name", ArgumentType arg_type
= ArgumentType
.NAME
) {
1122 var name
= reader
.get_attribute (attribute_name
);
1123 var pattern
= metadata
.get_string (arg_type
);
1124 if (pattern
!= null) {
1126 var regex
= new
Regex (pattern
, RegexCompileFlags
.ANCHORED
, RegexMatchFlags
.ANCHORED
);
1127 GLib
.MatchInfo match
;
1128 if (!regex
.match (name
, 0, out match
)) {
1131 var matched
= match
.fetch (1);
1132 if (matched
!= null && matched
.length
> 0) {
1145 void parse_repository () {
1146 start_element ("repository");
1147 if (reader
.get_attribute ("version") != GIR_VERSION
) {
1148 Report
.error (get_current_src (), "unsupported GIR version %s (supported: %s)".printf (reader
.get_attribute ("version"), GIR_VERSION
));
1152 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1153 if (reader
.name
== "namespace") {
1154 var ns
= parse_namespace ();
1156 context
.root
.add_namespace (ns
);
1158 } else if (reader
.name
== "include") {
1160 } else if (reader
.name
== "package") {
1161 var pkg
= parse_package ();
1162 if (context
.has_package (pkg
)) {
1163 // package already provided elsewhere, stop parsing this GIR
1166 context
.add_package (pkg
);
1168 } else if (reader
.name
== "c:include") {
1172 Report
.error (get_current_src (), "unknown child element `%s' in `repository'".printf (reader
.name
));
1176 end_element ("repository");
1179 void parse_include () {
1180 start_element ("include");
1181 var pkg
= reader
.get_attribute ("name");
1182 var version
= reader
.get_attribute ("version");
1183 if (version
!= null) {
1184 pkg
= "%s-%s".printf (pkg
, version
);
1186 // add the package to the queue
1187 context
.add_external_package (pkg
);
1189 end_element ("include");
1192 string parse_package () {
1193 start_element ("package");
1194 var pkg
= reader
.get_attribute ("name");
1196 end_element ("package");
1200 void parse_c_include () {
1201 start_element ("c:include");
1202 cheader_filenames
+= reader
.get_attribute ("name");
1204 end_element ("c:include");
1207 void skip_element () {
1212 if (current_token
== MarkupTokenType
.START_ELEMENT
) {
1214 } else if (current_token
== MarkupTokenType
.END_ELEMENT
) {
1216 } else if (current_token
== MarkupTokenType
.EOF
) {
1217 Report
.error (get_current_src (), "unexpected end of file");
1224 Namespace?
parse_namespace () {
1225 start_element ("namespace");
1227 bool new_namespace
= false;
1228 string? cprefix
= reader
.get_attribute ("c:identifier-prefixes");
1229 string namespace_name
= cprefix
;
1230 string gir_namespace
= reader
.get_attribute ("name");
1231 string gir_version
= reader
.get_attribute ("version");
1232 if (namespace_name
== null) {
1233 namespace_name
= gir_namespace
;
1235 current_source_file
.gir_namespace
= gir_namespace
;
1236 current_source_file
.gir_version
= gir_version
;
1238 var ns_metadata
= metadata
.match_child (gir_namespace
);
1239 if (ns_metadata
.has_argument (ArgumentType
.NAME
)) {
1240 namespace_name
= ns_metadata
.get_string (ArgumentType
.NAME
);
1243 var ns
= context
.root
.scope
.lookup (namespace_name
) as Namespace
;
1245 ns
= new
Namespace (namespace_name
, get_current_src ());
1246 new_namespace
= true;
1248 if (ns
.external_package
) {
1249 ns
.attributes
= null;
1250 ns
.source_reference
= get_current_src ();
1254 if (gir_namespace
!= ns
.name
) {
1255 set_symbol_mapping (new
UnresolvedSymbol (null, gir_namespace
), ns
);
1258 var old_namespace
= current_namespace
;
1259 current_namespace
= ns
;
1261 if (cprefix
!= null) {
1262 ns
.add_cprefix (cprefix
);
1263 ns
.set_lower_case_cprefix (Symbol
.camel_case_to_lower_case (cprefix
) + "_");
1266 if (ns_metadata
.has_argument (ArgumentType
.CHEADER_FILENAME
)) {
1267 var val
= ns_metadata
.get_string (ArgumentType
.CHEADER_FILENAME
);
1268 foreach (string filename
in val
.split (",")) {
1269 ns
.add_cheader_filename (filename
);
1272 foreach (string c_header
in cheader_filenames
) {
1273 ns
.add_cheader_filename (c_header
);
1278 var current_namespace_methods
= namespace_methods
[ns
];
1279 if (current_namespace_methods
== null) {
1280 current_namespace_methods
= new ArrayList
<Method
> ();
1281 namespace_methods
[ns
] = current_namespace_methods
;
1283 var old_symbols_info
= current_symbols_info
;
1284 current_symbols_info
= new HashMap
<string,ArrayList
<SymbolInfo
>> (str_hash
, str_equal
);
1285 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1286 if (!push_metadata ()) {
1291 if (reader
.name
== "alias") {
1292 var alias
= parse_alias ();
1293 aliases
.add (alias
);
1294 } else if (reader
.name
== "enumeration") {
1295 if (reader
.get_attribute ("glib:error-quark") != null) {
1296 add_symbol_info (parse_error_domain ());
1298 add_symbol_info (parse_enumeration ());
1300 } else if (reader
.name
== "bitfield") {
1301 add_symbol_info (parse_bitfield ());
1302 } else if (reader
.name
== "function") {
1303 current_namespace_methods
.add (parse_method ("function"));
1304 } else if (reader
.name
== "callback") {
1305 add_symbol_info (parse_callback ());
1306 } else if (reader
.name
== "record") {
1307 if (reader
.get_attribute ("glib:get-type") != null) {
1308 add_symbol_info (parse_boxed ());
1310 var record
= parse_record ();
1311 if (record
!= null) {
1312 add_symbol_info (record
);
1315 } else if (reader
.name
== "class") {
1316 add_symbol_info (parse_class ());
1317 } else if (reader
.name
== "interface") {
1318 add_symbol_info (parse_interface ());
1319 } else if (reader
.name
== "glib:boxed") {
1320 add_symbol_info (parse_boxed ());
1321 } else if (reader
.name
== "union") {
1322 add_symbol_info (parse_union ());
1323 } else if (reader
.name
== "constant") {
1324 add_symbol_info (parse_constant ());
1327 Report
.error (get_current_src (), "unknown child element `%s' in `namespace'".printf (reader
.name
));
1333 end_element ("namespace");
1335 merge_add_process (ns
);
1336 current_symbols_info
= old_symbols_info
;
1337 current_namespace
= old_namespace
;
1339 if (!new_namespace
) {
1346 Alias
parse_alias () {
1347 // alias has no type information
1348 start_element ("alias");
1349 var alias
= new
Alias ();
1350 alias
.source_reference
= get_current_src ();
1351 alias
.name
= reader
.get_attribute ("name");
1352 alias
.base_type
= element_get_type (parse_type_from_gir_name (reader
.get_attribute ("target")), true);
1353 alias
.parent_namespace
= current_namespace
;
1355 end_element ("alias");
1359 private void calculate_common_prefix (ref string common_prefix
, string cname
) {
1360 if (common_prefix
== null) {
1361 common_prefix
= cname
;
1362 while (common_prefix
.length
> 0 && !common_prefix
.has_suffix ("_")) {
1363 // FIXME: could easily be made faster
1364 common_prefix
= common_prefix
.ndup (common_prefix
.length
- 1);
1367 while (!cname
.has_prefix (common_prefix
)) {
1368 common_prefix
= common_prefix
.ndup (common_prefix
.length
- 1);
1371 while (common_prefix
.length
> 0 && (!common_prefix
.has_suffix ("_") ||
1372 (cname
.offset (common_prefix
.length
).get_char ().isdigit ()) && (cname
.length
- common_prefix
.length
) <= 1)) {
1373 // enum values may not consist solely of digits
1374 common_prefix
= common_prefix
.ndup (common_prefix
.length
- 1);
1378 Enum
parse_enumeration () {
1379 start_element ("enumeration");
1380 var en
= new
Enum (reader
.get_attribute ("name"), get_current_src ());
1381 en
.access
= SymbolAccessibility
.PUBLIC
;
1383 string enum_cname
= reader
.get_attribute ("c:type");
1384 if (enum_cname
!= null) {
1385 en
.set_cname (enum_cname
);
1390 string common_prefix
= null;
1392 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1393 if (!push_metadata ()) {
1398 if (reader
.name
== "member") {
1399 var ev
= parse_enumeration_member ();
1401 calculate_common_prefix (ref common_prefix
, ev
.get_cname ());
1404 Report
.error (get_current_src (), "unknown child element `%s' in `enumaration'".printf (reader
.name
));
1411 en
.set_cprefix (common_prefix
);
1413 end_element ("enumeration");
1417 ErrorDomain
parse_error_domain () {
1418 start_element ("enumeration");
1420 var ed
= new
ErrorDomain (reader
.get_attribute ("name"), get_current_src ());
1421 ed
.access
= SymbolAccessibility
.PUBLIC
;
1423 string enum_cname
= reader
.get_attribute ("c:type");
1424 if (enum_cname
!= null) {
1425 ed
.set_cname (enum_cname
);
1430 string common_prefix
= null;
1432 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1433 if (!push_metadata ()) {
1438 if (reader
.name
== "member") {
1439 ErrorCode ec
= parse_error_member ();
1441 calculate_common_prefix (ref common_prefix
, ec
.get_cname ());
1444 Report
.error (get_current_src (), "unknown child element `%s' in `enumeration'".printf (reader
.name
));
1451 ed
.set_cprefix (common_prefix
);
1453 end_element ("enumeration");
1457 Enum
parse_bitfield () {
1458 start_element ("bitfield");
1459 var en
= new
Enum (reader
.get_attribute ("name"), get_current_src ());
1460 en
.access
= SymbolAccessibility
.PUBLIC
;
1462 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1463 if (!push_metadata ()) {
1468 if (reader
.name
== "member") {
1469 en
.add_value (parse_enumeration_member ());
1472 Report
.error (get_current_src (), "unknown child element `%s' in `bitfield'".printf (reader
.name
));
1478 end_element ("bitfield");
1482 EnumValue
parse_enumeration_member () {
1483 start_element ("member");
1484 var ev
= new
EnumValue (reader
.get_attribute ("name").up ().replace ("-", "_"), null, get_current_src ());
1485 ev
.set_cname (reader
.get_attribute ("c:identifier"));
1487 end_element ("member");
1491 ErrorCode
parse_error_member () {
1492 start_element ("member");
1495 string name
= reader
.get_attribute ("name").up ().replace ("-", "_");
1496 string value
= reader
.get_attribute ("value");
1497 if (value
!= null) {
1498 ec
= new ErrorCode
.with_value (name
, new
IntegerLiteral (value
));
1500 ec
= new
ErrorCode (name
);
1504 end_element ("member");
1508 DataType
parse_return_value (out string? ctype
= null) {
1509 start_element ("return-value");
1510 string transfer
= reader
.get_attribute ("transfer-ownership");
1511 string allow_none
= reader
.get_attribute ("allow-none");
1513 var transfer_elements
= transfer
== "full";
1514 var type
= &ctype
!= null ?
parse_type(out ctype
, null, transfer_elements
) : parse_type (null, null, transfer_elements
);
1515 if (transfer
== "full" || transfer
== "container") {
1516 type
.value_owned
= true;
1518 if (allow_none
== "1") {
1519 type
.nullable
= true;
1521 end_element ("return-value");
1525 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) {
1528 if (&array_length_idx
!= null) {
1529 array_length_idx
= -1;
1531 if (&closure_idx
!= null) {
1534 if (&destroy_idx
!= null) {
1538 start_element ("parameter");
1539 string name
= reader
.get_attribute ("name");
1541 name
= default_name
;
1543 string direction
= null;
1544 if (metadata
.has_argument (ArgumentType
.OUT
)) {
1545 if (metadata
.get_bool (ArgumentType
.OUT
)) {
1548 } else if (metadata
.has_argument (ArgumentType
.REF
)) {
1549 if (metadata
.get_bool (ArgumentType
.REF
)) {
1550 direction
= "inout";
1553 direction
= reader
.get_attribute ("direction");
1555 string transfer
= reader
.get_attribute ("transfer-ownership");
1556 string allow_none
= reader
.get_attribute ("allow-none");
1558 if (&scope
!= null) {
1559 scope
= reader
.get_attribute ("scope");
1562 string closure
= reader
.get_attribute ("closure");
1563 string destroy
= reader
.get_attribute ("destroy");
1564 if (closure
!= null && &closure_idx
!= null) {
1565 closure_idx
= closure
.to_int ();
1567 if (destroy
!= null && &destroy_idx
!= null) {
1568 destroy_idx
= destroy
.to_int ();
1572 if (reader
.name
== "varargs") {
1573 start_element ("varargs");
1575 param
= new Parameter
.with_ellipsis (get_current_src ());
1576 end_element ("varargs");
1579 var type
= parse_type (out ctype
, out array_length_idx
, transfer
== "full");
1581 type
= element_get_type (type
, false, out changed
);
1583 // discard ctype, duplicated information
1587 if (type is ArrayType
&& metadata
.has_argument (ArgumentType
.ARRAY_LENGTH_POS
)) {
1588 array_length_idx
= metadata
.get_integer (ArgumentType
.ARRAY_LENGTH_POS
);
1591 if (transfer
== "full" || transfer
== "container" || destroy
!= null) {
1592 type
.value_owned
= true;
1594 if (allow_none
== "1") {
1595 type
.nullable
= true;
1597 param
= new
Parameter (name
, type
, get_current_src ());
1598 param
.ctype
= ctype
;
1599 if (direction
== "out") {
1600 param
.direction
= ParameterDirection
.OUT
;
1601 } else if (direction
== "inout") {
1602 param
.direction
= ParameterDirection
.REF
;
1604 param
.initializer
= metadata
.get_expression (ArgumentType
.DEFAULT
);
1606 end_element ("parameter");
1610 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) {
1611 bool is_array
= false;
1612 string type_name
= reader
.get_attribute ("name");
1614 if (reader
.name
== "array") {
1616 start_element ("array");
1618 if (!(type_name
== "GLib.Array" || type_name
== "GLib.PtrArray")) {
1619 if (reader
.get_attribute ("length") != null
1620 && &array_length_index
!= null) {
1621 array_length_index
= reader
.get_attribute ("length").to_int ();
1624 var element_type
= parse_type ();
1625 end_element ("array");
1626 return new
ArrayType (element_type
, 1, null);
1628 } else if (reader
.name
== "callback"){
1629 var callback = parse_callback ();
1630 return new
DelegateType (callback);
1632 start_element ("type");
1635 if (&ctype
!= null) {
1636 ctype
= reader
.get_attribute("c:type");
1641 if (type_name
== "GLib.PtrArray"
1642 && current_token
== MarkupTokenType
.START_ELEMENT
) {
1643 type_name
= "GLib.GenericArray";
1646 DataType type
= parse_type_from_gir_name (type_name
, out no_array_length
, out array_null_terminated
);
1648 // type arguments / element types
1649 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1650 var element_type
= parse_type ();
1651 element_type
.value_owned
= transfer_elements
;
1652 type
.add_type_argument (element_type
);
1655 end_element (is_array ?
"array" : "type");
1659 DataType
parse_type_from_gir_name (string type_name
, out bool no_array_length
= null, out bool array_null_terminated
= null) {
1660 if (&no_array_length
!= null) {
1661 no_array_length
= false;
1663 if (&array_null_terminated
!= null) {
1664 array_null_terminated
= false;
1668 if (type_name
== "none") {
1669 type
= new
VoidType (get_current_src ());
1670 } else if (type_name
== "gpointer") {
1671 type
= new
PointerType (new
VoidType (get_current_src ()), get_current_src ());
1672 } else if (type_name
== "GObject.Strv") {
1673 type
= new
ArrayType (new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, "string")), 1, get_current_src ());
1674 if (&no_array_length
!= null) {
1675 no_array_length
= true;
1677 if (&array_null_terminated
!= null) {
1678 array_null_terminated
= true;
1681 bool known_type
= true;
1682 if (type_name
== "utf8") {
1683 type_name
= "string";
1684 } else if (type_name
== "gboolean") {
1686 } else if (type_name
== "gchar") {
1688 } else if (type_name
== "gshort") {
1689 type_name
= "short";
1690 } else if (type_name
== "gushort") {
1691 type_name
= "ushort";
1692 } else if (type_name
== "gint") {
1694 } else if (type_name
== "guint") {
1696 } else if (type_name
== "glong") {
1698 } else if (type_name
== "gulong") {
1699 type_name
= "ulong";
1700 } else if (type_name
== "gint8") {
1702 } else if (type_name
== "guint8") {
1703 type_name
= "uint8";
1704 } else if (type_name
== "gint16") {
1705 type_name
= "int16";
1706 } else if (type_name
== "guint16") {
1707 type_name
= "uint16";
1708 } else if (type_name
== "gint32") {
1709 type_name
= "int32";
1710 } else if (type_name
== "guint32") {
1711 type_name
= "uint32";
1712 } else if (type_name
== "gint64") {
1713 type_name
= "int64";
1714 } else if (type_name
== "guint64") {
1715 type_name
= "uint64";
1716 } else if (type_name
== "gfloat") {
1717 type_name
= "float";
1718 } else if (type_name
== "gdouble") {
1719 type_name
= "double";
1720 } else if (type_name
== "filename") {
1721 type_name
= "string";
1722 } else if (type_name
== "GLib.offset") {
1723 type_name
= "int64";
1724 } else if (type_name
== "gsize") {
1725 type_name
= "size_t";
1726 } else if (type_name
== "gssize") {
1727 type_name
= "ssize_t";
1728 } else if (type_name
== "GType") {
1729 type_name
= "GLib.Type";
1730 } else if (type_name
== "GLib.String") {
1731 type_name
= "GLib.StringBuilder";
1732 } else if (type_name
== "GObject.Class") {
1733 type_name
= "GLib.ObjectClass";
1734 } else if (type_name
== "GLib.unichar") {
1735 type_name
= "unichar";
1736 } else if (type_name
== "GLib.Data") {
1737 type_name
= "GLib.Datalist";
1738 } else if (type_name
== "Atk.ImplementorIface") {
1739 type_name
= "Atk.Implementor";
1743 var sym
= parse_symbol_from_string (type_name
, get_current_src ());
1744 type
= new UnresolvedType
.from_symbol (sym
, get_current_src ());
1746 unresolved_gir_symbols
.add (sym
);
1753 Struct?
parse_record () {
1754 start_element ("record");
1755 var st
= new
Struct (reader
.get_attribute ("name"), get_current_src ());
1758 current_gtype_struct_for
= reader
.get_attribute ("glib:is-gtype-struct-for");
1760 st
.access
= SymbolAccessibility
.PUBLIC
;
1762 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1763 if (!push_metadata ()) {
1768 if (reader
.name
== "field") {
1769 st
.add_field (parse_field ());
1770 } else if (reader
.name
== "constructor") {
1771 parse_constructor ();
1772 } else if (reader
.name
== "method") {
1773 st
.add_method (parse_method ("method"));
1774 } else if (reader
.name
== "union") {
1775 Struct s
= parse_union ();
1776 var s_fields
= s
.get_fields ();
1777 foreach (var f
in s_fields
) {
1778 f
.set_cname (s
.get_cname () + "." + f
.get_cname ());
1779 f
.name
= s
.name
+ "_" + f
.name
;
1784 Report
.error (get_current_src (), "unknown child element `%s' in `record'".printf (reader
.name
));
1790 end_element ("record");
1792 if (current_gtype_struct_for
!= null) {
1793 // skip *Class or *Iface
1794 current_gtype_struct_for
= null;
1801 Class
parse_class () {
1802 start_element ("class");
1803 var cl
= new
Class (reader
.get_attribute ("name"), get_current_src ());
1804 cl
.access
= SymbolAccessibility
.PUBLIC
;
1807 string cname
= reader
.get_attribute ("c:type");
1808 if (cname
!= null) {
1809 cl
.set_cname (cname
);
1812 string parent
= reader
.get_attribute ("parent");
1813 if (parent
!= null) {
1814 cl
.add_base_type (parse_type_from_gir_name (parent
));
1818 var old_symbols_info
= current_symbols_info
;
1819 current_symbols_info
= new HashMap
<string,ArrayList
<SymbolInfo
>> (str_hash
, str_equal
);
1820 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1821 if (!push_metadata ()) {
1826 if (reader
.name
== "implements") {
1827 start_element ("implements");
1828 cl
.add_base_type (parse_type_from_gir_name (reader
.get_attribute ("name")));
1830 end_element ("implements");
1831 } else if (reader
.name
== "constant") {
1832 add_symbol_info (parse_constant ());
1833 } else if (reader
.name
== "field") {
1834 add_symbol_info (parse_field ());
1835 } else if (reader
.name
== "property") {
1836 add_symbol_info (parse_property ());
1837 } else if (reader
.name
== "constructor") {
1838 add_symbol_info (parse_constructor (cname
));
1839 } else if (reader
.name
== "function") {
1840 add_symbol_info (parse_method ("function"));
1841 } else if (reader
.name
== "method") {
1842 add_symbol_info (parse_method ("method"));
1843 } else if (reader
.name
== "virtual-method") {
1844 add_symbol_info (parse_method ("virtual-method"));
1845 } else if (reader
.name
== "union") {
1846 Struct s
= parse_union ();
1847 var s_fields
= s
.get_fields ();
1848 foreach (var f
in s_fields
) {
1849 f
.set_cname (s
.get_cname () + "." + f
.get_cname ());
1850 f
.name
= s
.name
+ "_" + f
.name
;
1851 add_symbol_info (f
);
1853 } else if (reader
.name
== "glib:signal") {
1854 add_symbol_info (parse_signal ());
1857 Report
.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader
.name
));
1864 merge_add_process (cl
);
1865 current_symbols_info
= old_symbols_info
;
1867 handle_async_methods (cl
);
1869 end_element ("class");
1873 Interface
parse_interface () {
1874 start_element ("interface");
1875 var iface
= new
Interface (element_get_name (), get_current_src ());
1876 iface
.access
= SymbolAccessibility
.PUBLIC
;
1877 iface
.external
= true;
1879 string cname
= reader
.get_attribute ("c:type");
1880 if (cname
!= null) {
1881 iface
.set_cname (cname
);
1885 var old_symbols_info
= current_symbols_info
;
1886 current_symbols_info
= new HashMap
<string,ArrayList
<SymbolInfo
>> (str_hash
, str_equal
);
1887 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1888 if (!push_metadata ()) {
1893 if (reader
.name
== "prerequisite") {
1894 start_element ("prerequisite");
1895 iface
.add_prerequisite (parse_type_from_gir_name (reader
.get_attribute ("name")));
1897 end_element ("prerequisite");
1898 } else if (reader
.name
== "field") {
1900 } else if (reader
.name
== "property") {
1901 add_symbol_info (parse_property ());
1902 } else if (reader
.name
== "virtual-method") {
1903 add_symbol_info (parse_method ("virtual-method"));
1904 } else if (reader
.name
== "function") {
1905 add_symbol_info (parse_method ("function"));
1906 } else if (reader
.name
== "method") {
1907 add_symbol_info (parse_method ("method"));
1908 } else if (reader
.name
== "glib:signal") {
1909 add_symbol_info (parse_signal ());
1912 Report
.error (get_current_src (), "unknown child element `%s' in `interface'".printf (reader
.name
));
1919 merge_add_process (iface
);
1920 current_symbols_info
= old_symbols_info
;
1922 handle_async_methods (iface
);
1924 end_element ("interface");
1928 void handle_async_methods (ObjectTypeSymbol type_symbol
) {
1929 var methods
= type_symbol
.get_methods ();
1930 for (int method_n
= 0 ; method_n
< methods
.size
; method_n
++) {
1931 var m
= methods
.get (method_n
);
1934 string finish_method_base
;
1935 if (m
.name
.has_suffix ("_async")) {
1936 finish_method_base
= m
.name
.substring (0, m
.name
.length
- "_async".length
);
1938 finish_method_base
= m
.name
;
1940 var finish_method
= type_symbol
.scope
.lookup (finish_method_base
+ "_finish") as Method
;
1942 // check if the method is using non-standard finish method name
1943 if (finish_method
== null) {
1944 var method_cname
= m
.get_finish_cname ();
1945 foreach (Method method
in type_symbol
.get_methods ()) {
1946 if (method
.get_cname () == method_cname
) {
1947 finish_method
= method
;
1953 if (finish_method
!= null) {
1954 m
.return_type
= finish_method
.return_type
.copy ();
1955 m
.no_array_length
= finish_method
.no_array_length
;
1956 m
.array_null_terminated
= finish_method
.array_null_terminated
;
1957 foreach (var param
in finish_method
.get_parameters ()) {
1958 if (param
.direction
== ParameterDirection
.OUT
) {
1959 var async_param
= param
.copy ();
1960 if (m
.scope
.lookup (param
.name
) != null) {
1961 // parameter name conflict
1962 async_param
.name
+= "_out";
1964 m
.add_parameter (async_param
);
1967 foreach (DataType error_type
in finish_method
.get_error_types ()) {
1968 m
.add_error_type (error_type
.copy ());
1970 if (methods
.index_of (finish_method
) < method_n
) {
1973 type_symbol
.scope
.remove (finish_method
.name
);
1974 methods
.remove (finish_method
);
1980 Field
parse_field () {
1981 start_element ("field");
1982 string name
= reader
.get_attribute ("name");
1983 string allow_none
= reader
.get_attribute ("allow-none");
1985 var type
= parse_type ();
1986 type
= element_get_type (type
, true);
1987 if (type is DelegateType
&& current_gtype_struct_for
!= null) {
1989 var callback_scope
= new
CallbackScope ();
1990 callback_scope
.parent_namespace
= current_namespace
;
1991 callback_scope
.gtype_struct_for
= parse_symbol_from_string (current_gtype_struct_for
);
1992 ArrayList
<Delegate
> callbacks
= gtype_callbacks
.get (callback_scope
);
1993 if (callbacks
== null) {
1994 callbacks
= new ArrayList
<Delegate
> ();
1995 gtype_callbacks
.set (callback_scope
, callbacks
);
1997 callbacks
.add (((DelegateType
) type
).delegate_symbol
);
1999 var field
= new
Field (name
, type
, null, get_current_src ());
2000 field
.access
= SymbolAccessibility
.PUBLIC
;
2001 field
.no_array_length
= true;
2002 if (allow_none
== "1") {
2003 type
.nullable
= true;
2005 end_element ("field");
2009 Property
parse_property () {
2010 start_element ("property");
2011 string name
= reader
.get_attribute ("name").replace ("-", "_");
2012 string readable
= reader
.get_attribute ("readable");
2013 string writable
= reader
.get_attribute ("writable");
2014 string construct_
= reader
.get_attribute ("construct");
2015 string construct_only
= reader
.get_attribute ("construct-only");
2017 bool no_array_length
;
2018 bool array_null_terminated
;
2019 var type
= parse_type (null, null, false, out no_array_length
, out array_null_terminated
);
2020 var prop
= new
Property (name
, type
, null, null, get_current_src ());
2021 prop
.access
= SymbolAccessibility
.PUBLIC
;
2022 prop
.no_accessor_method
= true;
2023 prop
.no_array_length
= no_array_length
;
2024 prop
.array_null_terminated
= array_null_terminated
;
2025 if (readable
!= "0") {
2026 prop
.get_accessor
= new
PropertyAccessor (true, false, false, prop
.property_type
.copy (), null, null);
2028 if (writable
== "1" || construct_only
== "1") {
2029 prop
.set_accessor
= new
PropertyAccessor (false, (construct_only
!= "1") && (writable
== "1"), (construct_only
== "1") || (construct_
== "1"), prop
.property_type
.copy (), null, null);
2031 end_element ("property");
2035 Delegate
parse_callback () {
2036 return this
.parse_function ("callback") as Delegate
;
2039 Method
parse_constructor (string? parent_ctype
= null) {
2040 start_element ("constructor");
2041 string name
= element_get_name ();
2042 string throws_string
= reader
.get_attribute ("throws");
2043 string cname
= reader
.get_attribute ("c:identifier");
2047 parse_return_value (out ctype
);
2049 var m
= new
CreationMethod (null, name
, get_current_src ());
2050 m
.access
= SymbolAccessibility
.PUBLIC
;
2051 m
.has_construct_function
= false;
2052 if (ctype
!= null && (parent_ctype
== null || ctype
!= parent_ctype
+ "*")) {
2053 m
.custom_return_type_cname
= ctype
;
2055 if (m
.name
== "new") {
2057 } else if (m
.name
.has_prefix ("new_")) {
2058 m
.name
= m
.name
.offset ("new_".length
);
2060 if (cname
!= null) {
2061 m
.set_cname (cname
);
2063 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "parameters") {
2064 start_element ("parameters");
2066 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2067 if (!push_metadata ()) {
2072 m
.add_parameter (parse_parameter ());
2076 end_element ("parameters");
2079 if (throws_string
== "1") {
2080 m
.add_error_type (new
ErrorType (null, null));
2082 end_element ("constructor");
2087 public MethodInfo (Parameter param
, int array_length_idx
, int closure_idx
, int destroy_idx
) {
2089 this
.array_length_idx
= array_length_idx
;
2090 this
.closure_idx
= closure_idx
;
2091 this
.destroy_idx
= destroy_idx
;
2092 this
.vala_idx
= 0.0F
;
2096 public Parameter param
;
2097 public float vala_idx
;
2098 public int array_length_idx
;
2099 public int closure_idx
;
2100 public int destroy_idx
;
2104 Symbol
parse_function (string element_name
) {
2105 start_element (element_name
);
2106 string name
= element_get_name ();
2107 string cname
= reader
.get_attribute ("c:identifier");
2108 string throws_string
= reader
.get_attribute ("throws");
2109 string invoker
= reader
.get_attribute ("invoker");
2111 DataType return_type
;
2112 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "return-value") {
2113 return_type
= parse_return_value ();
2115 return_type
= new
VoidType ();
2117 return_type
= element_get_type (return_type
, true);
2121 if (element_name
== "callback") {
2122 s
= new
Delegate (name
, return_type
, get_current_src ());
2124 s
= new
Method (name
, return_type
, get_current_src ());
2127 s
.access
= SymbolAccessibility
.PUBLIC
;
2128 if (cname
!= null) {
2130 ((Method
) s
).set_cname (cname
);
2132 ((Delegate
) s
).set_cname (cname
);
2136 if (element_name
== "virtual-method" || element_name
== "callback") {
2138 ((Method
) s
).is_virtual
= true;
2141 if (invoker
!= null){
2144 } else if (element_name
== "function") {
2145 ((Method
) s
).binding
= MemberBinding
.STATIC
;
2148 var parameters
= new ArrayList
<MethodInfo
> ();
2149 var array_length_parameters
= new ArrayList
<int> ();
2150 var closure_parameters
= new ArrayList
<int> ();
2151 var destroy_parameters
= new ArrayList
<int> ();
2152 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "parameters") {
2153 start_element ("parameters");
2156 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2157 if (!push_metadata ()) {
2162 int array_length_idx
, closure_idx
, destroy_idx
;
2164 string default_param_name
= null;
2165 if (s is Delegate
) {
2166 default_param_name
= "arg%d".printf (parameters
.size
);
2168 var param
= parse_parameter (out array_length_idx
, out closure_idx
, out destroy_idx
, out scope
, default_param_name
);
2169 if (array_length_idx
!= -1) {
2170 array_length_parameters
.add (array_length_idx
);
2172 if (closure_idx
!= -1) {
2173 closure_parameters
.add (closure_idx
);
2175 if (destroy_idx
!= -1) {
2176 destroy_parameters
.add (destroy_idx
);
2179 var info
= new
MethodInfo(param
, array_length_idx
, closure_idx
, destroy_idx
);
2181 if (s is Method
&& scope
== "async") {
2182 var unresolved_type
= param
.variable_type as UnresolvedType
;
2183 if (unresolved_type
!= null && unresolved_type
.unresolved_symbol
.name
== "AsyncReadyCallback") {
2184 // GAsync-style method
2185 ((Method
) s
).coroutine
= true;
2190 parameters
.add (info
);
2193 end_element ("parameters");
2198 foreach (MethodInfo info
in parameters
) {
2199 if (s is Delegate
&& info
.closure_idx
== i
) {
2200 var d
= (Delegate
) s
;
2201 d
.has_target
= true;
2202 d
.cinstance_parameter_position
= (float) j
- 0.1;
2204 } else if (info
.keep
2205 && !array_length_parameters
.contains (i
)
2206 && !closure_parameters
.contains (i
)
2207 && !destroy_parameters
.contains (i
)) {
2208 info
.vala_idx
= (float) j
;
2211 /* interpolate for vala_idx between this and last*/
2212 float last_idx
= 0.0F
;
2214 last_idx
= parameters
[last
].vala_idx
;
2216 for (int k
=last
+1; k
< i
; k
++) {
2217 parameters
[k
].vala_idx
= last_idx
+ (((j
- last_idx
) / (i
-last
)) * (k
-last
));
2223 // make sure that vala_idx is always set
2224 // the above if branch does not set vala_idx for
2225 // hidden parameters at the end of the parameter list
2226 info
.vala_idx
= (j
- 1) + (i
- last
) * 0.1F
;
2231 foreach (MethodInfo info
in parameters
) {
2234 /* add_parameter sets carray_length_parameter_position and cdelegate_target_parameter_position
2237 ((Method
) s
).add_parameter (info
.param
);
2239 ((Delegate
) s
).add_parameter (info
.param
);
2242 if (info
.array_length_idx
!= -1) {
2243 if ((info
.array_length_idx
) >= parameters
.size
) {
2244 Report
.error (get_current_src (), "invalid array_length index");
2247 info
.param
.carray_length_parameter_position
= parameters
[info
.array_length_idx
].vala_idx
;
2248 info
.param
.set_array_length_cname (parameters
[info
.array_length_idx
].param
.name
);
2250 if (info
.param
.variable_type is ArrayType
&& info
.array_length_idx
== -1) {
2251 info
.param
.no_array_length
= true;
2254 if (info
.closure_idx
!= -1) {
2255 if ((info
.closure_idx
) >= parameters
.size
) {
2256 Report
.error (get_current_src (), "invalid closure index");
2259 info
.param
.cdelegate_target_parameter_position
= parameters
[info
.closure_idx
].vala_idx
;
2261 if (info
.destroy_idx
!= -1) {
2262 if (info
.destroy_idx
>= parameters
.size
) {
2263 Report
.error (get_current_src (), "invalid destroy index");
2266 info
.param
.cdestroy_notify_parameter_position
= parameters
[info
.destroy_idx
].vala_idx
;
2271 if (throws_string
== "1") {
2272 s
.add_error_type (new
ErrorType (null, null));
2274 end_element (element_name
);
2278 Method
parse_method (string element_name
) {
2279 return this
.parse_function (element_name
) as Method
;
2282 Signal
parse_signal () {
2283 start_element ("glib:signal");
2284 string name
= reader
.get_attribute ("name").replace ("-", "_");
2286 DataType return_type
;
2287 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "return-value") {
2288 return_type
= parse_return_value ();
2290 return_type
= new
VoidType ();
2292 var sig
= new
Signal (name
, return_type
, get_current_src ());
2293 sig
.access
= SymbolAccessibility
.PUBLIC
;
2294 sig
.external
= true;
2295 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "parameters") {
2296 start_element ("parameters");
2298 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2299 if (!push_metadata ()) {
2304 sig
.add_parameter (parse_parameter ());
2308 end_element ("parameters");
2310 end_element ("glib:signal");
2314 Class
parse_boxed () {
2315 string name
= reader
.get_attribute ("name");
2317 name
= reader
.get_attribute ("glib:name");
2319 var cl
= new
Class (name
, get_current_src ());
2320 cl
.access
= SymbolAccessibility
.PUBLIC
;
2322 cl
.is_compact
= true;
2324 string cname
= reader
.get_attribute ("c:type");
2325 if (cname
!= null) {
2326 cl
.set_cname (cname
);
2329 cl
.set_type_id ("%s ()".printf (reader
.get_attribute ("glib:get-type")));
2330 cl
.set_free_function ("g_boxed_free");
2331 cl
.set_dup_function ("g_boxed_copy");
2335 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2336 if (!push_metadata ()) {
2341 if (reader
.name
== "field") {
2342 cl
.add_field (parse_field ());
2343 } else if (reader
.name
== "constructor") {
2344 parse_constructor ();
2345 } else if (reader
.name
== "method") {
2346 cl
.add_method (parse_method ("method"));
2349 Report
.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader
.name
));
2356 if (current_token
!= MarkupTokenType
.END_ELEMENT
) {
2358 Report
.error (get_current_src (), "expected end element");
2364 Struct
parse_union () {
2365 start_element ("union");
2366 var st
= new
Struct (reader
.get_attribute ("name"), get_current_src ());
2367 st
.access
= SymbolAccessibility
.PUBLIC
;
2371 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2372 if (!push_metadata ()) {
2377 if (reader
.name
== "field") {
2378 st
.add_field (parse_field ());
2379 } else if (reader
.name
== "constructor") {
2380 parse_constructor ();
2381 } else if (reader
.name
== "method") {
2382 st
.add_method (parse_method ("method"));
2383 } else if (reader
.name
== "record") {
2384 Struct s
= parse_record ();
2385 var fs
= s
.get_fields ();
2386 foreach (var f
in fs
) {
2387 f
.set_cname (s
.get_cname () + "." + f
.get_cname ());
2388 f
.name
= s
.name
+ "_" + f
.name
;
2393 Report
.error (get_current_src (), "unknown child element `%s' in `union'".printf (reader
.name
));
2400 end_element ("union");
2404 Constant
parse_constant () {
2405 start_element ("constant");
2406 string name
= element_get_name ();
2408 var type
= parse_type ();
2409 var c
= new
Constant (name
, type
, null, get_current_src ());
2410 c
.access
= SymbolAccessibility
.PUBLIC
;
2412 end_element ("constant");
2417 void report_unused_metadata (Metadata metadata
) {
2418 if (metadata
== Metadata
.empty
) {
2422 if (metadata
.args
.size
== 0 && metadata
.children
.size
== 0) {
2423 Report
.warning (metadata
.source_reference
, "empty metadata");
2427 foreach (var arg_type
in metadata
.args
.get_keys ()) {
2428 var arg
= metadata
.args
[arg_type
];
2430 // if metadata is used and argument is not, then it's a unexpected argument
2431 Report
.warning (arg
.source_reference
, "argument never used");
2435 foreach (var child
in metadata
.children
) {
2437 Report
.warning (child
.source_reference
, "metadata never used");
2439 report_unused_metadata (child
);
2446 void resolve_gir_symbols () {
2447 // we are remapping unresolved symbols, so create them from concrete symbols
2448 foreach (var map_from
in concrete_symbols_map
.get_keys ()) {
2449 unresolved_symbols_map
[get_unresolved_symbol(map_from
)] = concrete_symbols_map
[map_from
];
2452 // gir has simple namespaces, we won't get deeper than 2 levels here, except reparenting
2453 foreach (var map_from
in unresolved_gir_symbols
) {
2454 while (map_from
!= null) {
2455 var map_to
= unresolved_symbols_map
[map_from
];
2456 if (map_to
!= null) {
2457 // remap the original symbol to match the target
2458 map_from
.inner
= null;
2459 map_from
.name
= map_to
.name
;
2460 if (map_to is UnresolvedSymbol
) {
2461 var umap_to
= (UnresolvedSymbol
) map_to
;
2462 while (umap_to
.inner
!= null) {
2463 umap_to
= umap_to
.inner
;
2464 map_from
.inner
= new
UnresolvedSymbol (null, umap_to
.name
);
2465 map_from
= map_from
.inner
;
2468 while (map_to
.parent_symbol
!= null && map_to
.parent_symbol
!= context
.root
) {
2469 map_to
= map_to
.parent_symbol
;
2470 map_from
.inner
= new
UnresolvedSymbol (null, map_to
.name
);
2471 map_from
= map_from
.inner
;
2476 map_from
= map_from
.inner
;
2481 Symbol?
resolve_symbol (Scope parent_scope
, UnresolvedSymbol unresolved_symbol
) {
2482 // simple symbol resolver, enough for gir
2483 if (unresolved_symbol
.inner
== null) {
2484 var scope
= parent_scope
;
2485 while (scope
!= null) {
2486 var sym
= scope
.lookup (unresolved_symbol
.name
);
2490 scope
= scope
.parent_scope
;
2493 var inner
= resolve_symbol (parent_scope
, unresolved_symbol
.inner
);
2494 if (inner
!= null) {
2495 return inner
.scope
.lookup (unresolved_symbol
.name
);
2501 void postprocess_reparenting () {
2502 foreach (UnresolvedSymbol target_unresolved_symbol
in symbol_reparent_map
.get_keys ()) {
2503 var target_symbol
= resolve_symbol (context
.root
.scope
, target_unresolved_symbol
);
2504 if (target_symbol
== null) {
2505 // create namespaces backward
2506 var sym
= target_unresolved_symbol
;
2507 var ns
= new
Namespace (sym
.name
, sym
.source_reference
);
2510 while (sym
!= null) {
2511 var res
= resolve_symbol (context
.root
.scope
, sym
);
2512 if (res
!= null && !(res is Namespace
)) {
2516 var parent
= res as Namespace
;
2518 parent
= new
Namespace (sym
.name
, sym
.source_reference
);
2520 if (parent
.scope
.lookup (ns
.name
) == null) {
2521 parent
.add_namespace (ns
);
2526 if (result
!= null && sym
== null && context
.root
.scope
.lookup (ns
.name
) == null) {
2527 // a new root namespace, helpful for a possible non-gobject gir?
2528 context
.root
.add_namespace (ns
);
2530 target_symbol
= result
;
2532 if (target_symbol
== null) {
2533 Report
.error (null, "unable to reparent into `%s'".printf (target_unresolved_symbol
.to_string ()));
2536 var symbols
= symbol_reparent_map
[target_unresolved_symbol
];
2537 foreach (var symbol
in symbols
) {
2538 add_symbol_to_container (target_symbol
, symbol
);
2543 void postprocess_gtype_callbacks () {
2544 foreach (CallbackScope callback_scope
in gtype_callbacks
.get_keys ()) {
2545 var gtype
= resolve_symbol (callback_scope
.parent_namespace
.scope
, callback_scope
.gtype_struct_for
) as ObjectTypeSymbol
;
2546 if (gtype
== null) {
2547 Report
.error (null, "unknown symbol `%s'".printf (callback_scope
.gtype_struct_for
.to_string ()));
2550 ArrayList
<Delegate
> callbacks
= gtype_callbacks
.get (callback_scope
);
2551 foreach (Delegate d
in callbacks
) {
2552 var symbol
= gtype
.scope
.lookup (d
.name
);
2553 if (symbol
== null) {
2555 } else if (symbol is Method
) {
2556 var meth
= (Method
) symbol
;
2557 if (gtype is Class
) {
2558 meth
.is_virtual
= true;
2559 } else if (gtype is Interface
) {
2560 meth
.is_abstract
= true;
2562 } else if (symbol is Signal
) {
2563 var sig
= (Signal
) symbol
;
2564 sig
.is_virtual
= true;
2565 assume_parameter_names (sig
, d
);
2566 } else if (symbol is Property
) {
2567 var prop
= (Property
) symbol
;
2568 prop
.is_virtual
= true;
2570 Report
.error (get_current_src (), "unknown member type `%s' in `%s'".printf (d
.name
, gtype
.name
));
2576 void postprocess_aliases () {
2577 /* this is unfortunate because <alias> tag has no type information, thus we have
2578 to guess it from the target */
2579 foreach (var alias
in aliases
) {
2580 DataType base_type
= null;
2581 Symbol type_sym
= null;
2582 if (alias
.base_type is UnresolvedType
) {
2583 base_type
= alias
.base_type
;
2584 type_sym
= resolve_symbol (alias
.parent_namespace
.scope
, ((UnresolvedType
) base_type
).unresolved_symbol
);
2585 } else if (!(alias
.base_type is VoidType
)) {
2586 base_type
= alias
.base_type
;
2587 type_sym
= base_type
.data_type
;
2590 if (base_type
== null || type_sym
== null || type_sym is Struct
) {
2591 var st
= new
Struct (alias
.name
, alias
.source_reference
);
2592 st
.access
= SymbolAccessibility
.PUBLIC
;
2593 if (base_type
!= null) {
2594 // threat target="none" as a new struct
2595 st
.base_type
= base_type
;
2598 alias
.parent_namespace
.add_struct (st
);
2599 } else if (type_sym is Class
) {
2600 var cl
= new
Class (alias
.name
, alias
.source_reference
);
2601 cl
.access
= SymbolAccessibility
.PUBLIC
;
2602 if (base_type
!= null) {
2603 cl
.add_base_type (base_type
);
2606 alias
.parent_namespace
.add_class (cl
);
2611 void find_static_method_parent (string cname
, Symbol current
, ref Symbol best
, ref double match
, double match_char
) {
2612 var old_best
= best
;
2613 if (current
.scope
.get_symbol_table () != null) {
2614 foreach (var child
in current
.scope
.get_symbol_table().get_values ()) {
2615 if (child is Struct
|| child is ObjectTypeSymbol
|| child is Namespace
) {
2616 find_static_method_parent (cname
, child
, ref best
, ref match
, match_char
);
2620 if (best
!= old_best
) {
2625 var current_cprefix
= current
.get_lower_case_cprefix ();
2626 if (cname
.has_prefix (current_cprefix
)) {
2627 var current_match
= match_char
* current_cprefix
.length
;
2628 if (current_match
> match
) {
2629 match
= current_match
;
2635 void postprocess_namespace_methods () {
2636 /* transform static methods into instance methods if possible.
2637 In most of cases this is a .gir fault we are going to fix */
2638 foreach (var ns
in namespace_methods
.get_keys ()) {
2639 var ns_cprefix
= ns
.get_lower_case_cprefix ();
2640 var methods
= namespace_methods
[ns
];
2641 foreach (var method
in methods
) {
2642 if (method
.parent_node
!= null) {
2643 // fixed earlier by metadata
2647 var cname
= method
.get_cname ();
2649 Parameter first_param
= null;
2650 if (method
.get_parameters ().size
> 0) {
2651 first_param
= method
.get_parameters()[0];
2653 if (first_param
!= null && first_param
.variable_type is UnresolvedType
) {
2654 // check if it's a missed instance method (often happens for structs)
2655 var parent
= resolve_symbol (ns
.scope
, ((UnresolvedType
) first_param
.variable_type
).unresolved_symbol
);
2656 if (parent
!= null && (parent is Struct
|| parent is ObjectTypeSymbol
|| parent is Namespace
)
2657 && cname
.has_prefix (parent
.get_lower_case_cprefix ())) {
2659 var new_name
= method
.name
.offset (parent
.get_lower_case_cprefix().length
-ns_cprefix
.length
);
2660 if (parent
.scope
.lookup (new_name
) == null) {
2661 method
.name
= new_name
;
2662 method
.get_parameters().remove_at (0);
2663 method
.binding
= MemberBinding
.INSTANCE
;
2664 add_symbol_to_container (parent
, method
);
2666 ns
.add_method (method
);
2674 find_static_method_parent (cname
, ns
, ref parent
, ref match
, 1.0/cname
.length
);
2675 var new_name
= method
.name
.offset (parent
.get_lower_case_cprefix().length
-ns_cprefix
.length
);
2676 if (parent
.scope
.lookup (new_name
) == null) {
2677 method
.name
= new_name
;
2678 add_symbol_to_container (parent
, method
);
2680 ns
.add_method (method
);
2686 /* Hash and equal functions */
2688 static uint unresolved_symbol_hash (void *ptr
) {
2689 var sym
= (UnresolvedSymbol
) ptr
;
2690 var builder
= new
StringBuilder ();
2691 while (sym
!= null) {
2692 builder
.append (sym
.name
);
2695 return builder
.str
.hash ();
2698 static bool unresolved_symbol_equal (void *ptr1
, void *ptr2
) {
2699 var sym1
= (UnresolvedSymbol
) ptr1
;
2700 var sym2
= (UnresolvedSymbol
) ptr2
;
2701 while (sym1
!= sym2
) {
2702 if (sym1
== null || sym2
== null) {
2705 if (sym1
.name
!= sym2
.name
) {
2714 static uint callback_scope_hash (void *ptr
) {
2715 var cs
= (CallbackScope
) ptr
;
2716 return unresolved_symbol_hash (cs
.gtype_struct_for
);
2719 static bool callback_scope_equal (void *ptr1
, void *ptr2
) {
2720 var cs1
= (CallbackScope
) ptr1
;
2721 var cs2
= (CallbackScope
) ptr2
;
2722 return cs1
.parent_namespace
== cs2
.parent_namespace
&& unresolved_symbol_equal (cs1
.gtype_struct_for
, cs2
.gtype_struct_for
);