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
{
75 public static ArgumentType?
from_string (string name
) {
76 var enum_class
= (EnumClass
) typeof(ArgumentType
).class_ref ();
77 var nick
= name
.replace ("_", "-");
78 unowned GLib
.EnumValue? enum_value
= enum_class
.get_value_by_nick (nick
);
79 if (enum_value
!= null) {
80 ArgumentType value
= (ArgumentType
) enum_value
.value
;
88 public Expression expression
;
89 public SourceReference source_reference
;
91 public bool used
= false;
93 public Argument (Expression expression
, SourceReference? source_reference
= null) {
94 this
.expression
= expression
;
95 this
.source_reference
= source_reference
;
99 class MetadataSet
: Metadata
{
100 public MetadataSet (MetadataType type
) {
104 public void add_sibling (Metadata metadata
) {
105 foreach (var child
in metadata
.children
) {
108 // merge arguments and take precedence
109 foreach (var key
in metadata
.args
.get_keys ()) {
110 args
[key
] = metadata
.args
[key
];
116 private static Metadata _empty
= null;
117 public static Metadata empty
{
119 if (_empty
== null) {
120 _empty
= new
Metadata ("");
126 public string pattern
;
127 public PatternSpec pattern_spec
;
128 public MetadataType type
;
129 public SourceReference source_reference
;
131 public bool used
= false;
132 public Vala
.Map
<ArgumentType
,Argument
> args
= new HashMap
<ArgumentType
,Argument
> ();
133 public ArrayList
<Metadata
> children
= new ArrayList
<Metadata
> ();
135 public Metadata (string pattern
, MetadataType type
= MetadataType
.GENERIC
, SourceReference? source_reference
= null) {
136 this
.pattern
= pattern
;
137 this
.pattern_spec
= new
PatternSpec (pattern
);
139 this
.source_reference
= source_reference
;
142 public void add_child (Metadata metadata
) {
143 children
.add (metadata
);
146 public Metadata?
get_child (string pattern
, MetadataType type
= MetadataType
.GENERIC
) {
147 foreach (var metadata
in children
) {
148 if (metadata
.type
== type
&& metadata
.pattern
== pattern
) {
155 public Metadata
match_child (string name
, MetadataType type
= MetadataType
.GENERIC
) {
156 var result
= Metadata
.empty
;
157 foreach (var metadata
in children
) {
158 if (metadata
.type
== type
&& metadata
.pattern_spec
.match_string (name
)) {
159 metadata
.used
= true;
160 if (result
== Metadata
.empty
) {
164 var ms
= result as MetadataSet
;
167 ms
= new
MetadataSet (type
);
168 ms
.add_sibling (result
);
170 ms
.add_sibling (metadata
);
178 public void add_argument (ArgumentType key
, Argument value
) {
179 args
.set (key
, value
);
182 public bool has_argument (ArgumentType key
) {
183 return args
.contains (key
);
186 public Expression?
get_expression (ArgumentType arg
) {
187 var val
= args
.get (arg
);
190 return val
.expression
;
195 public string?
get_string (ArgumentType arg
) {
196 var lit
= get_expression (arg
) as StringLiteral
;
203 public int get_integer (ArgumentType arg
) {
204 var unary
= get_expression (arg
) as UnaryExpression
;
205 if (unary
!= null && unary
.operator
== UnaryOperator
.MINUS
) {
206 var lit
= unary
.inner as IntegerLiteral
;
208 return -int.parse (lit
.value
);
211 var lit
= get_expression (arg
) as IntegerLiteral
;
213 return int.parse (lit
.value
);
220 public bool get_bool (ArgumentType arg
) {
221 var lit
= get_expression (arg
) as BooleanLiteral
;
228 public SourceReference?
get_source_reference (ArgumentType arg
) {
229 var val
= args
.get (arg
);
231 return val
.source_reference
;
237 class MetadataParser
{
240 * metadata ::= [ rule [ '\n' relativerule ]* ]
241 * rule ::= pattern ' ' [ args ]
242 * relativerule ::= [ access ] rule
243 * pattern ::= identifier [ access identifier ]*
244 * access ::= '.' | ':' | '::'
246 private Metadata tree
= new
Metadata ("");
247 private Scanner scanner
;
248 private SourceLocation begin
;
249 private SourceLocation end
;
250 private SourceLocation old_end
;
251 private TokenType current
;
252 private Metadata parent_metadata
;
254 public MetadataParser () {
258 SourceReference
get_current_src () {
259 return new
SourceReference (scanner
.source_file
, begin
.line
, begin
.column
, end
.line
, end
.column
);
262 SourceReference
get_src (SourceLocation begin
) {
263 return new
SourceReference (scanner
.source_file
, begin
.line
, begin
.column
, end
.line
, end
.column
);
266 public Metadata
parse_metadata (SourceFile metadata_file
) {
267 scanner
= new
Scanner (metadata_file
);
269 while (current
!= TokenType
.EOF
) {
270 if (!parse_rule ()) {
271 return Metadata
.empty
;
279 current
= scanner
.read_token (out begin
, out end
);
284 return old_end
.pos
!= begin
.pos
;
287 bool has_newline () {
288 return old_end
.line
!= begin
.line
;
291 string get_string () {
292 return ((string) begin
.pos
).substring (0, (int) (end
.pos
- begin
.pos
));
295 MetadataType?
parse_metadata_access () {
299 return MetadataType
.GENERIC
;
300 case TokenType
.COLON
:
302 return MetadataType
.PROPERTY
;
303 case TokenType
.DOUBLE_COLON
:
305 return MetadataType
.SIGNAL
;
311 string?
parse_identifier (out SourceReference source_reference
, bool is_glob
) {
312 var begin
= this
.begin
;
313 var builder
= new
StringBuilder ();
315 if (is_glob
&& current
== TokenType
.STAR
) {
316 builder
.append_c ('*');
320 case TokenType
.IDENTIFIER
:
321 case TokenType
.UNOWNED
:
322 case TokenType
.OWNED
:
325 case TokenType
.DEFAULT
:
328 case TokenType
.VIRTUAL
:
329 case TokenType
.ABSTRACT
:
336 builder
.append (str
);
338 source_reference
= get_src (begin
);
340 } while (!has_space ());
342 if (builder
.str
== "") {
344 Report
.error (get_src (begin
), "expected pattern");
346 Report
.error (get_src (begin
), "expected identifier");
353 Metadata?
parse_pattern () {
355 bool is_relative
= false;
356 MetadataType? type
= MetadataType
.GENERIC
;
357 if (current
== TokenType
.IDENTIFIER
|| current
== TokenType
.STAR
) {
359 parent_metadata
= tree
;
362 type
= parse_metadata_access ();
367 Report
.error (get_current_src (), "expected pattern, `.', `:' or `::'");
371 if (parent_metadata
== null) {
372 Report
.error (get_current_src (), "cannot determinate parent metadata");
377 var pattern
= parse_identifier (out src
, true);
378 if (pattern
== null) {
381 metadata
= parent_metadata
.get_child (pattern
, type
);
382 if (metadata
== null) {
383 metadata
= new
Metadata (pattern
, type
, src
);
384 parent_metadata
.add_child (metadata
);
387 while (current
!= TokenType
.EOF
&& !has_space ()) {
388 type
= parse_metadata_access ();
390 Report
.error (get_current_src (), "expected `.', `:' or `::'");
394 pattern
= parse_identifier (out src
, true);
395 if (pattern
== null) {
398 var child
= metadata
.get_child (pattern
, type
);
400 child
= new
Metadata (pattern
, type
, src
);
401 metadata
.add_child (child
);
406 parent_metadata
= metadata
;
412 Expression?
parse_expression () {
413 var begin
= this
.begin
;
414 var src
= get_current_src ();
415 Expression expr
= null;
418 expr
= new
NullLiteral (src
);
421 expr
= new
BooleanLiteral (true, src
);
423 case TokenType
.FALSE
:
424 expr
= new
BooleanLiteral (false, src
);
426 case TokenType
.MINUS
:
428 var inner
= parse_expression ();
430 Report
.error (src
, "expected expression after `-', got `%s'".printf (current
.to_string ()));
432 expr
= new
UnaryExpression (UnaryOperator
.MINUS
, inner
, get_src (begin
));
435 case TokenType
.INTEGER_LITERAL
:
436 expr
= new
IntegerLiteral (get_string (), src
);
438 case TokenType
.REAL_LITERAL
:
439 expr
= new
RealLiteral (get_string (), src
);
441 case TokenType
.STRING_LITERAL
:
442 expr
= new
StringLiteral (get_string (), src
);
444 case TokenType
.IDENTIFIER
:
445 expr
= new
MemberAccess (null, get_string (), src
);
446 while (next () == TokenType
.DOT
) {
447 if (next () != TokenType
.IDENTIFIER
) {
448 Report
.error (get_current_src (), "expected identifier got `%s'".printf (current
.to_string ()));
451 expr
= new
MemberAccess (expr
, get_string (), get_current_src ());
455 Report
.error (src
, "expected literal or symbol got `%s'".printf (current
.to_string ()));
462 bool parse_args (Metadata metadata
) {
463 while (current
!= TokenType
.EOF
&& has_space () && !has_newline ()) {
465 var id
= parse_identifier (out src
, false);
469 var arg_type
= ArgumentType
.from_string (id
);
470 if (arg_type
== null) {
471 Report
.error (src
, "unknown argument");
475 if (current
!= TokenType
.ASSIGN
) {
477 metadata
.add_argument (arg_type
, new
Argument (new
BooleanLiteral (true, src
), src
));
482 Expression expr
= parse_expression ();
486 metadata
.add_argument (arg_type
, new
Argument (expr
, src
));
494 var metadata
= parse_pattern ();
495 if (metadata
== null) {
499 if (current
== TokenType
.EOF
|| old_end
.line
!= end
.line
) {
503 return parse_args (metadata
);
508 public Symbol symbol
;
509 public Metadata metadata
;
510 // additional information from GIR
511 public HashMap
<string,string> girdata
;
517 public DataType base_type
;
518 public Symbol parent_symbol
;
519 public SourceReference source_reference
;
522 static GLib
.Regex type_from_string_regex
;
529 SourceFile current_source_file
;
530 Symbol current_symbol
;
532 string current_gtype_struct_for
;
533 SourceLocation begin
;
535 MarkupTokenType current_token
;
537 string[] cheader_filenames
;
539 ArrayList
<Metadata
> metadata_stack
;
541 ArrayList
<HashMap
<string,string>> girdata_stack
;
542 HashMap
<string,string> girdata
;
544 ArrayList
<SymbolInfo
> current_symbols_info
;
546 HashMap
<UnresolvedSymbol
,Symbol
> unresolved_symbols_map
= new HashMap
<UnresolvedSymbol
,Symbol
> (unresolved_symbol_hash
, unresolved_symbol_equal
);
547 HashMap
<Symbol
,Symbol
> concrete_symbols_map
= new HashMap
<Symbol
,Symbol
> ();
549 ArrayList
<UnresolvedSymbol
> unresolved_gir_symbols
= new ArrayList
<UnresolvedSymbol
> ();
550 HashMap
<UnresolvedSymbol
,ArrayList
<Symbol
>> symbol_reparent_map
= new HashMap
<UnresolvedSymbol
,ArrayList
<Symbol
>> (unresolved_symbol_hash
, unresolved_symbol_equal
);
551 HashMap
<Namespace
,ArrayList
<Method
>> namespace_methods
= new HashMap
<Namespace
,ArrayList
<Method
>> ();
552 ArrayList
<Alias
> aliases
= new ArrayList
<Alias
> ();
553 ArrayList
<Interface
> interfaces
= new ArrayList
<Interface
> ();
555 HashMap
<UnresolvedSymbol
,ArrayList
<Delegate
>> gtype_callbacks
;
558 * Parses all .gir source files in the specified code
559 * context and builds a code tree.
561 * @param context a code context
563 public void parse (CodeContext context
) {
564 this
.context
= context
;
565 glib_ns
= context
.root
.scope
.lookup ("GLib") as Namespace
;
566 context
.accept (this
);
568 resolve_gir_symbols ();
570 postprocess_interfaces ();
571 postprocess_reparenting ();
572 postprocess_aliases ();
573 postprocess_namespace_methods ();
576 public override void visit_source_file (SourceFile source_file
) {
577 // collect gir namespaces
578 foreach (var node
in source_file
.get_nodes ()) {
579 if (node is Namespace
) {
580 var ns
= (Namespace
) node
;
581 var gir_namespace
= source_file
.gir_namespace
;
582 if (gir_namespace
== null) {
583 var a
= ns
.get_attribute ("CCode");
584 if (a
!= null && a
.has_argument ("gir_namespace")) {
585 gir_namespace
= a
.get_string ("gir_namespace");
588 if (gir_namespace
!= null && gir_namespace
!= ns
.name
) {
589 var map_from
= new
UnresolvedSymbol (null, gir_namespace
);
590 set_symbol_mapping (map_from
, ns
);
596 if (source_file
.filename
.has_suffix (".gir")) {
597 parse_file (source_file
);
601 public void parse_file (SourceFile source_file
) {
602 metadata_stack
= new ArrayList
<Metadata
> ();
603 metadata
= Metadata
.empty
;
604 girdata_stack
= new ArrayList
<HashMap
<string,string>> ();
606 // load metadata, first look into metadata directories then in the same directory of the .gir.
607 string? metadata_filename
= context
.get_metadata_path (source_file
.filename
);
608 if (metadata_filename
!= null && FileUtils
.test (metadata_filename
, FileTest
.EXISTS
)) {
609 var metadata_parser
= new
MetadataParser ();
610 var metadata_file
= new
SourceFile (context
, source_file
.file_type
, metadata_filename
);
611 context
.add_source_file (metadata_file
);
612 metadata
= metadata_parser
.parse_metadata (metadata_file
);
615 this
.current_source_file
= source_file
;
616 reader
= new
MarkupReader (source_file
.filename
);
626 this
.current_source_file
= null;
630 current_token
= reader
.read_token (out begin
, out end
);
632 // Skip *all* <doc> tags
633 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "doc")
637 void start_element (string name
) {
638 if (current_token
!= MarkupTokenType
.START_ELEMENT
|| reader
.name
!= name
) {
640 Report
.error (get_current_src (), "expected start element of `%s'".printf (name
));
644 void end_element (string name
) {
645 if (current_token
!= MarkupTokenType
.END_ELEMENT
|| reader
.name
!= name
) {
647 Report
.error (get_current_src (), "expected end element of `%s'".printf (name
));
652 SourceReference
get_current_src () {
653 return new
SourceReference (this
.current_source_file
, begin
.line
, begin
.column
, end
.line
, end
.column
);
656 const string GIR_VERSION
= "1.2";
658 void add_symbol_to_container (Symbol container
, Symbol sym
) {
660 if (name
== null && sym is CreationMethod
) {
663 if (container
.scope
.lookup (name
) != null) {
664 // overridden by -custom.vala
668 if (container is Class
) {
669 unowned Class cl
= (Class
) container
;
672 cl
.add_class ((Class
) sym
);
673 } else if (sym is Constant
) {
674 cl
.add_constant ((Constant
) sym
);
675 } else if (sym is Enum
) {
676 cl
.add_enum ((Enum
) sym
);
677 } else if (sym is Field
) {
678 cl
.add_field ((Field
) sym
);
679 } else if (sym is Method
) {
680 cl
.add_method ((Method
) sym
);
681 } else if (sym is Property
) {
682 cl
.add_property ((Property
) sym
);
683 } else if (sym is Signal
) {
684 cl
.add_signal ((Signal
) sym
);
685 } else if (sym is Struct
) {
686 cl
.add_struct ((Struct
) sym
);
688 } else if (container is Enum
) {
689 unowned Enum en
= (Enum
) container
;
691 if (sym is EnumValue
) {
692 en
.add_value ((EnumValue
) sym
);
693 } else if (sym is Constant
) {
694 en
.add_constant ((Constant
) sym
);
695 } else if (sym is Method
) {
696 en
.add_method ((Method
) sym
);
698 } else if (container is Interface
) {
699 unowned Interface iface
= (Interface
) container
;
702 iface
.add_class ((Class
) sym
);
703 } else if (sym is Constant
) {
704 iface
.add_constant ((Constant
) sym
);
705 } else if (sym is Enum
) {
706 iface
.add_enum ((Enum
) sym
);
707 } else if (sym is Field
) {
708 iface
.add_field ((Field
) sym
);
709 } else if (sym is Method
) {
710 iface
.add_method ((Method
) sym
);
711 } else if (sym is Property
) {
712 iface
.add_property ((Property
) sym
);
713 } else if (sym is Signal
) {
714 iface
.add_signal ((Signal
) sym
);
715 } else if (sym is Struct
) {
716 iface
.add_struct ((Struct
) sym
);
718 } else if (container is Namespace
) {
719 unowned Namespace ns
= (Namespace
) container
;
721 if (sym is Namespace
) {
722 ns
.add_namespace ((Namespace
) sym
);
723 } else if (sym is Class
) {
724 ns
.add_class ((Class
) sym
);
725 } else if (sym is Constant
) {
726 ns
.add_constant ((Constant
) sym
);
727 } else if (sym is Delegate
) {
728 ns
.add_delegate ((Delegate
) sym
);
729 } else if (sym is Enum
) {
730 ns
.add_enum ((Enum
) sym
);
731 } else if (sym is ErrorDomain
) {
732 ns
.add_error_domain ((ErrorDomain
) sym
);
733 } else if (sym is Field
) {
734 ns
.add_field ((Field
) sym
);
735 } else if (sym is Interface
) {
736 ns
.add_interface ((Interface
) sym
);
737 } else if (sym is Method
) {
738 ns
.add_method ((Method
) sym
);
739 } else if (sym is Namespace
) {
740 ns
.add_namespace ((Namespace
) sym
);
741 } else if (sym is Struct
) {
742 ns
.add_struct ((Struct
) sym
);
744 } else if (container is Struct
) {
745 unowned Struct st
= (Struct
) container
;
747 if (sym is Constant
) {
748 st
.add_constant ((Constant
) sym
);
749 } else if (sym is Field
) {
750 st
.add_field ((Field
) sym
);
751 } else if (sym is Method
) {
752 st
.add_method ((Method
) sym
);
753 } else if (sym is Property
) {
754 st
.add_property ((Property
) sym
);
757 Report
.error (sym
.source_reference
, "impossible to add to container `%s'".printf (container
.name
));
761 UnresolvedSymbol?
parse_symbol_from_string (string symbol_string
, SourceReference? source_reference
= null) {
762 UnresolvedSymbol? sym
= null;
763 foreach (unowned
string s
in symbol_string
.split (".")) {
764 sym
= new
UnresolvedSymbol (sym
, s
, source_reference
);
767 Report
.error (source_reference
, "a symbol must be specified");
772 UnresolvedSymbol
get_unresolved_symbol (Symbol symbol
) {
773 if (symbol is UnresolvedSymbol
) {
774 return (UnresolvedSymbol
) symbol
;
776 var sym
= new
UnresolvedSymbol (null, symbol
.name
);
778 var cur
= symbol
.parent_node as Symbol
;
779 while (cur
!= null && cur
.name
!= null) {
780 sym
= new
UnresolvedSymbol (sym
, cur
.name
);
781 cur
= cur
.parent_node as Symbol
;
786 void set_symbol_mapping (Symbol map_from
, Symbol map_to
) {
787 // last mapping is the most up-to-date
788 if (map_from is UnresolvedSymbol
) {
789 unresolved_symbols_map
[(UnresolvedSymbol
) map_from
] = map_to
;
791 concrete_symbols_map
[map_from
] = map_to
;
795 void assume_parameter_names (Signal sig
, Symbol sym
, bool skip_first
) {
796 Iterator
<Parameter
> iter
;
798 iter
= ((Method
) sym
).get_parameters ().iterator ();
800 iter
= ((Delegate
) sym
).get_parameters ().iterator ();
803 foreach (var param
in sig
.get_parameters ()) {
805 // unreachable for valid GIR
808 if (skip_first
&& first
) {
810 // unreachable for valid GIR
815 param
.name
= iter
.get ().name
;
819 SymbolInfo?
add_symbol_info (Symbol symbol
) {
820 var name
= symbol
.name
;
821 if (symbol is CreationMethod
&& name
== null) {
825 var info
= new
SymbolInfo ();
826 info
.symbol
= symbol
;
827 info
.metadata
= metadata
;
828 info
.girdata
= girdata
;
829 current_symbols_info
.add (info
);
833 ArrayList
<SymbolInfo
> get_colliding_symbols_info (SymbolInfo info
) {
834 var name
= info
.symbol
.name
;
835 if (name
== null && info
.symbol is CreationMethod
) {
838 var result
= new ArrayList
<SymbolInfo
> ();
839 foreach (var cinfo
in current_symbols_info
) {
840 if (cinfo
.symbol
.name
== name
) {
847 SymbolInfo?
get_current_first_symbol_info (string name
) {
848 foreach (var info
in current_symbols_info
) {
849 if (info
.symbol
.name
== name
) {
856 Symbol?
get_current_first_symbol (string name
) {
857 var info
= get_current_first_symbol_info (name
);
864 SymbolInfo?
find_invoker (Method method
) {
865 /* most common use case is invoker has at least the given method prefix
866 and the same parameter names */
867 var prefix
= "%s_".printf (method
.name
);
868 foreach (var info
in current_symbols_info
) {
869 if (!info
.symbol
.name
.has_prefix (prefix
)) {
872 Method? invoker
= info
.symbol as Method
;
873 if (invoker
== null || (method
.get_parameters ().size
!= invoker
.get_parameters ().size
)) {
876 var iter
= invoker
.get_parameters ().iterator ();
877 foreach (var param
in method
.get_parameters ()) {
878 assert (iter
.next ());
879 if (param
.name
!= iter
.get ().name
) {
884 if (invoker
!= null) {
892 void merge (SymbolInfo info
, ArrayList
<SymbolInfo
> colliding
, HashSet
<SymbolInfo
> merged
) {
893 if (info
.symbol is Struct
) {
894 var gtype_struct_for
= info
.girdata
["glib:is-gtype-struct-for"];
895 if (gtype_struct_for
!= null) {
896 var iface
= get_current_first_symbol (gtype_struct_for
) as Interface
;
898 // set the interface struct name
899 iface
.set_type_cname (((Struct
) info
.symbol
).get_cname ());
903 } else if (info
.symbol is Property
) {
904 var prop
= (Property
) info
.symbol
;
905 foreach (var cinfo
in colliding
) {
906 var sym
= cinfo
.symbol
;
907 if (sym is Signal
|| sym is Field
) {
908 // properties take precedence
910 } else if (sym is Method
) {
911 // assume method is getter
915 var getter_name
= "get_%s".printf (prop
.name
);
916 var setter_name
= "set_%s".printf (prop
.name
);
917 if (prop
.get_accessor
!= null) {
918 var getter_method
= get_current_first_symbol (getter_name
) as Method
;
919 if (getter_method
!= null) {
920 prop
.no_accessor_method
= false;
921 prop
.get_accessor
.value_type
.value_owned
= getter_method
.return_type
.value_owned
;
923 } else if (prop
.set_accessor
!= null && get_current_first_symbol_info (setter_name
) != null) {
924 prop
.no_accessor_method
= false;
926 } else if (info
.symbol is Signal
) {
927 var sig
= (Signal
) info
.symbol
;
928 foreach (var cinfo
in colliding
) {
929 var sym
= cinfo
.symbol
;
931 var method
= (Method
) sym
;
932 if (method
.is_virtual
) {
933 sig
.is_virtual
= true;
935 sig
.has_emitter
= true;
937 assume_parameter_names (sig
, method
, false);
939 } else if (sym is Field
) {
943 } else if (info
.symbol is Method
&& !(info
.symbol is CreationMethod
)) {
944 var m
= (Method
) info
.symbol
;
945 foreach (var cinfo
in colliding
) {
946 var sym
= cinfo
.symbol
;
947 if (sym
!= m
&& m
.is_virtual
&& sym is Method
) {
948 bool different_invoker
= false;
949 foreach (var attr
in m
.attributes
) {
950 if (attr
.name
== "NoWrapper") {
951 /* no invoker but this method has the same name,
952 most probably the invoker has a different name
953 and g-ir-scanner missed it */
954 var invoker
= find_invoker (m
);
955 if (invoker
!= null) {
956 m
.vfunc_name
= m
.name
;
957 m
.name
= invoker
.symbol
.name
;
958 m
.attributes
.remove (attr
);
959 merged
.add (invoker
);
960 different_invoker
= true;
965 if (!different_invoker
) {
970 // merge custom vfunc
971 if (info
.metadata
.has_argument (ArgumentType
.VFUNC_NAME
)) {
972 var vfunc
= get_current_first_symbol_info (info
.metadata
.get_string (ArgumentType
.VFUNC_NAME
));
973 if (vfunc
!= null && vfunc
!= info
) {
978 // handle async methods
979 string finish_method_base
;
980 if (m
.name
.has_suffix ("_async")) {
981 finish_method_base
= m
.name
.substring (0, m
.name
.length
- "_async".length
);
983 finish_method_base
= m
.name
;
985 var finish_method_info
= get_current_first_symbol_info (finish_method_base
+ "_finish");
987 // check if the method is using non-standard finish method name
988 if (finish_method_info
== null) {
989 var method_cname
= m
.get_finish_cname ();
990 foreach (var minfo
in current_symbols_info
) {
991 if (minfo
.symbol is Method
&& ((Method
) minfo
.symbol
).get_cname () == method_cname
) {
992 finish_method_info
= minfo
;
998 if (finish_method_info
!= null && finish_method_info
.symbol is Method
) {
999 var finish_method
= (Method
) finish_method_info
.symbol
;
1001 if (finish_method is CreationMethod
) {
1002 method
= new
CreationMethod (((CreationMethod
) finish_method
).class_name
, null, m
.source_reference
);
1003 method
.access
= m
.access
;
1004 method
.binding
= m
.binding
;
1005 method
.external
= true;
1006 method
.coroutine
= true;
1007 method
.has_construct_function
= finish_method
.has_construct_function
;
1008 method
.attributes
= m
.attributes
.copy ();
1009 method
.set_cname (m
.get_cname ());
1010 if (finish_method_base
== "new") {
1012 } else if (finish_method_base
.has_prefix ("new_")) {
1013 method
.name
= m
.name
.substring ("new_".length
);
1015 foreach (var param
in m
.get_parameters ()) {
1016 method
.add_parameter (param
);
1018 info
.symbol
= method
;
1022 method
.return_type
= finish_method
.return_type
.copy ();
1023 method
.no_array_length
= finish_method
.no_array_length
;
1024 method
.array_null_terminated
= finish_method
.array_null_terminated
;
1025 foreach (var param
in finish_method
.get_parameters ()) {
1026 if (param
.direction
== ParameterDirection
.OUT
) {
1027 var async_param
= param
.copy ();
1028 if (method
.scope
.lookup (param
.name
) != null) {
1029 // parameter name conflict
1030 async_param
.name
+= "_out";
1032 method
.add_parameter (async_param
);
1035 foreach (DataType error_type
in finish_method
.get_error_types ()) {
1036 method
.add_error_type (error_type
.copy ());
1038 merged
.add (finish_method_info
);
1041 } else if (info
.symbol is Field
) {
1042 foreach (var cinfo
in colliding
) {
1043 var sym
= cinfo
.symbol
;
1044 if (sym is Method
) {
1045 // assume method is getter
1050 var field
= (Field
) info
.symbol
;
1051 if (field
.variable_type is ArrayType
) {
1052 var array_length
= get_current_first_symbol_info ("n_%s".printf (field
.name
));
1053 if (array_length
== null) {
1054 array_length
= get_current_first_symbol_info ("%s_length".printf (field
.name
));
1056 if (array_length
!= null) {
1058 field
.set_array_length_cname (array_length
.symbol
.name
);
1059 field
.no_array_length
= false;
1060 merged
.add (array_length
);
1066 void postprocess_symbol (Symbol sym
, Metadata metadata
) {
1068 sym
.replacement
= metadata
.get_string (ArgumentType
.REPLACEMENT
);
1069 sym
.deprecated_since
= element_get_string ("deprecated-version", ArgumentType
.DEPRECATED_SINCE
);
1070 sym
.deprecated
= metadata
.get_bool (ArgumentType
.DEPRECATED
) || sym
.replacement
!= null || sym
.deprecated_since
!= null;
1072 // mark to be reparented
1073 if (metadata
.has_argument (ArgumentType
.PARENT
)) {
1074 var target_symbol
= parse_symbol_from_string (metadata
.get_string (ArgumentType
.PARENT
), metadata
.get_source_reference (ArgumentType
.PARENT
));
1075 var reparent_list
= symbol_reparent_map
[target_symbol
];
1076 if (reparent_list
== null) {
1077 reparent_list
= new ArrayList
<Symbol
>();
1078 symbol_reparent_map
[target_symbol
] = reparent_list
;
1080 reparent_list
.add (sym
);
1082 // if referenceable, map unresolved references to point to the new place
1083 if (sym is Namespace
|| sym is TypeSymbol
) {
1084 set_symbol_mapping (sym
, new
UnresolvedSymbol (target_symbol
, sym
.name
));
1089 var cl
= (Class
) sym
;
1090 if (cl
.default_construction_method
== null) {
1091 // always provide constructor in generated bindings
1092 // to indicate that implicit Object () chainup is allowed
1093 var cm
= new
CreationMethod (null, null, cl
.source_reference
);
1094 cm
.has_construct_function
= false;
1095 cm
.access
= SymbolAccessibility
.PROTECTED
;
1101 void merge_add_process (Symbol container
) {
1102 var merged
= new HashSet
<SymbolInfo
> ();
1103 foreach (var info
in current_symbols_info
) {
1104 merge (info
, get_colliding_symbols_info (info
), merged
);
1107 foreach (var info
in current_symbols_info
) {
1108 if (merged
.contains (info
) || info
.metadata
.get_bool (ArgumentType
.HIDDEN
)) {
1111 if (!(current_symbol is Namespace
&& info
.symbol is Method
) && !info
.metadata
.has_argument (ArgumentType
.PARENT
)) {
1112 add_symbol_to_container (container
, info
.symbol
);
1114 postprocess_symbol (info
.symbol
, info
.metadata
);
1118 Metadata
get_current_metadata () {
1119 var name
= reader
.name
;
1120 var child_name
= reader
.get_attribute ("name");
1121 if (child_name
== null) {
1122 return Metadata
.empty
;
1125 var type
= MetadataType
.GENERIC
;
1126 if (name
== "glib:signal") {
1127 child_name
= child_name
.replace ("-", "_");
1128 type
= MetadataType
.SIGNAL
;
1129 } else if (name
== "property") {
1130 type
= MetadataType
.PROPERTY
;
1133 return metadata
.match_child (child_name
, type
);
1136 bool push_metadata () {
1137 var new_metadata
= get_current_metadata ();
1139 if (new_metadata
.has_argument (ArgumentType
.SKIP
)) {
1140 if (new_metadata
.get_bool (ArgumentType
.SKIP
)) {
1143 } else if (reader
.get_attribute ("introspectable") == "0") {
1147 metadata_stack
.add (metadata
);
1148 metadata
= new_metadata
;
1149 girdata_stack
.add (girdata
);
1150 girdata
= new HashMap
<string,string> (str_hash
, str_equal
);
1155 void pop_metadata () {
1156 metadata
= metadata_stack
[metadata_stack
.size
- 1];
1157 metadata_stack
.remove_at (metadata_stack
.size
- 1);
1158 girdata
= girdata_stack
[girdata_stack
.size
- 1];
1159 girdata_stack
.remove_at (girdata_stack
.size
- 1);
1162 bool parse_type_arguments_from_string (DataType parent_type
, string type_arguments
, SourceReference? source_reference
= null) {
1163 int type_arguments_length
= (int) type_arguments
.length
;
1164 GLib
.StringBuilder current
= new GLib
.StringBuilder
.sized (type_arguments_length
);
1167 for (var c
= 0 ; c
< type_arguments_length
; c
++) {
1168 if (type_arguments
[c
] == '<' || type_arguments
[c
] == '[') {
1170 current
.append_unichar (type_arguments
[c
]);
1171 } else if (type_arguments
[c
] == '>' || type_arguments
[c
] == ']') {
1173 current
.append_unichar (type_arguments
[c
]);
1174 } else if (type_arguments
[c
] == ',') {
1176 var dt
= parse_type_from_string (current
.str
, true, source_reference
);
1180 parent_type
.add_type_argument (dt
);
1181 current
.truncate ();
1183 current
.append_unichar (type_arguments
[c
]);
1186 current
.append_unichar (type_arguments
[c
]);
1190 var dt
= parse_type_from_string (current
.str
, true, source_reference
);
1194 parent_type
.add_type_argument (dt
);
1199 DataType?
parse_type_from_string (string type_string
, bool owned_by_default
, SourceReference? source_reference
= null) {
1200 if (type_from_string_regex
== null) {
1202 type_from_string_regex
= new GLib
.Regex ("^(?:(owned|unowned|weak) +)?([0-9a-zA-Z_\\.]+)(?:<(.+)>)?(\\*+)?(\\[,*\\])?(\\?)?$", GLib
.RegexCompileFlags
.ANCHORED
| GLib
.RegexCompileFlags
.DOLLAR_ENDONLY
| GLib
.RegexCompileFlags
.OPTIMIZE
);
1203 } catch (GLib
.RegexError e
) {
1204 GLib
.error ("Unable to compile regex: %s", e
.message
);
1208 GLib
.MatchInfo match
;
1209 if (!type_from_string_regex
.match (type_string
, 0, out match
)) {
1210 Report
.error (source_reference
, "unable to parse type");
1214 DataType? type
= null;
1216 var ownership_data
= match
.fetch (1);
1217 var type_name
= match
.fetch (2);
1218 var type_arguments_data
= match
.fetch (3);
1219 var pointers_data
= match
.fetch (4);
1220 var array_data
= match
.fetch (5);
1221 var nullable_data
= match
.fetch (6);
1223 var nullable
= nullable_data
!= null && nullable_data
.length
> 0;
1225 if (ownership_data
== null && type_name
== "void") {
1226 if (array_data
== null && !nullable
) {
1227 type
= new
VoidType (source_reference
);
1228 if (pointers_data
!= null) {
1229 for (int i
=0; i
< pointers_data
.length
; i
++) {
1230 type
= new
PointerType (type
);
1235 Report
.error (source_reference
, "invalid void type");
1240 bool value_owned
= owned_by_default
;
1242 if (ownership_data
== "owned") {
1243 if (owned_by_default
) {
1244 Report
.error (source_reference
, "unexpected `owned' keyword");
1248 } else if (ownership_data
== "unowned") {
1249 if (owned_by_default
) {
1250 value_owned
= false;
1252 Report
.error (source_reference
, "unexpected `unowned' keyword");
1257 var sym
= parse_symbol_from_string (type_name
, source_reference
);
1261 type
= new UnresolvedType
.from_symbol (sym
, source_reference
);
1263 if (type_arguments_data
!= null && type_arguments_data
.length
> 0) {
1264 if (!parse_type_arguments_from_string (type
, type_arguments_data
, source_reference
)) {
1269 if (pointers_data
!= null) {
1270 for (int i
=0; i
< pointers_data
.length
; i
++) {
1271 type
= new
PointerType (type
);
1275 if (array_data
!= null) {
1276 type
= new
ArrayType (type
, (int) array_data
.length
- 1, source_reference
);
1279 type
.nullable
= nullable
;
1280 type
.value_owned
= value_owned
;
1284 string?
element_get_string (string attribute_name
, ArgumentType arg_type
) {
1285 if (metadata
.has_argument (arg_type
)) {
1286 return metadata
.get_string (arg_type
);
1288 return reader
.get_attribute (attribute_name
);
1293 * The changed is a faster way to check whether the type has changed and it may affect the C declaration.
1294 * If type arguments change, the C declaration is not affected.
1296 DataType?
element_get_type (DataType orig_type
, bool owned_by_default
, out bool changed
= null) {
1298 var type
= orig_type
;
1300 if (metadata
.has_argument (ArgumentType
.TYPE
)) {
1301 var new_type
= parse_type_from_string (metadata
.get_string (ArgumentType
.TYPE
), owned_by_default
, metadata
.get_source_reference (ArgumentType
.TYPE
));
1306 if (type is VoidType
) {
1310 if (metadata
.has_argument (ArgumentType
.TYPE_ARGUMENTS
)) {
1311 type
.remove_all_type_arguments ();
1312 parse_type_arguments_from_string (type
, metadata
.get_string (ArgumentType
.TYPE_ARGUMENTS
), metadata
.get_source_reference (ArgumentType
.TYPE_ARGUMENTS
));
1315 if (metadata
.get_bool (ArgumentType
.ARRAY
)) {
1316 type
= new
ArrayType (type
, 1, type
.source_reference
);
1320 if (owned_by_default
) {
1321 if (metadata
.has_argument (ArgumentType
.UNOWNED
)) {
1322 type
.value_owned
= !metadata
.get_bool (ArgumentType
.UNOWNED
);
1325 if (metadata
.has_argument (ArgumentType
.OWNED
)) {
1326 type
.value_owned
= metadata
.get_bool (ArgumentType
.OWNED
);
1329 if (metadata
.has_argument (ArgumentType
.NULLABLE
)) {
1330 type
.nullable
= metadata
.get_bool (ArgumentType
.NULLABLE
);
1336 string?
element_get_name (bool remap
= false) {
1337 var name
= reader
.get_attribute ("name");
1338 var orig_name
= name
;
1339 var pattern
= metadata
.get_string (ArgumentType
.NAME
);
1340 if (pattern
!= null) {
1342 var regex
= new
Regex (pattern
, RegexCompileFlags
.ANCHORED
, RegexMatchFlags
.ANCHORED
);
1343 GLib
.MatchInfo match
;
1344 if (!regex
.match (name
, 0, out match
)) {
1347 var matched
= match
.fetch (1);
1348 if (matched
!= null && matched
.length
> 0) {
1358 if (name
!= null && name
.has_suffix ("Enum")) {
1359 name
= name
.substring (0, name
.length
- "Enum".length
);
1362 if (name
!= orig_name
&& remap
) {
1363 set_symbol_mapping (parse_symbol_from_string (orig_name
), parse_symbol_from_string (name
));
1369 void set_array_ccode (Symbol sym
, ParameterInfo info
) {
1370 if (sym is Method
) {
1371 var m
= (Method
) sym
;
1372 m
.carray_length_parameter_position
= info
.vala_idx
;
1373 } else if (sym is Delegate
) {
1374 var d
= (Delegate
) sym
;
1375 d
.carray_length_parameter_position
= info
.vala_idx
;
1377 var param
= (Parameter
) sym
;
1378 param
.carray_length_parameter_position
= info
.vala_idx
;
1379 param
.set_array_length_cname (info
.param
.name
);
1381 if (info
.param
.variable_type
.to_qualified_string () != "int") {
1382 var unresolved_type
= (UnresolvedType
) info
.param
.variable_type
;
1383 var resolved_struct
= resolve_symbol (glib_ns
.scope
, unresolved_type
.unresolved_symbol
) as Struct
;
1384 if (resolved_struct
!= null) {
1385 if (sym is Method
) {
1386 var m
= (Method
) sym
;
1387 m
.array_length_type
= resolved_struct
.get_cname ();
1389 var param
= (Parameter
) sym
;
1390 param
.array_length_type
= resolved_struct
.get_cname ();
1396 void parse_repository () {
1397 start_element ("repository");
1398 if (reader
.get_attribute ("version") != GIR_VERSION
) {
1399 Report
.error (get_current_src (), "unsupported GIR version %s (supported: %s)".printf (reader
.get_attribute ("version"), GIR_VERSION
));
1403 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1404 if (reader
.name
== "namespace") {
1405 var ns
= parse_namespace ();
1407 context
.root
.add_namespace (ns
);
1409 } else if (reader
.name
== "include") {
1411 } else if (reader
.name
== "package") {
1412 var pkg
= parse_package ();
1413 if (context
.has_package (pkg
)) {
1414 // package already provided elsewhere, stop parsing this GIR
1417 context
.add_package (pkg
);
1419 } else if (reader
.name
== "c:include") {
1423 Report
.error (get_current_src (), "unknown child element `%s' in `repository'".printf (reader
.name
));
1427 end_element ("repository");
1429 report_unused_metadata (metadata
);
1432 void parse_include () {
1433 start_element ("include");
1434 var pkg
= reader
.get_attribute ("name");
1435 var version
= reader
.get_attribute ("version");
1436 if (version
!= null) {
1437 pkg
= "%s-%s".printf (pkg
, version
);
1439 // add the package to the queue
1440 context
.add_external_package (pkg
);
1442 end_element ("include");
1445 string parse_package () {
1446 start_element ("package");
1447 var pkg
= reader
.get_attribute ("name");
1449 end_element ("package");
1453 void parse_c_include () {
1454 start_element ("c:include");
1455 cheader_filenames
+= reader
.get_attribute ("name");
1457 end_element ("c:include");
1460 void skip_element () {
1465 if (current_token
== MarkupTokenType
.START_ELEMENT
) {
1467 } else if (current_token
== MarkupTokenType
.END_ELEMENT
) {
1469 } else if (current_token
== MarkupTokenType
.EOF
) {
1470 Report
.error (get_current_src (), "unexpected end of file");
1477 Namespace?
parse_namespace () {
1478 start_element ("namespace");
1480 bool new_namespace
= false;
1481 string? cprefix
= reader
.get_attribute ("c:identifier-prefixes");
1482 string namespace_name
= cprefix
;
1483 string gir_namespace
= reader
.get_attribute ("name");
1484 string gir_version
= reader
.get_attribute ("version");
1485 if (namespace_name
== null) {
1486 namespace_name
= gir_namespace
;
1488 current_source_file
.gir_namespace
= gir_namespace
;
1489 current_source_file
.gir_version
= gir_version
;
1491 var ns_metadata
= metadata
.match_child (gir_namespace
);
1492 if (ns_metadata
.has_argument (ArgumentType
.NAME
)) {
1493 namespace_name
= ns_metadata
.get_string (ArgumentType
.NAME
);
1496 var ns
= context
.root
.scope
.lookup (namespace_name
) as Namespace
;
1498 ns
= new
Namespace (namespace_name
, get_current_src ());
1499 new_namespace
= true;
1501 if (ns
.external_package
) {
1502 ns
.attributes
= null;
1503 ns
.source_reference
= get_current_src ();
1507 if (gir_namespace
!= ns
.name
) {
1508 set_symbol_mapping (new
UnresolvedSymbol (null, gir_namespace
), ns
);
1511 if (cprefix
!= null) {
1512 ns
.add_cprefix (cprefix
);
1513 ns
.set_lower_case_cprefix (Symbol
.camel_case_to_lower_case (cprefix
) + "_");
1516 if (ns_metadata
.has_argument (ArgumentType
.CHEADER_FILENAME
)) {
1517 var val
= ns_metadata
.get_string (ArgumentType
.CHEADER_FILENAME
);
1518 foreach (string filename
in val
.split (",")) {
1519 ns
.add_cheader_filename (filename
);
1522 foreach (string c_header
in cheader_filenames
) {
1523 ns
.add_cheader_filename (c_header
);
1528 var current_namespace_methods
= namespace_methods
[ns
];
1529 if (current_namespace_methods
== null) {
1530 current_namespace_methods
= new ArrayList
<Method
> ();
1531 namespace_methods
[ns
] = current_namespace_methods
;
1533 var old_symbols_info
= current_symbols_info
;
1534 var old_symbol
= current_symbol
;
1535 current_symbols_info
= new ArrayList
<SymbolInfo
> ();
1536 current_symbol
= ns
;
1537 gtype_callbacks
= new HashMap
<UnresolvedSymbol
,ArrayList
<Delegate
>> (unresolved_symbol_hash
, unresolved_symbol_equal
);
1538 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1539 if (!push_metadata ()) {
1544 if (reader
.name
== "alias") {
1545 var alias
= parse_alias ();
1546 aliases
.add (alias
);
1547 } else if (reader
.name
== "enumeration") {
1548 if (reader
.get_attribute ("glib:error-quark") != null) {
1549 add_symbol_info (parse_error_domain ());
1551 add_symbol_info (parse_enumeration ());
1553 } else if (reader
.name
== "bitfield") {
1554 add_symbol_info (parse_bitfield ());
1555 } else if (reader
.name
== "function") {
1556 var method
= parse_method ("function");
1557 add_symbol_info (method
);
1558 current_namespace_methods
.add (method
);
1559 } else if (reader
.name
== "callback") {
1560 add_symbol_info (parse_callback ());
1561 } else if (reader
.name
== "record") {
1562 if (reader
.get_attribute ("glib:get-type") != null) {
1563 add_symbol_info (parse_boxed ("record"));
1565 if (!reader
.get_attribute ("name").has_suffix ("Private")) {
1566 add_symbol_info (parse_record ());
1571 } else if (reader
.name
== "class") {
1572 add_symbol_info (parse_class ());
1573 } else if (reader
.name
== "interface") {
1574 var iface
= parse_interface ();
1575 add_symbol_info (iface
);
1576 interfaces
.add (iface
);
1577 } else if (reader
.name
== "glib:boxed") {
1578 add_symbol_info (parse_boxed ("glib:boxed"));
1579 } else if (reader
.name
== "union") {
1580 add_symbol_info (parse_union ());
1581 } else if (reader
.name
== "constant") {
1582 add_symbol_info (parse_constant ());
1585 Report
.error (get_current_src (), "unknown child element `%s' in `namespace'".printf (reader
.name
));
1591 end_element ("namespace");
1593 merge_add_process (ns
);
1594 current_symbols_info
= old_symbols_info
;
1595 current_symbol
= old_symbol
;
1596 postprocess_gtype_callbacks (ns
);
1598 if (!new_namespace
) {
1605 Alias
parse_alias () {
1606 // alias has no type information
1607 start_element ("alias");
1608 var alias
= new
Alias ();
1609 alias
.source_reference
= get_current_src ();
1610 alias
.name
= reader
.get_attribute ("name");
1611 alias
.cname
= reader
.get_attribute ("c:type");
1612 alias
.parent_symbol
= current_symbol
;
1615 alias
.base_type
= element_get_type (parse_type (null, null, true), true);
1617 end_element ("alias");
1621 private void calculate_common_prefix (ref string common_prefix
, string cname
) {
1622 if (common_prefix
== null) {
1623 common_prefix
= cname
;
1624 while (common_prefix
.length
> 0 && !common_prefix
.has_suffix ("_")) {
1625 // FIXME: could easily be made faster
1626 common_prefix
= common_prefix
.substring (0, common_prefix
.length
- 1);
1629 while (!cname
.has_prefix (common_prefix
)) {
1630 common_prefix
= common_prefix
.substring (0, common_prefix
.length
- 1);
1633 while (common_prefix
.length
> 0 && (!common_prefix
.has_suffix ("_") ||
1634 (cname
.get_char (common_prefix
.length
).isdigit ()) && (cname
.length
- common_prefix
.length
) <= 1)) {
1635 // enum values may not consist solely of digits
1636 common_prefix
= common_prefix
.substring (0, common_prefix
.length
- 1);
1640 Symbol
parse_enumeration (string element_name
= "enumeration", bool error_domain
= false) {
1641 start_element (element_name
);
1645 sym
= new
ErrorDomain (element_get_name (true), get_current_src ());
1647 var en
= new
Enum (element_get_name (), get_current_src ());
1648 if (element_name
== "bitfield") {
1653 sym
.access
= SymbolAccessibility
.PUBLIC
;
1655 string cname
= reader
.get_attribute ("c:type");
1656 string common_prefix
= null;
1660 var old_symbol
= current_symbol
;
1661 current_symbol
= sym
;
1662 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1663 if (!push_metadata ()) {
1668 if (reader
.name
== "member") {
1670 ErrorCode ec
= parse_error_member ();
1671 ((ErrorDomain
) sym
).add_code (ec
);
1672 calculate_common_prefix (ref common_prefix
, ec
.get_cname ());
1674 var ev
= parse_enumeration_member ();
1675 ((Enum
) sym
).add_value (ev
);
1676 calculate_common_prefix (ref common_prefix
, ev
.get_cname ());
1680 Report
.error (get_current_src (), "unknown child element `%s' in `%s'".printf (reader
.name
, element_name
));
1687 if (cname
!= null) {
1689 ((Enum
) sym
).set_cname (cname
);
1690 ((Enum
) sym
).set_cprefix (common_prefix
);
1692 ((ErrorDomain
) sym
).set_cname (cname
);
1693 ((ErrorDomain
) sym
).set_cprefix (common_prefix
);
1697 end_element (element_name
);
1698 current_symbol
= old_symbol
;
1702 ErrorDomain
parse_error_domain () {
1703 return parse_enumeration ("enumeration", true) as ErrorDomain
;
1706 Enum
parse_bitfield () {
1707 return parse_enumeration ("bitfield") as Enum
;
1710 EnumValue
parse_enumeration_member () {
1711 start_element ("member");
1712 var ev
= new
EnumValue (reader
.get_attribute ("name").up ().replace ("-", "_"), null, get_current_src ());
1713 ev
.set_cname (reader
.get_attribute ("c:identifier"));
1715 end_element ("member");
1719 ErrorCode
parse_error_member () {
1720 start_element ("member");
1723 string name
= reader
.get_attribute ("name").up ().replace ("-", "_");
1724 string value
= reader
.get_attribute ("value");
1725 if (value
!= null) {
1726 ec
= new ErrorCode
.with_value (name
, new
IntegerLiteral (value
));
1728 ec
= new
ErrorCode (name
);
1730 ec
.set_cname (reader
.get_attribute ("c:identifier"));
1733 end_element ("member");
1737 DataType
parse_return_value (out string? ctype
= null) {
1738 start_element ("return-value");
1739 string transfer
= reader
.get_attribute ("transfer-ownership");
1740 string allow_none
= reader
.get_attribute ("allow-none");
1742 var transfer_elements
= transfer
== "full";
1743 var type
= parse_type (out ctype
, null, transfer_elements
);
1744 if (transfer
== "full" || transfer
== "container") {
1745 type
.value_owned
= true;
1747 if (allow_none
== "1") {
1748 type
.nullable
= true;
1750 end_element ("return-value");
1754 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) {
1757 array_length_idx
= -1;
1761 start_element ("parameter");
1762 string name
= reader
.get_attribute ("name");
1764 name
= default_name
;
1766 string direction
= null;
1767 if (metadata
.has_argument (ArgumentType
.OUT
)) {
1768 if (metadata
.get_bool (ArgumentType
.OUT
)) {
1771 } else if (metadata
.has_argument (ArgumentType
.REF
)) {
1772 if (metadata
.get_bool (ArgumentType
.REF
)) {
1773 direction
= "inout";
1776 direction
= reader
.get_attribute ("direction");
1778 string transfer
= reader
.get_attribute ("transfer-ownership");
1779 string allow_none
= reader
.get_attribute ("allow-none");
1781 scope
= element_get_string ("scope", ArgumentType
.SCOPE
);
1783 string closure
= reader
.get_attribute ("closure");
1784 string destroy
= reader
.get_attribute ("destroy");
1785 if (closure
!= null && &closure_idx
!= null) {
1786 closure_idx
= int.parse (closure
);
1788 if (destroy
!= null && &destroy_idx
!= null) {
1789 destroy_idx
= int.parse (destroy
);
1793 if (reader
.name
== "varargs") {
1794 start_element ("varargs");
1796 param
= new Parameter
.with_ellipsis (get_current_src ());
1797 end_element ("varargs");
1800 var type
= parse_type (out ctype
, out array_length_idx
, transfer
== "full");
1802 type
= element_get_type (type
, false, out changed
);
1804 // discard ctype, duplicated information
1808 if (type is ArrayType
&& metadata
.has_argument (ArgumentType
.ARRAY_LENGTH_IDX
)) {
1809 array_length_idx
= metadata
.get_integer (ArgumentType
.ARRAY_LENGTH_IDX
);
1812 if (transfer
== "full" || transfer
== "container" || destroy
!= null) {
1813 type
.value_owned
= true;
1815 if (allow_none
== "1") {
1816 type
.nullable
= true;
1818 param
= new
Parameter (name
, type
, get_current_src ());
1819 param
.ctype
= ctype
;
1820 if (direction
== "out") {
1821 param
.direction
= ParameterDirection
.OUT
;
1822 } else if (direction
== "inout") {
1823 param
.direction
= ParameterDirection
.REF
;
1825 param
.initializer
= metadata
.get_expression (ArgumentType
.DEFAULT
);
1827 end_element ("parameter");
1831 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) {
1832 bool is_array
= false;
1833 string type_name
= reader
.get_attribute ("name");
1835 array_length_index
= -1;
1837 if (reader
.name
== "array") {
1839 start_element ("array");
1841 if (type_name
== null) {
1842 if (reader
.get_attribute ("length") != null
1843 && &array_length_index
!= null) {
1844 array_length_index
= int.parse (reader
.get_attribute ("length"));
1847 var element_type
= parse_type ();
1848 end_element ("array");
1849 return new
ArrayType (element_type
, 1, null);
1851 } else if (reader
.name
== "callback"){
1852 var callback = parse_callback ();
1853 return new
DelegateType (callback);
1855 start_element ("type");
1858 ctype
= reader
.get_attribute("c:type");
1862 if (type_name
== "GLib.PtrArray"
1863 && current_token
== MarkupTokenType
.START_ELEMENT
) {
1864 type_name
= "GLib.GenericArray";
1867 DataType type
= parse_type_from_gir_name (type_name
, out no_array_length
, out array_null_terminated
, ctype
);
1869 // type arguments / element types
1870 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1871 if (type_name
== "GLib.ByteArray") {
1875 var element_type
= parse_type ();
1876 element_type
.value_owned
= transfer_elements
;
1877 type
.add_type_argument (element_type
);
1880 end_element (is_array ?
"array" : "type");
1884 DataType
parse_type_from_gir_name (string type_name
, out bool no_array_length
= null, out bool array_null_terminated
= null, string? ctype
= null) {
1885 no_array_length
= false;
1886 array_null_terminated
= false;
1889 if (type_name
== "none") {
1890 type
= new
VoidType (get_current_src ());
1891 } else if (type_name
== "gpointer") {
1892 type
= new
PointerType (new
VoidType (get_current_src ()), get_current_src ());
1893 } else if (type_name
== "GObject.Strv") {
1894 type
= new
ArrayType (new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, "string")), 1, get_current_src ());
1895 no_array_length
= true;
1896 array_null_terminated
= true;
1898 bool known_type
= true;
1899 if (type_name
== "utf8") {
1900 type_name
= "string";
1901 } else if (type_name
== "gboolean") {
1903 } else if (type_name
== "gchar") {
1905 } else if (type_name
== "gshort") {
1906 type_name
= "short";
1907 } else if (type_name
== "gushort") {
1908 type_name
= "ushort";
1909 } else if (type_name
== "gint") {
1911 } else if (type_name
== "guint") {
1913 } else if (type_name
== "glong") {
1914 if (ctype
!= null && ctype
.has_prefix ("gssize")) {
1915 type_name
= "ssize_t";
1919 } else if (type_name
== "gulong") {
1920 if (ctype
!= null && ctype
.has_prefix ("gsize")) {
1921 type_name
= "size_t";
1923 type_name
= "ulong";
1925 } else if (type_name
== "gint8") {
1927 } else if (type_name
== "guint8") {
1928 type_name
= "uint8";
1929 } else if (type_name
== "gint16") {
1930 type_name
= "int16";
1931 } else if (type_name
== "guint16") {
1932 type_name
= "uint16";
1933 } else if (type_name
== "gint32") {
1934 type_name
= "int32";
1935 } else if (type_name
== "guint32") {
1936 type_name
= "uint32";
1937 } else if (type_name
== "gint64") {
1938 type_name
= "int64";
1939 } else if (type_name
== "guint64") {
1940 type_name
= "uint64";
1941 } else if (type_name
== "gfloat") {
1942 type_name
= "float";
1943 } else if (type_name
== "gdouble") {
1944 type_name
= "double";
1945 } else if (type_name
== "filename") {
1946 type_name
= "string";
1947 } else if (type_name
== "GLib.offset") {
1948 type_name
= "int64";
1949 } else if (type_name
== "gsize") {
1950 type_name
= "size_t";
1951 } else if (type_name
== "gssize") {
1952 type_name
= "ssize_t";
1953 } else if (type_name
== "GType") {
1954 type_name
= "GLib.Type";
1955 } else if (type_name
== "GLib.String") {
1956 type_name
= "GLib.StringBuilder";
1957 } else if (type_name
== "GObject.Class") {
1958 type_name
= "GLib.ObjectClass";
1959 } else if (type_name
== "GLib.unichar") {
1960 type_name
= "unichar";
1961 } else if (type_name
== "GLib.Data") {
1962 type_name
= "GLib.Datalist";
1963 } else if (type_name
== "Atk.ImplementorIface") {
1964 type_name
= "Atk.Implementor";
1968 var sym
= parse_symbol_from_string (type_name
, get_current_src ());
1969 type
= new UnresolvedType
.from_symbol (sym
, get_current_src ());
1971 unresolved_gir_symbols
.add (sym
);
1978 Struct
parse_record () {
1979 start_element ("record");
1980 var st
= new
Struct (reader
.get_attribute ("name"), get_current_src ());
1982 st
.access
= SymbolAccessibility
.PUBLIC
;
1984 string cname
= reader
.get_attribute ("c:type");
1985 if (cname
!= null) {
1986 st
.set_cname (cname
);
1989 current_gtype_struct_for
= reader
.get_attribute ("glib:is-gtype-struct-for");
1990 if (current_gtype_struct_for
!= null) {
1991 girdata
["glib:is-gtype-struct-for"] = current_gtype_struct_for
;
1995 var old_symbols_info
= current_symbols_info
;
1996 var old_symbol
= current_symbol
;
1997 current_symbols_info
= new ArrayList
<SymbolInfo
> ();
1998 current_symbol
= st
;
1999 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2000 if (!push_metadata ()) {
2005 if (reader
.name
== "field") {
2006 if (reader
.get_attribute ("name") != "priv") {
2007 add_symbol_info (parse_field ());
2011 } else if (reader
.name
== "constructor") {
2012 parse_constructor ();
2013 } else if (reader
.name
== "method") {
2014 add_symbol_info (parse_method ("method"));
2015 } else if (reader
.name
== "union") {
2016 Struct s
= parse_union ();
2017 var s_fields
= s
.get_fields ();
2018 foreach (var f
in s_fields
) {
2019 f
.set_cname (s
.get_cname () + "." + f
.get_cname ());
2020 f
.name
= s
.name
+ "_" + f
.name
;
2025 Report
.error (get_current_src (), "unknown child element `%s' in `record'".printf (reader
.name
));
2031 end_element ("record");
2033 merge_add_process (st
);
2034 current_symbols_info
= old_symbols_info
;
2035 current_symbol
= old_symbol
;
2036 current_gtype_struct_for
= null;
2041 Class
parse_class () {
2042 start_element ("class");
2043 var name
= element_get_name ();
2044 string cname
= reader
.get_attribute ("c:type");
2045 string parent
= reader
.get_attribute ("parent");
2046 var cl
= current_symbol
.scope
.lookup (name
) as Class
;
2048 cl
= new
Class (name
, get_current_src ());
2049 cl
.access
= SymbolAccessibility
.PUBLIC
;
2052 if (cname
!= null) {
2053 cl
.set_cname (cname
);
2056 if (parent
!= null) {
2057 cl
.add_base_type (parse_type_from_gir_name (parent
));
2061 var first_field
= true;
2062 var old_symbol
= current_symbol
;
2063 var old_symbols_info
= current_symbols_info
;
2064 current_symbols_info
= new ArrayList
<SymbolInfo
> ();
2065 current_symbol
= cl
;
2066 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2067 if (!push_metadata ()) {
2072 if (reader
.name
== "implements") {
2073 start_element ("implements");
2074 cl
.add_base_type (parse_type_from_gir_name (reader
.get_attribute ("name")));
2076 end_element ("implements");
2077 } else if (reader
.name
== "constant") {
2078 add_symbol_info (parse_constant ());
2079 } else if (reader
.name
== "field") {
2080 if (first_field
&& parent
!= null) {
2081 // first field is guaranteed to be the parent instance
2084 if (reader
.get_attribute ("name") != "priv") {
2085 add_symbol_info (parse_field ());
2090 first_field
= false;
2091 } else if (reader
.name
== "property") {
2092 add_symbol_info (parse_property ());
2093 } else if (reader
.name
== "constructor") {
2094 add_symbol_info (parse_constructor ());
2095 } else if (reader
.name
== "function") {
2096 add_symbol_info (parse_method ("function"));
2097 } else if (reader
.name
== "method") {
2098 add_symbol_info (parse_method ("method"));
2099 } else if (reader
.name
== "virtual-method") {
2100 add_symbol_info (parse_method ("virtual-method"));
2101 } else if (reader
.name
== "union") {
2102 Struct s
= parse_union ();
2103 var s_fields
= s
.get_fields ();
2104 foreach (var f
in s_fields
) {
2105 f
.set_cname (s
.get_cname () + "." + f
.get_cname ());
2106 f
.name
= s
.name
+ "_" + f
.name
;
2107 add_symbol_info (f
);
2109 } else if (reader
.name
== "glib:signal") {
2110 add_symbol_info (parse_signal ());
2113 Report
.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader
.name
));
2120 merge_add_process (cl
);
2121 current_symbols_info
= old_symbols_info
;
2122 current_symbol
= old_symbol
;
2124 end_element ("class");
2128 Interface
parse_interface () {
2129 start_element ("interface");
2130 var iface
= new
Interface (element_get_name (), get_current_src ());
2131 iface
.access
= SymbolAccessibility
.PUBLIC
;
2132 iface
.external
= true;
2134 string cname
= reader
.get_attribute ("c:type");
2135 if (cname
!= null) {
2136 iface
.set_cname (cname
);
2140 var old_symbol
= current_symbol
;
2141 var old_symbols_info
= current_symbols_info
;
2142 current_symbol
= iface
;
2143 current_symbols_info
= new ArrayList
<SymbolInfo
> ();
2144 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2145 if (!push_metadata ()) {
2150 if (reader
.name
== "prerequisite") {
2151 start_element ("prerequisite");
2152 iface
.add_prerequisite (parse_type_from_gir_name (reader
.get_attribute ("name")));
2154 end_element ("prerequisite");
2155 } else if (reader
.name
== "field") {
2156 add_symbol_info (parse_field ());
2157 } else if (reader
.name
== "property") {
2158 add_symbol_info (parse_property ());
2159 } else if (reader
.name
== "virtual-method") {
2160 add_symbol_info (parse_method ("virtual-method"));
2161 } else if (reader
.name
== "function") {
2162 add_symbol_info (parse_method ("function"));
2163 } else if (reader
.name
== "method") {
2164 add_symbol_info (parse_method ("method"));
2165 } else if (reader
.name
== "glib:signal") {
2166 add_symbol_info (parse_signal ());
2169 Report
.error (get_current_src (), "unknown child element `%s' in `interface'".printf (reader
.name
));
2176 merge_add_process (iface
);
2177 current_symbol
= old_symbol
;
2178 current_symbols_info
= old_symbols_info
;
2180 end_element ("interface");
2184 Field
parse_field () {
2185 start_element ("field");
2186 string name
= reader
.get_attribute ("name");
2187 string allow_none
= reader
.get_attribute ("allow-none");
2189 var type
= parse_type ();
2190 type
= element_get_type (type
, true);
2191 if (type is DelegateType
&& current_gtype_struct_for
!= null) {
2193 var gtype_struct_for
= parse_symbol_from_string (current_gtype_struct_for
);
2194 ArrayList
<Delegate
> callbacks
= gtype_callbacks
.get (gtype_struct_for
);
2195 if (callbacks
== null) {
2196 callbacks
= new ArrayList
<Delegate
> ();
2197 gtype_callbacks
.set (gtype_struct_for
, callbacks
);
2199 callbacks
.add (((DelegateType
) type
).delegate_symbol
);
2201 var field
= new
Field (name
, type
, null, get_current_src ());
2202 field
.access
= SymbolAccessibility
.PUBLIC
;
2203 field
.no_array_length
= true;
2204 field
.array_null_terminated
= true;
2205 if (allow_none
== "1") {
2206 type
.nullable
= true;
2208 end_element ("field");
2212 Property
parse_property () {
2213 start_element ("property");
2214 string name
= reader
.get_attribute ("name").replace ("-", "_");
2215 string readable
= reader
.get_attribute ("readable");
2216 string writable
= reader
.get_attribute ("writable");
2217 string construct_
= reader
.get_attribute ("construct");
2218 string construct_only
= reader
.get_attribute ("construct-only");
2220 bool no_array_length
;
2221 bool array_null_terminated
;
2222 var type
= parse_type (null, null, false, out no_array_length
, out array_null_terminated
);
2223 var prop
= new
Property (name
, type
, null, null, get_current_src ());
2224 prop
.access
= SymbolAccessibility
.PUBLIC
;
2225 prop
.external
= true;
2226 prop
.no_accessor_method
= true;
2227 prop
.no_array_length
= no_array_length
;
2228 prop
.array_null_terminated
= array_null_terminated
;
2229 if (readable
!= "0") {
2230 prop
.get_accessor
= new
PropertyAccessor (true, false, false, prop
.property_type
.copy (), null, null);
2231 prop
.get_accessor
.value_type
.value_owned
= true;
2233 if (writable
== "1" || construct_only
== "1") {
2234 prop
.set_accessor
= new
PropertyAccessor (false, (construct_only
!= "1") && (writable
== "1"), (construct_only
== "1") || (construct_
== "1"), prop
.property_type
.copy (), null, null);
2236 end_element ("property");
2240 Delegate
parse_callback () {
2241 return this
.parse_function ("callback") as Delegate
;
2244 CreationMethod
parse_constructor () {
2245 return parse_function ("constructor") as CreationMethod
;
2248 class ParameterInfo
{
2249 public ParameterInfo (Parameter param
, int array_length_idx
, int closure_idx
, int destroy_idx
) {
2251 this
.array_length_idx
= array_length_idx
;
2252 this
.closure_idx
= closure_idx
;
2253 this
.destroy_idx
= destroy_idx
;
2254 this
.vala_idx
= 0.0F
;
2258 public Parameter param
;
2259 public float vala_idx
;
2260 public int array_length_idx
;
2261 public int closure_idx
;
2262 public int destroy_idx
;
2266 Symbol
parse_function (string element_name
) {
2267 start_element (element_name
);
2268 string name
= element_get_name ();
2269 string cname
= reader
.get_attribute ("c:identifier");
2270 string throws_string
= reader
.get_attribute ("throws");
2271 string invoker
= reader
.get_attribute ("invoker");
2274 DataType return_type
;
2275 string return_ctype
= null;
2276 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "return-value") {
2277 return_type
= parse_return_value (out return_ctype
);
2279 return_type
= new
VoidType ();
2281 return_type
= element_get_type (return_type
, true);
2285 if (element_name
== "callback") {
2286 s
= new
Delegate (name
, return_type
, get_current_src ());
2287 } else if (element_name
== "constructor") {
2288 if (name
== "new") {
2290 } else if (name
.has_prefix ("new_")) {
2291 name
= name
.substring ("new_".length
);
2293 var m
= new
CreationMethod (null, name
, get_current_src ());
2294 m
.has_construct_function
= false;
2296 string parent_ctype
= null;
2297 if (current_symbol is Class
) {
2298 parent_ctype
= ((Class
) current_symbol
).get_cname ();
2300 if (return_ctype
!= null && (parent_ctype
== null || return_ctype
!= parent_ctype
+ "*")) {
2301 m
.custom_return_type_cname
= return_ctype
;
2305 s
= new
Method (name
, return_type
, get_current_src ());
2308 s
.access
= SymbolAccessibility
.PUBLIC
;
2309 if (cname
!= null) {
2311 ((Method
) s
).set_cname (cname
);
2313 ((Delegate
) s
).set_cname (cname
);
2319 if (element_name
== "virtual-method" || element_name
== "callback") {
2321 ((Method
) s
).is_virtual
= true;
2322 if (invoker
== null && !metadata
.has_argument (ArgumentType
.VFUNC_NAME
)) {
2323 s
.attributes
.append (new
Attribute ("NoWrapper", s
.source_reference
));
2327 if (invoker
!= null) {
2330 } else if (element_name
== "function") {
2331 ((Method
) s
).binding
= MemberBinding
.STATIC
;
2334 if (s is Method
&& !(s is CreationMethod
)) {
2335 var method
= (Method
) s
;
2336 if (metadata
.has_argument (ArgumentType
.VIRTUAL
)) {
2337 method
.is_virtual
= metadata
.get_bool (ArgumentType
.VIRTUAL
);
2338 method
.is_abstract
= false;
2339 } else if (metadata
.has_argument (ArgumentType
.ABSTRACT
)) {
2340 method
.is_abstract
= metadata
.get_bool (ArgumentType
.ABSTRACT
);
2341 method
.is_virtual
= false;
2343 if (metadata
.has_argument (ArgumentType
.VFUNC_NAME
)) {
2344 method
.vfunc_name
= metadata
.get_string (ArgumentType
.VFUNC_NAME
);
2345 method
.is_virtual
= true;
2349 var parameters
= new ArrayList
<ParameterInfo
> ();
2350 var array_length_parameters
= new ArrayList
<int> ();
2351 var closure_parameters
= new ArrayList
<int> ();
2352 var destroy_parameters
= new ArrayList
<int> ();
2353 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "parameters") {
2354 start_element ("parameters");
2357 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2358 if (!push_metadata ()) {
2363 int array_length_idx
, closure_idx
, destroy_idx
;
2365 string default_param_name
= null;
2366 default_param_name
= "arg%d".printf (parameters
.size
);
2367 var param
= parse_parameter (out array_length_idx
, out closure_idx
, out destroy_idx
, out scope
, default_param_name
);
2368 if (array_length_idx
!= -1) {
2369 array_length_parameters
.add (array_length_idx
);
2371 if (closure_idx
!= -1) {
2372 closure_parameters
.add (closure_idx
);
2374 if (destroy_idx
!= -1) {
2375 destroy_parameters
.add (destroy_idx
);
2378 var info
= new
ParameterInfo(param
, array_length_idx
, closure_idx
, destroy_idx
);
2380 if (s is Method
&& scope
== "async") {
2381 var unresolved_type
= param
.variable_type as UnresolvedType
;
2382 if (unresolved_type
!= null && unresolved_type
.unresolved_symbol
.name
== "AsyncReadyCallback") {
2383 // GAsync-style method
2384 ((Method
) s
).coroutine
= true;
2389 parameters
.add (info
);
2392 end_element ("parameters");
2394 var array_length_idx
= -1;
2395 if (return_type is ArrayType
&& metadata
.has_argument (ArgumentType
.ARRAY_LENGTH_IDX
)) {
2396 array_length_idx
= metadata
.get_integer (ArgumentType
.ARRAY_LENGTH_IDX
);
2397 parameters
[array_length_idx
].keep
= false;
2398 array_length_parameters
.add (array_length_idx
);
2404 foreach (ParameterInfo info
in parameters
) {
2405 if (s is Delegate
&& info
.closure_idx
== i
) {
2406 var d
= (Delegate
) s
;
2407 d
.has_target
= true;
2408 d
.cinstance_parameter_position
= (float) j
- 0.1;
2410 } else if (info
.keep
2411 && !array_length_parameters
.contains (i
)
2412 && !closure_parameters
.contains (i
)
2413 && !destroy_parameters
.contains (i
)) {
2414 info
.vala_idx
= (float) j
;
2417 /* interpolate for vala_idx between this and last*/
2418 float last_idx
= 0.0F
;
2420 last_idx
= parameters
[last
].vala_idx
;
2422 for (int k
=last
+1; k
< i
; k
++) {
2423 parameters
[k
].vala_idx
= last_idx
+ (((j
- last_idx
) / (i
-last
)) * (k
-last
));
2429 // make sure that vala_idx is always set
2430 // the above if branch does not set vala_idx for
2431 // hidden parameters at the end of the parameter list
2432 info
.vala_idx
= (j
- 1) + (i
- last
) * 0.1F
;
2437 foreach (ParameterInfo info
in parameters
) {
2440 /* add_parameter sets carray_length_parameter_position and cdelegate_target_parameter_position
2443 ((Method
) s
).add_parameter (info
.param
);
2445 ((Delegate
) s
).add_parameter (info
.param
);
2448 if (info
.array_length_idx
!= -1) {
2449 if ((info
.array_length_idx
) >= parameters
.size
) {
2450 Report
.error (get_current_src (), "invalid array_length index");
2453 set_array_ccode (info
.param
, parameters
[info
.array_length_idx
]);
2454 } else if (info
.param
.variable_type is ArrayType
) {
2455 info
.param
.no_array_length
= true;
2456 info
.param
.array_null_terminated
= true;
2459 if (info
.closure_idx
!= -1) {
2460 if ((info
.closure_idx
) >= parameters
.size
) {
2461 Report
.error (get_current_src (), "invalid closure index");
2464 info
.param
.cdelegate_target_parameter_position
= parameters
[info
.closure_idx
].vala_idx
;
2466 if (info
.destroy_idx
!= -1) {
2467 if (info
.destroy_idx
>= parameters
.size
) {
2468 Report
.error (get_current_src (), "invalid destroy index");
2471 info
.param
.cdestroy_notify_parameter_position
= parameters
[info
.destroy_idx
].vala_idx
;
2475 if (array_length_idx
!= -1) {
2476 if (array_length_idx
>= parameters
.size
) {
2477 Report
.error (get_current_src (), "invalid array_length index");
2479 set_array_ccode (s
, parameters
[array_length_idx
]);
2481 } else if (return_type is ArrayType
) {
2484 m
.no_array_length
= true;
2485 m
.array_null_terminated
= true;
2487 var d
= (Delegate
) s
;
2488 d
.no_array_length
= true;
2489 d
.array_null_terminated
= true;
2493 if (throws_string
== "1") {
2494 s
.add_error_type (new
ErrorType (null, null));
2496 end_element (element_name
);
2500 Method
parse_method (string element_name
) {
2501 return this
.parse_function (element_name
) as Method
;
2504 Signal
parse_signal () {
2505 start_element ("glib:signal");
2506 string name
= reader
.get_attribute ("name").replace ("-", "_");
2508 DataType return_type
;
2509 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "return-value") {
2510 return_type
= parse_return_value ();
2512 return_type
= new
VoidType ();
2514 var sig
= new
Signal (name
, return_type
, get_current_src ());
2515 sig
.access
= SymbolAccessibility
.PUBLIC
;
2516 sig
.external
= true;
2517 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "parameters") {
2518 start_element ("parameters");
2520 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2521 if (!push_metadata ()) {
2526 sig
.add_parameter (parse_parameter ());
2530 end_element ("parameters");
2532 end_element ("glib:signal");
2536 Class
parse_boxed (string element_name
) {
2537 start_element (element_name
);
2538 string name
= reader
.get_attribute ("name");
2540 name
= reader
.get_attribute ("glib:name");
2542 var cl
= new
Class (name
, get_current_src ());
2543 cl
.access
= SymbolAccessibility
.PUBLIC
;
2545 cl
.is_compact
= true;
2547 string cname
= reader
.get_attribute ("c:type");
2548 if (cname
!= null) {
2549 cl
.set_cname (cname
);
2552 cl
.set_type_id ("%s ()".printf (reader
.get_attribute ("glib:get-type")));
2553 cl
.set_free_function ("g_boxed_free");
2554 cl
.set_dup_function ("g_boxed_copy");
2557 var old_symbols_info
= current_symbols_info
;
2558 var old_symbol
= current_symbol
;
2559 current_symbols_info
= new ArrayList
<SymbolInfo
> ();
2560 current_symbol
= cl
;
2561 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2562 if (!push_metadata ()) {
2567 if (reader
.name
== "field") {
2568 add_symbol_info (parse_field ());
2569 } else if (reader
.name
== "constructor") {
2570 parse_constructor ();
2571 } else if (reader
.name
== "method") {
2572 add_symbol_info (parse_method ("method"));
2575 Report
.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader
.name
));
2581 end_element (element_name
);
2583 merge_add_process (cl
);
2584 current_symbols_info
= old_symbols_info
;
2585 current_symbol
= old_symbol
;
2590 Struct
parse_union () {
2591 start_element ("union");
2592 var st
= new
Struct (reader
.get_attribute ("name"), get_current_src ());
2593 st
.access
= SymbolAccessibility
.PUBLIC
;
2597 var old_symbol
= current_symbol
;
2598 current_symbol
= st
;
2599 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2600 if (!push_metadata ()) {
2605 if (reader
.name
== "field") {
2606 st
.add_field (parse_field ());
2607 } else if (reader
.name
== "constructor") {
2608 parse_constructor ();
2609 } else if (reader
.name
== "method") {
2610 st
.add_method (parse_method ("method"));
2611 } else if (reader
.name
== "record") {
2612 Struct s
= parse_record ();
2613 var fs
= s
.get_fields ();
2614 foreach (var f
in fs
) {
2615 f
.set_cname (s
.get_cname () + "." + f
.get_cname ());
2616 f
.name
= s
.name
+ "_" + f
.name
;
2621 Report
.error (get_current_src (), "unknown child element `%s' in `union'".printf (reader
.name
));
2628 end_element ("union");
2629 current_symbol
= old_symbol
;
2634 Constant
parse_constant () {
2635 start_element ("constant");
2636 string name
= element_get_name ();
2638 var type
= parse_type ();
2639 var c
= new
Constant (name
, type
, null, get_current_src ());
2640 c
.access
= SymbolAccessibility
.PUBLIC
;
2642 end_element ("constant");
2647 void report_unused_metadata (Metadata metadata
) {
2648 if (metadata
== Metadata
.empty
) {
2652 if (metadata
.args
.size
== 0 && metadata
.children
.size
== 0) {
2653 Report
.warning (metadata
.source_reference
, "empty metadata");
2657 foreach (var arg_type
in metadata
.args
.get_keys ()) {
2658 var arg
= metadata
.args
[arg_type
];
2660 // if metadata is used and argument is not, then it's a unexpected argument
2661 Report
.warning (arg
.source_reference
, "argument never used");
2665 foreach (var child
in metadata
.children
) {
2667 Report
.warning (child
.source_reference
, "metadata never used");
2669 report_unused_metadata (child
);
2676 void resolve_gir_symbols () {
2677 // we are remapping unresolved symbols, so create them from concrete symbols
2678 foreach (var map_from
in concrete_symbols_map
.get_keys ()) {
2679 unresolved_symbols_map
[get_unresolved_symbol(map_from
)] = concrete_symbols_map
[map_from
];
2682 // gir has simple namespaces, we won't get deeper than 2 levels here, except reparenting
2683 foreach (var map_from
in unresolved_gir_symbols
) {
2684 while (map_from
!= null) {
2685 var map_to
= unresolved_symbols_map
[map_from
];
2686 if (map_to
!= null) {
2687 // remap the original symbol to match the target
2688 map_from
.inner
= null;
2689 map_from
.name
= map_to
.name
;
2690 if (map_to is UnresolvedSymbol
) {
2691 var umap_to
= (UnresolvedSymbol
) map_to
;
2692 while (umap_to
.inner
!= null) {
2693 umap_to
= umap_to
.inner
;
2694 map_from
.inner
= new
UnresolvedSymbol (null, umap_to
.name
);
2695 map_from
= map_from
.inner
;
2698 while (map_to
.parent_symbol
!= null && map_to
.parent_symbol
!= context
.root
) {
2699 map_to
= map_to
.parent_symbol
;
2700 map_from
.inner
= new
UnresolvedSymbol (null, map_to
.name
);
2701 map_from
= map_from
.inner
;
2706 map_from
= map_from
.inner
;
2711 Symbol?
resolve_symbol (Scope parent_scope
, UnresolvedSymbol unresolved_symbol
) {
2712 // simple symbol resolver, enough for gir
2713 if (unresolved_symbol
.inner
== null) {
2714 var scope
= parent_scope
;
2715 while (scope
!= null) {
2716 var sym
= scope
.lookup (unresolved_symbol
.name
);
2720 scope
= scope
.parent_scope
;
2723 var inner
= resolve_symbol (parent_scope
, unresolved_symbol
.inner
);
2724 if (inner
!= null) {
2725 return inner
.scope
.lookup (unresolved_symbol
.name
);
2731 void postprocess_interfaces () {
2732 foreach (var iface
in interfaces
) {
2733 /* Temporarily workaround G-I bug not adding GLib.Object prerequisite:
2734 ensure we have at least one instantiable prerequisite */
2735 bool has_instantiable_prereq
= false;
2736 foreach (DataType prereq
in iface
.get_prerequisites ()) {
2738 if (prereq is UnresolvedType
) {
2739 var unresolved_symbol
= ((UnresolvedType
) prereq
).unresolved_symbol
;
2740 sym
= resolve_symbol (iface
.parent_symbol
.scope
, unresolved_symbol
);
2742 sym
= prereq
.data_type
;
2745 has_instantiable_prereq
= true;
2750 if (!has_instantiable_prereq
) {
2751 iface
.add_prerequisite (new
ObjectType ((ObjectTypeSymbol
) glib_ns
.scope
.lookup ("Object")));
2756 void postprocess_reparenting () {
2757 foreach (UnresolvedSymbol target_unresolved_symbol
in symbol_reparent_map
.get_keys ()) {
2758 var target_symbol
= resolve_symbol (context
.root
.scope
, target_unresolved_symbol
);
2759 if (target_symbol
== null) {
2760 // create namespaces backward
2761 var sym
= target_unresolved_symbol
;
2762 var ns
= new
Namespace (sym
.name
, sym
.source_reference
);
2765 while (sym
!= null) {
2766 var res
= resolve_symbol (context
.root
.scope
, sym
);
2767 if (res
!= null && !(res is Namespace
)) {
2771 var parent
= res as Namespace
;
2773 parent
= new
Namespace (sym
.name
, sym
.source_reference
);
2775 if (parent
.scope
.lookup (ns
.name
) == null) {
2776 parent
.add_namespace (ns
);
2781 if (result
!= null && sym
== null && context
.root
.scope
.lookup (ns
.name
) == null) {
2782 // a new root namespace, helpful for a possible non-gobject gir?
2783 context
.root
.add_namespace (ns
);
2785 target_symbol
= result
;
2787 if (target_symbol
== null) {
2788 Report
.error (null, "unable to reparent into `%s'".printf (target_unresolved_symbol
.to_string ()));
2791 var symbols
= symbol_reparent_map
[target_unresolved_symbol
];
2792 foreach (var symbol
in symbols
) {
2793 add_symbol_to_container (target_symbol
, symbol
);
2798 void postprocess_gtype_callbacks (Namespace ns
) {
2799 foreach (UnresolvedSymbol gtype_struct_for
in gtype_callbacks
.get_keys ()) {
2800 // parent symbol is the record, therefore use parent of parent symbol
2801 var gtype
= resolve_symbol (ns
.scope
, gtype_struct_for
) as ObjectTypeSymbol
;
2802 if (gtype
== null) {
2803 Report
.error (null, "unknown symbol `%s' while postprocessing callbacks".printf (gtype_struct_for
.name
));
2806 ArrayList
<Delegate
> callbacks
= gtype_callbacks
.get (gtype_struct_for
);
2807 foreach (Delegate d
in callbacks
) {
2808 var symbol
= gtype
.scope
.lookup (d
.name
);
2809 if (symbol
== null) {
2811 } else if (symbol is Method
) {
2812 var meth
= (Method
) symbol
;
2813 if (gtype is Class
) {
2814 meth
.is_virtual
= true;
2815 } else if (gtype is Interface
) {
2816 meth
.is_abstract
= true;
2818 } else if (symbol is Signal
) {
2819 var sig
= (Signal
) symbol
;
2820 sig
.is_virtual
= true;
2821 assume_parameter_names (sig
, d
, true);
2822 } else if (symbol is Property
) {
2823 var prop
= (Property
) symbol
;
2824 prop
.is_virtual
= true;
2826 Report
.error (get_current_src (), "unknown member type `%s' in `%s'".printf (d
.name
, gtype
.name
));
2832 void postprocess_aliases () {
2833 /* this is unfortunate because <alias> tag has no type information, thus we have
2834 to guess it from the base type */
2835 foreach (var alias
in aliases
) {
2836 DataType base_type
= null;
2837 Symbol type_sym
= null;
2838 bool simple_type
= false;
2839 if (alias
.base_type is UnresolvedType
) {
2840 base_type
= alias
.base_type
;
2841 type_sym
= resolve_symbol (alias
.parent_symbol
.scope
, ((UnresolvedType
) base_type
).unresolved_symbol
);
2842 } else if (alias
.base_type is PointerType
&& ((PointerType
) alias
.base_type
).base_type is VoidType
) {
2843 // gpointer, if it's a struct make it a simpletype
2846 base_type
= alias
.base_type
;
2847 type_sym
= base_type
.data_type
;
2850 if (type_sym is Struct
&& ((Struct
) type_sym
).is_simple_type ()) {
2854 if (base_type
== null || type_sym
== null || type_sym is Struct
) {
2855 var st
= new
Struct (alias
.name
, alias
.source_reference
);
2856 st
.access
= SymbolAccessibility
.PUBLIC
;
2857 if (base_type
!= null) {
2858 // threat target="none" as a new struct
2859 st
.base_type
= base_type
;
2862 if (alias
.cname
!= null) {
2863 st
.set_cname (alias
.cname
);
2866 st
.set_simple_type (true);
2868 add_symbol_to_container (alias
.parent_symbol
, st
);
2869 } else if (type_sym is Class
) {
2870 var cl
= new
Class (alias
.name
, alias
.source_reference
);
2871 cl
.access
= SymbolAccessibility
.PUBLIC
;
2872 if (base_type
!= null) {
2873 cl
.add_base_type (base_type
);
2876 if (alias
.cname
!= null) {
2877 cl
.set_cname (alias
.cname
);
2879 add_symbol_to_container (alias
.parent_symbol
, cl
);
2884 void find_static_method_parent (string cname
, Symbol current
, ref Symbol best
, ref double match
, double match_char
) {
2885 var old_best
= best
;
2886 if (current
.scope
.get_symbol_table () != null) {
2887 foreach (var child
in current
.scope
.get_symbol_table().get_values ()) {
2888 if (child is Struct
|| child is ObjectTypeSymbol
|| child is Namespace
) {
2889 find_static_method_parent (cname
, child
, ref best
, ref match
, match_char
);
2893 if (best
!= old_best
) {
2898 var current_cprefix
= current
.get_lower_case_cprefix ();
2899 if (cname
.has_prefix (current_cprefix
)) {
2900 var current_match
= match_char
* current_cprefix
.length
;
2901 if (current_match
> match
) {
2902 match
= current_match
;
2908 void postprocess_namespace_methods () {
2909 /* transform static methods into instance methods if possible.
2910 In most of cases this is a .gir fault we are going to fix */
2911 foreach (var ns
in namespace_methods
.get_keys ()) {
2912 var ns_cprefix
= ns
.get_lower_case_cprefix ();
2913 var methods
= namespace_methods
[ns
];
2914 foreach (var method
in methods
) {
2915 if (method
.parent_symbol
!= null) {
2916 // fixed earlier by metadata
2920 var cname
= method
.get_cname ();
2922 Parameter first_param
= null;
2923 if (method
.get_parameters ().size
> 0) {
2924 first_param
= method
.get_parameters()[0];
2926 if (first_param
!= null && first_param
.variable_type is UnresolvedType
) {
2927 // check if it's a missed instance method (often happens for structs)
2928 var parent
= resolve_symbol (ns
.scope
, ((UnresolvedType
) first_param
.variable_type
).unresolved_symbol
);
2929 if (parent
!= null && (parent is Struct
|| parent is ObjectTypeSymbol
|| parent is Namespace
)
2930 && cname
.has_prefix (parent
.get_lower_case_cprefix ())) {
2932 var new_name
= method
.name
.substring (parent
.get_lower_case_cprefix().length
- ns_cprefix
.length
);
2933 if (parent
.scope
.lookup (new_name
) == null) {
2934 method
.name
= new_name
;
2935 method
.get_parameters().remove_at (0);
2936 method
.binding
= MemberBinding
.INSTANCE
;
2937 add_symbol_to_container (parent
, method
);
2939 ns
.add_method (method
);
2947 find_static_method_parent (cname
, ns
, ref parent
, ref match
, 1.0/cname
.length
);
2948 var new_name
= method
.name
.substring (parent
.get_lower_case_cprefix().length
- ns_cprefix
.length
);
2949 if (parent
.scope
.lookup (new_name
) == null) {
2950 method
.name
= new_name
;
2951 add_symbol_to_container (parent
, method
);
2953 ns
.add_method (method
);
2959 /* Hash and equal functions */
2961 static uint unresolved_symbol_hash (void *ptr
) {
2962 var sym
= (UnresolvedSymbol
) ptr
;
2963 var builder
= new
StringBuilder ();
2964 while (sym
!= null) {
2965 builder
.append (sym
.name
);
2968 return builder
.str
.hash ();
2971 static bool unresolved_symbol_equal (void *ptr1
, void *ptr2
) {
2972 var sym1
= (UnresolvedSymbol
) ptr1
;
2973 var sym2
= (UnresolvedSymbol
) ptr2
;
2974 while (sym1
!= sym2
) {
2975 if (sym1
== null || sym2
== null) {
2978 if (sym1
.name
!= sym2
.name
) {