3 * Copyright (C) 2008-2012 Jürg Billeter
4 * Copyright (C) 2011-2014 Luca Bruno
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * Jürg Billeter <j@bitron.ch>
22 * Luca Bruno <lucabru@src.gnome.org>
28 * Code visitor parsing all GIR source files.
32 * 2) Parse GIR with metadata, track unresolved GIR symbols, create Vala symbols
33 * 3) Reconciliate the tree by mapping tracked symbols
36 public class Vala
.GirParser
: CodeVisitor
{
58 ARRAY_NULL_TERMINATED
,
86 RETURNS_MODIFIED_POINTER
,
87 DELEGATE_TARGET_CNAME
,
93 public static ArgumentType?
from_string (string name
) {
94 var enum_class
= (EnumClass
) typeof(ArgumentType
).class_ref ();
95 var nick
= name
.replace ("_", "-");
96 unowned GLib
.EnumValue? enum_value
= enum_class
.get_value_by_nick (nick
);
97 if (enum_value
!= null) {
98 ArgumentType value
= (ArgumentType
) enum_value
.value
;
106 public Expression expression
;
107 public SourceReference source_reference
;
109 public bool used
= false;
111 public Argument (Expression expression
, SourceReference? source_reference
= null) {
112 this
.expression
= expression
;
113 this
.source_reference
= source_reference
;
117 class MetadataSet
: Metadata
{
118 public MetadataSet (string? selector
= null) {
122 public void add_sibling (Metadata metadata
) {
123 foreach (var child
in metadata
.children
) {
126 // merge arguments and take precedence
127 foreach (var key
in metadata
.args
.get_keys ()) {
128 args
[key
] = metadata
.args
[key
];
134 private static Metadata _empty
= null;
135 public static Metadata empty
{
137 if (_empty
== null) {
138 _empty
= new
Metadata ("");
144 public PatternSpec pattern_spec
;
145 public string? selector
;
146 public SourceReference source_reference
;
148 public bool used
= false;
149 public Vala
.Map
<ArgumentType
,Argument
> args
= new HashMap
<ArgumentType
,Argument
> ();
150 public ArrayList
<Metadata
> children
= new ArrayList
<Metadata
> ();
152 public Metadata (string pattern
, string? selector
= null, SourceReference? source_reference
= null) {
153 this
.pattern_spec
= new
PatternSpec (pattern
);
154 this
.selector
= selector
;
155 this
.source_reference
= source_reference
;
158 public void add_child (Metadata metadata
) {
159 children
.add (metadata
);
162 public Metadata
match_child (string name
, string? selector
= null) {
163 var result
= Metadata
.empty
;
164 foreach (var metadata
in children
) {
165 if ((selector
== null || metadata
.selector
== null || metadata
.selector
== selector
) && metadata
.pattern_spec
.match_string (name
)) {
166 metadata
.used
= true;
167 if (result
== Metadata
.empty
) {
171 var ms
= result as MetadataSet
;
174 ms
= new
MetadataSet (selector
);
175 ms
.add_sibling (result
);
177 ms
.add_sibling (metadata
);
185 public void add_argument (ArgumentType key
, Argument value
) {
186 args
.set (key
, value
);
189 public bool has_argument (ArgumentType key
) {
190 return args
.contains (key
);
193 public Expression?
get_expression (ArgumentType arg
) {
194 var val
= args
.get (arg
);
197 return val
.expression
;
202 public string?
get_string (ArgumentType arg
) {
203 var lit
= get_expression (arg
) as StringLiteral
;
210 public int get_integer (ArgumentType arg
) {
211 var unary
= get_expression (arg
) as UnaryExpression
;
212 if (unary
!= null && unary
.operator
== UnaryOperator
.MINUS
) {
213 var lit
= unary
.inner as IntegerLiteral
;
215 return -int.parse (lit
.value
);
218 var lit
= get_expression (arg
) as IntegerLiteral
;
220 return int.parse (lit
.value
);
227 public bool get_bool (ArgumentType arg
, bool default_value
= false) {
228 var lit
= get_expression (arg
) as BooleanLiteral
;
232 return default_value
;
235 public SourceReference?
get_source_reference (ArgumentType arg
) {
236 var val
= args
.get (arg
);
238 return val
.source_reference
;
244 class MetadataParser
{
247 * metadata ::= [ rule [ '\n' relativerule ]* ]
248 * rule ::= pattern ' ' [ args ]
249 * relativerule ::= '.' rule
250 * pattern ::= glob [ '#' selector ] [ '.' pattern ]
252 private Metadata tree
= new
Metadata ("");
253 private Scanner scanner
;
254 private SourceLocation begin
;
255 private SourceLocation end
;
256 private SourceLocation old_end
;
257 private TokenType current
;
258 private Metadata parent_metadata
;
260 public MetadataParser () {
264 SourceReference
get_current_src () {
265 return new
SourceReference (scanner
.source_file
, begin
, end
);
268 SourceReference
get_src (SourceLocation begin
, SourceLocation? end
= null) {
273 return new
SourceReference (scanner
.source_file
, begin
, e
);
276 public Metadata
parse_metadata (SourceFile metadata_file
) {
277 scanner
= new
Scanner (metadata_file
);
279 while (current
!= TokenType
.EOF
) {
280 if (!parse_rule ()) {
281 return Metadata
.empty
;
289 current
= scanner
.read_token (out begin
, out end
);
294 return old_end
.pos
!= begin
.pos
;
297 bool has_newline () {
298 return old_end
.line
!= begin
.line
;
301 string get_string (SourceLocation? begin
= null, SourceLocation? end
= null) {
310 return ((string) b
.pos
).substring (0, (int) (e
.pos
- b
.pos
));
313 string?
parse_identifier (bool is_glob
) {
314 var begin
= this
.begin
;
316 if (current
== TokenType
.DOT
|| current
== TokenType
.HASH
) {
318 Report
.error (get_src (begin
), "expected glob-style pattern");
320 Report
.error (get_src (begin
), "expected identifier");
326 while (current
!= TokenType
.EOF
&& current
!= TokenType
.DOT
&& current
!= TokenType
.HASH
) {
336 return get_string (begin
, old_end
);
339 string?
parse_selector () {
340 if (current
!= TokenType
.HASH
|| has_space ()) {
345 return parse_identifier (false);
348 Metadata?
parse_pattern () {
350 bool is_relative
= false;
351 if (current
== TokenType
.IDENTIFIER
|| current
== TokenType
.STAR
) {
353 parent_metadata
= tree
;
356 if (current
!= TokenType
.DOT
) {
357 Report
.error (get_current_src (), "expected pattern or `.', got %s".printf (current
.to_string ()));
364 if (parent_metadata
== null) {
365 Report
.error (get_current_src (), "cannot determinate parent metadata");
369 SourceLocation begin
= this
.begin
;
370 var pattern
= parse_identifier (true);
371 if (pattern
== null) {
374 metadata
= new
Metadata (pattern
, parse_selector (), get_src (begin
));
375 parent_metadata
.add_child (metadata
);
377 while (current
!= TokenType
.EOF
&& !has_space ()) {
378 if (current
!= TokenType
.DOT
) {
379 Report
.error (get_current_src (), "expected `.' got %s".printf (current
.to_string ()));
385 pattern
= parse_identifier (true);
386 if (pattern
== null) {
389 var child
= new
Metadata (pattern
, parse_selector (), get_src (begin
, old_end
));
390 metadata
.add_child (child
);
394 parent_metadata
= metadata
;
400 Expression?
parse_expression () {
401 var begin
= this
.begin
;
402 var src
= get_current_src ();
403 Expression expr
= null;
406 expr
= new
NullLiteral (src
);
409 expr
= new
BooleanLiteral (true, src
);
411 case TokenType
.FALSE
:
412 expr
= new
BooleanLiteral (false, src
);
414 case TokenType
.MINUS
:
416 var inner
= parse_expression ();
418 Report
.error (src
, "expected expression after `-', got %s".printf (current
.to_string ()));
420 expr
= new
UnaryExpression (UnaryOperator
.MINUS
, inner
, get_src (begin
));
423 case TokenType
.INTEGER_LITERAL
:
424 expr
= new
IntegerLiteral (get_string (), src
);
426 case TokenType
.REAL_LITERAL
:
427 expr
= new
RealLiteral (get_string (), src
);
429 case TokenType
.STRING_LITERAL
:
430 expr
= new
StringLiteral (get_string (), src
);
432 case TokenType
.IDENTIFIER
:
433 expr
= new
MemberAccess (null, get_string (), src
);
434 while (next () == TokenType
.DOT
) {
435 if (next () != TokenType
.IDENTIFIER
) {
436 Report
.error (get_current_src (), "expected identifier got %s".printf (current
.to_string ()));
439 expr
= new
MemberAccess (expr
, get_string (), get_current_src ());
442 case TokenType
.OPEN_PARENS
:
443 // empty tuple => no expression
444 if (next () != TokenType
.CLOSE_PARENS
) {
445 Report
.error (get_current_src (), "expected `)', got %s".printf (current
.to_string ()));
448 expr
= new
Tuple (src
);
451 Report
.error (src
, "expected literal or symbol got %s".printf (current
.to_string ()));
458 bool parse_args (Metadata metadata
) {
459 while (current
!= TokenType
.EOF
&& has_space () && !has_newline ()) {
460 SourceLocation begin
= this
.begin
;
461 var id
= parse_identifier (false);
465 var arg_type
= ArgumentType
.from_string (id
);
466 if (arg_type
== null) {
467 Report
.warning (get_src (begin
, old_end
), "unknown argument `%s'".printf (id
));
471 if (current
!= TokenType
.ASSIGN
) {
473 metadata
.add_argument (arg_type
, new
Argument (new
BooleanLiteral (true, get_src (begin
)), get_src (begin
)));
478 Expression expr
= parse_expression ();
482 metadata
.add_argument (arg_type
, new
Argument (expr
, get_src (begin
)));
490 var metadata
= parse_pattern ();
491 if (metadata
== null) {
495 if (current
== TokenType
.EOF
|| old_end
.line
!= end
.line
) {
499 return parse_args (metadata
);
508 public static ArrayList
<Node
> new_namespaces
= new ArrayList
<Node
> ();
510 public weak Node parent
;
511 public string element_type
;
513 public Map
<string,string> girdata
= null;
514 public Metadata metadata
= Metadata
.empty
;
515 public SourceReference source_reference
= null;
516 public ArrayList
<Node
> members
= new ArrayList
<Node
> (); // guarantees fields order
517 public HashMap
<string, ArrayList
<Node
>> scope
= new HashMap
<string, ArrayList
<Node
>> (str_hash
, str_equal
);
519 public GirComment comment
;
520 public Symbol symbol
;
521 public bool new_symbol
;
523 public bool processed
;
526 public int return_array_length_idx
= -1;
527 public List
<ParameterInfo
> parameters
;
528 public ArrayList
<int> array_length_parameters
;
529 public ArrayList
<int> closure_parameters
;
530 public ArrayList
<int> destroy_parameters
;
532 public UnresolvedSymbol gtype_struct_for
;
534 public DataType base_type
;
536 public int array_length_idx
= -1;
538 public bool deprecated
= false;
539 public uint64 deprecated_version
= 0;
540 public string? deprecated_since
= null;
541 public string? deprecated_replacement
= null;
543 public Node (string? name
) {
547 public void add_member (Node node
) {
548 var nodes
= scope
[node
.name
];
550 nodes
= new ArrayList
<Node
> ();
551 scope
[node
.name
] = nodes
;
558 public void remove_member (Node node
) {
559 var nodes
= scope
[node
.name
];
561 if (nodes
.size
== 0) {
562 scope
.remove (node
.name
);
564 members
.remove (node
);
568 public Node?
lookup (string name
, bool create_namespace
= false, SourceReference? source_reference
= null) {
569 var nodes
= scope
[name
];
576 if (symbol
!= null) {
577 sym
= symbol
.scope
.lookup (name
);
579 if (sym
!= null || create_namespace
) {
580 node
= new
Node (name
);
582 node
.new_symbol
= node
.symbol
== null;
583 node
.source_reference
= source_reference
;
587 new_namespaces
.add (node
);
594 public ArrayList
<Node
>?
lookup_all (string name
) {
598 public UnresolvedSymbol
get_unresolved_symbol () {
599 if (parent
.name
== null) {
600 return new
UnresolvedSymbol (null, name
);
602 return new
UnresolvedSymbol (parent
.get_unresolved_symbol (), name
);
606 public string get_full_name () {
607 if (parent
== null) {
612 return parent
.get_full_name ();
615 if (parent
.get_full_name () == null) {
619 return "%s.%s".printf (parent
.get_full_name (), name
);
622 public string get_default_gir_name () {
623 GLib
.StringBuilder default_name
= new GLib
.StringBuilder ();
625 for (unowned Node? node
= this
; node
!= null ; node
= node
.parent
) {
626 if (node
.symbol is Namespace
) {
627 if (node
.symbol
.get_attribute_string ("CCode", "gir_namespace") != null) {
632 default_name
.prepend (node
.name
);
635 return default_name
.str
;
638 public string get_gir_name () {
639 var gir_name
= girdata
["name"];
640 if (gir_name
== null) {
641 gir_name
= girdata
["glib:name"];
646 public string get_lower_case_cprefix () {
651 var prefix
= symbol
.get_attribute_string ("CCode", "lower_case_cprefix");
652 if (prefix
== null && (symbol is ObjectTypeSymbol
|| symbol is Struct
)) {
653 if (metadata
.has_argument (ArgumentType
.LOWER_CASE_CPREFIX
)) {
654 prefix
= metadata
.get_string (ArgumentType
.LOWER_CASE_CPREFIX
);
655 } else if (metadata
.has_argument (ArgumentType
.CPREFIX
)) {
656 prefix
= metadata
.get_string (ArgumentType
.CPREFIX
);
658 prefix
= symbol
.get_attribute_string ("CCode", "cprefix");
662 if (prefix
== null && girdata
!= null && (girdata
.contains ("c:symbol-prefix") || girdata
.contains("c:symbol-prefixes"))) {
663 /* Use the prefix in the gir. We look up prefixes up to the root.
664 If some node does not have girdata, we ignore it as i might be
665 a namespace created due to reparenting. */
666 unowned Node cur
= this
;
668 if (cur
.girdata
!= null) {
669 var p
= cur
.girdata
["c:symbol-prefix"];
671 p
= cur
.girdata
["c:symbol-prefixes"];
673 var idx
= p
.index_of (",");
675 p
= p
.substring (0, idx
);
681 prefix
= "%s_%s".printf (p
, prefix ??
"");
686 } while (cur
!= null);
689 if (prefix
== null) {
690 prefix
= get_default_lower_case_cprefix ();
695 public string get_default_lower_case_cprefix () {
696 return "%s%s_".printf (parent
.get_lower_case_cprefix (), get_lower_case_csuffix ());
699 public string get_lower_case_csuffix () {
700 var suffix
= symbol
.get_attribute_string ("CCode", "lower_case_csuffix");
702 // we can't rely on gir suffix if metadata changed the name
703 if (suffix
== null && girdata
!= null && girdata
["c:symbol-prefix"] != null && !metadata
.has_argument (ArgumentType
.NAME
)) {
704 suffix
= girdata
["c:symbol-prefix"];
706 if (suffix
== null) {
707 suffix
= get_default_lower_case_csuffix ();
712 public string get_default_lower_case_csuffix () {
713 return Symbol
.camel_case_to_lower_case (name
);
716 public string get_cprefix () {
721 if (metadata
.has_argument (ArgumentType
.CPREFIX
)) {
722 prefix
= metadata
.get_string (ArgumentType
.CPREFIX
);
724 prefix
= symbol
.get_attribute_string ("CCode", "cprefix");
726 if (prefix
== null && girdata
!= null && girdata
["c:identifier-prefixes"] != null) {
727 prefix
= girdata
["c:identifier-prefixes"];
728 int idx
= prefix
.index_of (",");
730 prefix
= prefix
.substring (0, idx
);
733 if (prefix
== null) {
734 if (symbol is Enum
|| symbol is ErrorDomain
) {
735 prefix
= "%s%s".printf (parent
.get_lower_case_cprefix ().ascii_up (), name
);
737 prefix
= get_cname ();
743 public string get_cname () {
748 if (metadata
.has_argument (ArgumentType
.CNAME
)) {
749 cname
= metadata
.get_string (ArgumentType
.CNAME
);
751 cname
= symbol
.get_attribute_string ("CCode", "cname");
753 if (girdata
!= null) {
755 cname
= girdata
["c:identifier"];
758 cname
= girdata
["c:type"];
762 cname
= get_default_cname ();
767 public string get_default_cname () {
771 if (symbol is Field
) {
772 if (((Field
) symbol
).binding
== MemberBinding
.STATIC
) {
773 return parent
.get_lower_case_cprefix () + name
;
777 } else if (symbol is Method
) {
778 return "%s%s".printf (parent
.get_lower_case_cprefix (), name
);
780 return "%s%s".printf (parent
.get_cprefix (), name
);
784 public string get_finish_cname () {
785 var finish_cname
= symbol
.get_attribute_string ("CCode", "finish_name");
786 if (finish_cname
== null) {
787 finish_cname
= get_cname ();
788 if (finish_cname
.has_suffix ("_async")) {
789 finish_cname
= finish_cname
.substring (0, finish_cname
.length
- "_async".length
);
791 finish_cname
= "%s_finish".printf (finish_cname
);
796 public string get_cheader_filename () {
797 if (metadata
.has_argument (ArgumentType
.CHEADER_FILENAME
)) {
798 return metadata
.get_string (ArgumentType
.CHEADER_FILENAME
);
800 var cheader_filename
= symbol
.get_attribute_string ("CCode", "cheader_filename");
801 if (cheader_filename
!= null) {
802 return cheader_filename
;
804 if (parent
.name
!= null) {
805 return parent
.get_cheader_filename ();
806 } else if (symbol
.source_reference
!= null) {
807 return symbol
.source_reference
.file
.get_cinclude_filename ();
812 private static uint64 parse_version_string (string version
) {
815 string[] tokens
= version
.split (".", 3);
817 foreach (unowned
string token
in tokens
) {
820 if (!int64.try_parse (token
, out t
))
832 public void process (GirParser parser
) {
837 if (symbol is Namespace
&& parent
== parser
.root
) {
838 // first process aliases since they have no assigned symbol
839 foreach (var node
in members
) {
840 if (node
.element_type
== "alias") {
841 parser
.process_alias (node
);
845 // auto reparent namespace methods, allowing node removals
846 for (int i
=0; i
< members
.size
; i
++) {
847 var node
= members
[i
];
848 if (node
.symbol is Method
&& node
.new_symbol
) {
849 parser
.process_namespace_method (this
, node
);
850 if (i
< members
.size
&& members
[i
] != node
) {
851 // node removed in the middle
858 if (symbol is Class
&& girdata
!= null) {
859 var class_struct
= girdata
["glib:type-struct"];
860 if (class_struct
!= null) {
861 var klass
= parser
.resolve_node (parent
, parser
.parse_symbol_from_string (class_struct
, source_reference
));
864 while ( i
< klass
.members
.size
) {
865 var node
= klass
.members
[i
];
866 if (node
.symbol is Method
) {
867 klass
.remove_member (node
);
868 this
.add_member (node
);
870 Method m
= (Method
) node
.symbol
;
871 m
.binding
= MemberBinding
.CLASS
;
881 foreach (var node
in members
) {
882 node
.process (parser
);
885 if (girdata
!= null) {
886 // GIR node processing
887 if (symbol is Method
) {
888 var m
= (Method
) symbol
;
889 parser
.process_callable (this
);
891 var colliding
= parent
.lookup_all (name
);
892 foreach (var node
in colliding
) {
893 var sym
= node
.symbol
;
894 if (sym is Field
&& !(m
.return_type is VoidType
) && m
.get_parameters().size
== 0) {
895 // assume method is getter
897 } else if (sym is Signal
) {
898 node
.process (parser
);
899 var sig
= (Signal
) sym
;
900 if (m
.is_virtual
|| m
.is_abstract
) {
901 sig
.is_virtual
= true;
903 sig
.set_attribute ("HasEmitter", true);
905 parser
.assume_parameter_names (sig
, m
, false);
906 if (m
.get_parameters().size
!= sig
.get_parameters().size
) {
907 Report
.warning (symbol
.source_reference
, "Signal `%s' conflicts with method of the same name".printf (get_full_name ()));
910 } else if (sym is Method
&& !(sym is CreationMethod
) && node
!= this
) {
911 if (m
.is_virtual
|| m
.is_abstract
) {
912 bool different_invoker
= false;
913 var attr
= m
.get_attribute ("NoWrapper");
915 /* no invoker but this method has the same name,
916 most probably the invoker has a different name
917 and g-ir-scanner missed it */
918 var invoker
= parser
.find_invoker (this
);
919 if (invoker
!= null) {
920 m
.set_attribute_string ("CCode", "vfunc_name", m
.name
);
921 m
.name
= invoker
.symbol
.name
;
922 m
.set_attribute ("NoWrapper", false);
923 invoker
.merged
= true;
924 different_invoker
= true;
927 if (!different_invoker
) {
929 Report
.warning (symbol
.source_reference
, "Virtual method `%s' conflicts with method of the same name".printf (get_full_name ()));
936 if (!(m is CreationMethod
)) {
937 if (metadata
.has_argument (ArgumentType
.DESTROYS_INSTANCE
)) {
938 m
.set_attribute ("DestroysInstance", metadata
.get_bool (ArgumentType
.DESTROYS_INSTANCE
));
940 if (metadata
.has_argument (ArgumentType
.RETURNS_MODIFIED_POINTER
)) {
941 m
.set_attribute ("ReturnsModifiedPointer", metadata
.get_bool (ArgumentType
.RETURNS_MODIFIED_POINTER
));
943 // merge custom vfunc
944 if (metadata
.has_argument (ArgumentType
.VFUNC_NAME
)) {
945 var vfunc
= parent
.lookup (metadata
.get_string (ArgumentType
.VFUNC_NAME
));
946 if (vfunc
!= null && vfunc
!= this
) {
947 vfunc
.processed
= true;
953 parser
.process_async_method (this
);
955 } else if (symbol is Property
) {
956 var colliding
= parent
.lookup_all (name
);
957 foreach (var node
in colliding
) {
958 if (node
.symbol is Signal
) {
959 // properties take precedence
960 node
.processed
= true;
962 } else if (node
.symbol is Method
) {
963 // getter in C, but not in Vala
968 var prop
= (Property
) symbol
;
970 // add accessors, can't do this before gir symbol resolution
971 var readable
= girdata
["readable"];
972 var writable
= girdata
["writable"];
973 var construct_
= girdata
["construct"];
974 var construct_only
= girdata
["construct-only"];
975 if (readable
!= "0") {
976 prop
.get_accessor
= new
PropertyAccessor (true, false, false, prop
.property_type
.copy (), null, null);
978 if (writable
== "1" || construct_only
== "1") {
979 prop
.set_accessor
= new
PropertyAccessor (false, (construct_only
!= "1") && (writable
== "1"), (construct_only
== "1") || (construct_
== "1"), prop
.property_type
.copy (), null, null);
982 // find virtual/abstract accessors to handle abstract properties properly
985 var getters
= parent
.lookup_all ("get_%s".printf (name
));
986 if (getters
!= null) {
987 foreach (var g
in getters
) {
988 if ((getter
== null || !g
.merged
) && g
.get_cname () == "%sget_%s".printf (parent
.get_lower_case_cprefix (), name
)) {
995 var setters
= parent
.lookup_all ("set_%s".printf (name
));
996 if (setters
!= null) {
997 foreach (var s
in setters
) {
998 if ((setter
== null || !s
.merged
) && s
.get_cname () == "%sset_%s".printf (parent
.get_lower_case_cprefix (), name
)) {
1004 prop
.set_attribute ("NoAccessorMethod", (readable
== "0" && construct_only
== "1"));
1005 if (prop
.get_accessor
!= null) {
1006 var m
= getter
!= null ? getter
.symbol as Method
: null;
1007 // ensure getter vfunc if the property is abstract
1009 getter
.process (parser
);
1010 if (m
.return_type is VoidType
|| m
.get_parameters().size
!= 0 || m
.get_error_types ().size
> 0) {
1011 prop
.set_attribute ("NoAccessorMethod", true);
1013 if (getter
.name
== name
) {
1014 foreach (var node
in colliding
) {
1015 if (node
.symbol is Method
) {
1021 prop
.get_accessor
.value_type
.value_owned
= m
.return_type
.value_owned
;
1023 if (!m
.is_abstract
&& !m
.is_virtual
&& prop
.is_abstract
) {
1024 prop
.set_attribute ("ConcreteAccessor", true);
1028 prop
.set_attribute ("NoAccessorMethod", true);
1032 if (prop
.get_attribute ("NoAccessorMethod") == null && prop
.set_accessor
!= null && prop
.set_accessor
.writable
) {
1033 var m
= setter
!= null ? setter
.symbol as Method
: null;
1034 // ensure setter vfunc if the property is abstract
1036 setter
.process (parser
);
1037 if (!(m
.return_type is VoidType
|| m
.return_type is BooleanType
) || m
.get_parameters ().size
!= 1 || m
.get_error_types ().size
> 0) {
1038 prop
.set_attribute ("NoAccessorMethod", true);
1039 prop
.set_attribute ("ConcreteAccessor", false);
1041 prop
.set_accessor
.value_type
.value_owned
= m
.get_parameters()[0].variable_type
.value_owned
;
1042 if (prop
.get_attribute ("ConcreteAccessor") != null && !m
.is_abstract
&& !m
.is_virtual
&& prop
.is_abstract
) {
1043 prop
.set_attribute ("ConcreteAccessor", true);
1044 prop
.set_attribute ("NoAccessorMethod", false);
1048 prop
.set_attribute ("NoAccessorMethod", true);
1049 prop
.set_attribute ("ConcreteAccessor", false);
1053 if (prop
.get_attribute ("NoAccessorMethod") != null) {
1054 if (!prop
.overrides
&& parent
.symbol is Class
) {
1056 // find base interface property with ConcreteAccessor and this overriding property with NoAccessorMethod
1057 var base_prop_node
= parser
.base_interface_property (this
);
1058 if (base_prop_node
!= null) {
1059 base_prop_node
.process (parser
);
1061 var base_property
= (Property
) base_prop_node
.symbol
;
1062 if (base_property
.get_attribute ("ConcreteAccessor") != null) {
1063 prop
.set_attribute ("NoAccessorMethod", false);
1064 if (prop
.get_accessor
!= null) {
1065 prop
.get_accessor
.value_type
.value_owned
= base_property
.get_accessor
.value_type
.value_owned
;
1067 if (prop
.set_accessor
!= null) {
1068 prop
.set_accessor
.value_type
.value_owned
= base_property
.set_accessor
.value_type
.value_owned
;
1076 if (metadata
.has_argument (ArgumentType
.NO_ACCESSOR_METHOD
)) {
1077 prop
.set_attribute ("NoAccessorMethod", metadata
.get_bool (ArgumentType
.NO_ACCESSOR_METHOD
));
1080 if (prop
.get_attribute ("NoAccessorMethod") != null) {
1082 if (prop
.get_accessor
!= null) {
1083 prop
.get_accessor
.value_type
.value_owned
= true;
1085 if (prop
.set_accessor
!= null) {
1086 prop
.set_accessor
.value_type
.value_owned
= false;
1089 } else if (symbol is Field
) {
1090 var field
= (Field
) symbol
;
1091 var colliding
= parent
.lookup_all (name
);
1092 if (colliding
.size
> 1) {
1093 // whatelse has precedence over the field
1097 if (metadata
.has_argument (ArgumentType
.DELEGATE_TARGET
)) {
1098 field
.set_attribute_bool ("CCode", "delegate_target", metadata
.get_bool (ArgumentType
.DELEGATE_TARGET
));
1100 if (metadata
.has_argument (ArgumentType
.DELEGATE_TARGET_CNAME
)) {
1101 field
.set_attribute_string ("CCode", "delegate_target_cname", metadata
.get_string (ArgumentType
.DELEGATE_TARGET_CNAME
));
1104 if (field
.variable_type is DelegateType
&& parent
.gtype_struct_for
!= null) {
1105 // virtual method field
1106 var d
= ((DelegateType
) field
.variable_type
).delegate_symbol
;
1107 parser
.process_virtual_method_field (this
, d
, parent
.gtype_struct_for
);
1109 } else if (field
.variable_type is ArrayType
) {
1111 if (metadata
.has_argument (ArgumentType
.ARRAY_LENGTH_FIELD
)) {
1112 array_length
= parent
.lookup (metadata
.get_string (ArgumentType
.ARRAY_LENGTH_FIELD
));
1113 } else if (array_length_idx
> -1 && parent
.members
.size
> array_length_idx
) {
1114 array_length
= parent
.members
[array_length_idx
];
1116 array_length
= parent
.lookup ("n_%s".printf (field
.name
));
1117 if (array_length
== null) {
1118 array_length
= parent
.lookup ("num_%s".printf (field
.name
));
1119 if (array_length
== null) {
1120 array_length
= parent
.lookup ("%s_length".printf (field
.name
));
1124 if (array_length
!= null && array_length
.symbol is Field
) {
1125 var length_field
= (Field
) array_length
.symbol
;
1127 field
.set_attribute_string ("CCode", "array_length_cname", length_field
.name
);
1128 var length_type
= length_field
.variable_type
.to_qualified_string ();
1129 if (length_type
!= "int") {
1130 var st
= parser
.root
.lookup (length_type
);
1132 field
.set_attribute_string ("CCode", "array_length_type", st
.get_cname ());
1135 field
.remove_attribute_argument ("CCode", "array_length");
1136 field
.remove_attribute_argument ("CCode", "array_null_terminated");
1139 } else if (symbol is Signal
|| symbol is Delegate
) {
1140 parser
.process_callable (this
);
1141 } else if (symbol is Interface
) {
1142 parser
.process_interface (this
);
1143 } else if (symbol is Struct
) {
1144 if (parent
.symbol is ObjectTypeSymbol
|| parent
.symbol is Struct
) {
1146 foreach (var fn
in members
) {
1147 var f
= fn
.symbol as Field
;
1149 if (f
.binding
== MemberBinding
.INSTANCE
) {
1150 f
.set_attribute_string ("CCode", "cname", "%s.%s".printf (name
, fn
.get_cname ()));
1152 f
.name
= "%s_%s".printf (symbol
.name
, f
.name
);
1154 parent
.add_member (fn
);
1159 // record for a gtype
1160 var gtype_struct_for
= girdata
["glib:is-gtype-struct-for"];
1161 if (gtype_struct_for
!= null) {
1162 var iface
= parser
.resolve_node (parent
, parser
.parse_symbol_from_string (gtype_struct_for
, source_reference
));
1163 if (iface
!= null && iface
.symbol is Interface
&& "%sIface".printf (iface
.get_cname ()) != get_cname ()) {
1164 // set the interface struct name
1165 iface
.symbol
.set_attribute_string ("CCode", "type_cname", get_cname ());
1173 if (metadata
.has_argument (ArgumentType
.REPLACEMENT
)) {
1175 deprecated_replacement
= metadata
.get_string (ArgumentType
.REPLACEMENT
);
1177 if (metadata
.has_argument (ArgumentType
.DEPRECATED_SINCE
)) {
1179 deprecated_since
= metadata
.get_string (ArgumentType
.DEPRECATED_SINCE
);
1180 } else if (girdata
["deprecated-version"] != null) {
1182 deprecated_since
= girdata
.get ("deprecated-version");
1184 if (metadata
.has_argument (ArgumentType
.DEPRECATED
)) {
1185 deprecated
= metadata
.get_bool (ArgumentType
.DEPRECATED
, true);
1187 deprecated_since
= null;
1188 deprecated_replacement
= null;
1190 } else if (girdata
["deprecated"] != null) {
1193 if (deprecated_since
!= null) {
1194 deprecated_version
= parse_version_string (deprecated_since
);
1198 if (metadata
.has_argument (ArgumentType
.EXPERIMENTAL
)) {
1199 symbol
.set_attribute_bool ("Version", "experimental", metadata
.get_bool (ArgumentType
.EXPERIMENTAL
));
1203 if (metadata
.has_argument (ArgumentType
.SINCE
)) {
1204 symbol
.version
.since
= metadata
.get_string (ArgumentType
.SINCE
);
1205 } else if (symbol is Namespace
== false && girdata
["version"] != null) {
1206 symbol
.version
.since
= girdata
.get ("version");
1209 if (parent
.symbol is Namespace
) {
1210 // always write cheader filename for namespace children
1211 symbol
.set_attribute_string ("CCode", "cheader_filename", get_cheader_filename ());
1212 } else if (metadata
.has_argument (ArgumentType
.CHEADER_FILENAME
)) {
1213 symbol
.set_attribute_string ("CCode", "cheader_filename", metadata
.get_string (ArgumentType
.CHEADER_FILENAME
));
1215 if (get_cname () != get_default_cname ()) {
1216 symbol
.set_attribute_string ("CCode", "cname", get_cname ());
1219 // lower_case_cprefix
1220 if (get_lower_case_cprefix () != get_default_lower_case_cprefix ()) {
1221 symbol
.set_attribute_string ("CCode", "lower_case_cprefix", get_lower_case_cprefix ());
1223 // lower_case_csuffix
1224 if (get_lower_case_csuffix () != get_default_lower_case_csuffix ()) {
1225 symbol
.set_attribute_string ("CCode", "lower_case_csuffix", get_lower_case_csuffix ());
1228 // set gir name if the symbol has been renamed
1229 string gir_name
= get_gir_name ();
1230 string default_gir_name
= get_default_gir_name ();
1231 if (is_container (symbol
) && !(symbol is Namespace
) && (name
!= gir_name
|| gir_name
!= default_gir_name
)) {
1232 symbol
.set_attribute_string ("GIR", "name", gir_name
);
1236 if (!(new_symbol
&& merged
) && is_container (symbol
)) {
1237 foreach (var node
in members
) {
1238 if (this
.deprecated_version
> 0 && node
.deprecated_version
> 0) {
1239 if (this
.deprecated_version
<= node
.deprecated_version
) {
1240 node
.deprecated
= false;
1241 node
.deprecated_since
= null;
1242 node
.deprecated_replacement
= null;
1245 if (node
.deprecated
) {
1246 node
.symbol
.version
.deprecated
= true;
1248 if (node
.deprecated_since
!= null) {
1249 node
.symbol
.version
.deprecated_since
= node
.deprecated_since
;
1251 if (node
.deprecated_replacement
!= null) {
1252 node
.symbol
.version
.replacement
= node
.deprecated_replacement
;
1255 if (node
.new_symbol
&& !node
.merged
&& !metadata
.get_bool (ArgumentType
.HIDDEN
)) {
1256 add_symbol_to_container (symbol
, node
.symbol
);
1260 var cl
= symbol as Class
;
1261 if (cl
!= null && !cl
.is_compact
&& cl
.default_construction_method
== null) {
1262 // always provide constructor in generated bindings
1263 // to indicate that implicit Object () chainup is allowed
1264 var cm
= new
CreationMethod (null, null, cl
.source_reference
);
1265 cm
.has_construct_function
= false;
1266 cm
.access
= SymbolAccessibility
.PROTECTED
;
1274 public string to_string () {
1275 if (parent
.name
== null) {
1278 return "%s.%s".printf (parent
.to_string (), name
);
1283 static GLib
.Regex type_from_string_regex
;
1285 MarkupReader reader
;
1287 CodeContext context
;
1290 SourceFile current_source_file
;
1292 ArrayList
<Metadata
> metadata_roots
= new ArrayList
<Metadata
> ();
1294 SourceLocation begin
;
1296 MarkupTokenType current_token
;
1298 string[] cheader_filenames
;
1300 ArrayList
<Metadata
> metadata_stack
;
1302 ArrayList
<Node
> tree_stack
;
1306 Set
<string> provided_namespaces
= new HashSet
<string> (str_hash
, str_equal
);
1307 HashMap
<UnresolvedSymbol
,Symbol
> unresolved_symbols_map
= new HashMap
<UnresolvedSymbol
,Symbol
> (unresolved_symbol_hash
, unresolved_symbol_equal
);
1308 ArrayList
<UnresolvedSymbol
> unresolved_gir_symbols
= new ArrayList
<UnresolvedSymbol
> ();
1309 HashMap
<UnresolvedType
,Node
> unresolved_type_arguments
= new HashMap
<UnresolvedType
,Node
> ();
1312 * Parses all .gir source files in the specified code
1313 * context and builds a code tree.
1315 * @param context a code context
1317 public void parse (CodeContext context
) {
1318 this
.context
= context
;
1319 glib_ns
= context
.root
.scope
.lookup ("GLib") as Namespace
;
1321 root
= new
Node (null);
1322 root
.symbol
= context
.root
;
1323 tree_stack
= new ArrayList
<Node
> ();
1328 context
.accept (this
);
1330 resolve_gir_symbols ();
1331 create_new_namespaces ();
1332 resolve_type_arguments ();
1334 root
.process (this
);
1336 foreach (var metadata
in metadata_roots
) {
1337 report_unused_metadata (metadata
);
1340 this
.context
= null;
1343 void map_vala_to_gir () {
1344 foreach (var source_file
in context
.get_source_files ()) {
1345 string gir_namespace
= source_file
.gir_namespace
;
1346 string gir_version
= source_file
.gir_version
;
1347 Namespace ns
= null;
1348 if (gir_namespace
== null) {
1349 foreach (var node
in source_file
.get_nodes ()) {
1350 if (node is Namespace
) {
1351 ns
= (Namespace
) node
;
1352 gir_namespace
= ns
.get_attribute_string ("CCode", "gir_namespace");
1353 if (gir_namespace
!= null) {
1354 gir_version
= ns
.get_attribute_string ("CCode", "gir_version");
1360 if (gir_namespace
== null) {
1364 provided_namespaces
.add ("%s-%s".printf (gir_namespace
, gir_version
));
1366 var gir_symbol
= new
UnresolvedSymbol (null, gir_namespace
);
1367 if (gir_namespace
!= ns
.name
) {
1368 set_symbol_mapping (gir_symbol
, ns
);
1371 foreach (var node
in source_file
.get_nodes ()) {
1372 if (node
.has_attribute_argument ("GIR", "name")) {
1373 var map_from
= new
UnresolvedSymbol (gir_symbol
, node
.get_attribute_string ("GIR", "name"));
1374 set_symbol_mapping (map_from
, (Symbol
) node
);
1380 public override void visit_source_file (SourceFile source_file
) {
1381 if (source_file
.filename
.has_suffix (".gir")) {
1382 parse_file (source_file
);
1386 public void parse_file (SourceFile source_file
) {
1387 var has_global_context
= (context
!= null);
1388 if (!has_global_context
) {
1389 context
= source_file
.context
;
1392 metadata_stack
= new ArrayList
<Metadata
> ();
1393 metadata
= Metadata
.empty
;
1394 cheader_filenames
= null;
1396 this
.current_source_file
= source_file
;
1397 reader
= new
MarkupReader (source_file
.filename
);
1404 parse_repository ();
1407 this
.current_source_file
= null;
1408 if (!has_global_context
) {
1414 current_token
= reader
.read_token (out begin
, out end
);
1417 void start_element (string name
) {
1418 if (current_token
!= MarkupTokenType
.START_ELEMENT
|| reader
.name
!= name
) {
1420 Report
.error (get_current_src (), "expected start element of `%s'".printf (name
));
1424 void end_element (string name
) {
1425 while (current_token
!= MarkupTokenType
.END_ELEMENT
|| reader
.name
!= name
) {
1426 Report
.warning (get_current_src (), "expected end element of `%s'".printf (name
));
1432 SourceReference
get_current_src () {
1433 return new
SourceReference (this
.current_source_file
, begin
, end
);
1436 const string GIR_VERSION
= "1.2";
1438 static void add_symbol_to_container (Symbol container
, Symbol sym
) {
1439 if (container is Class
) {
1440 unowned Class cl
= (Class
) container
;
1443 cl
.add_class ((Class
) sym
);
1444 } else if (sym is Constant
) {
1445 cl
.add_constant ((Constant
) sym
);
1446 } else if (sym is Enum
) {
1447 cl
.add_enum ((Enum
) sym
);
1448 } else if (sym is Field
) {
1449 cl
.add_field ((Field
) sym
);
1450 } else if (sym is Method
) {
1451 cl
.add_method ((Method
) sym
);
1452 } else if (sym is Property
) {
1453 cl
.add_property ((Property
) sym
);
1454 } else if (sym is Signal
) {
1455 cl
.add_signal ((Signal
) sym
);
1456 } else if (sym is Struct
) {
1457 cl
.add_struct ((Struct
) sym
);
1459 } else if (container is Enum
) {
1460 unowned Enum en
= (Enum
) container
;
1462 if (sym is EnumValue
) {
1463 en
.add_value ((EnumValue
) sym
);
1464 } else if (sym is Constant
) {
1465 en
.add_constant ((Constant
) sym
);
1466 } else if (sym is Method
) {
1467 en
.add_method ((Method
) sym
);
1469 } else if (container is Interface
) {
1470 unowned Interface iface
= (Interface
) container
;
1473 iface
.add_class ((Class
) sym
);
1474 } else if (sym is Constant
) {
1475 iface
.add_constant ((Constant
) sym
);
1476 } else if (sym is Enum
) {
1477 iface
.add_enum ((Enum
) sym
);
1478 } else if (sym is Field
) {
1479 iface
.add_field ((Field
) sym
);
1480 } else if (sym is Method
) {
1481 iface
.add_method ((Method
) sym
);
1482 } else if (sym is Property
) {
1483 iface
.add_property ((Property
) sym
);
1484 } else if (sym is Signal
) {
1485 iface
.add_signal ((Signal
) sym
);
1486 } else if (sym is Struct
) {
1487 iface
.add_struct ((Struct
) sym
);
1489 } else if (container is Namespace
) {
1490 unowned Namespace ns
= (Namespace
) container
;
1492 if (sym is Namespace
) {
1493 ns
.add_namespace ((Namespace
) sym
);
1494 } else if (sym is Class
) {
1495 ns
.add_class ((Class
) sym
);
1496 } else if (sym is Constant
) {
1497 ns
.add_constant ((Constant
) sym
);
1498 } else if (sym is Delegate
) {
1499 ns
.add_delegate ((Delegate
) sym
);
1500 } else if (sym is Enum
) {
1501 ns
.add_enum ((Enum
) sym
);
1502 } else if (sym is ErrorDomain
) {
1503 ns
.add_error_domain ((ErrorDomain
) sym
);
1504 } else if (sym is Field
) {
1505 ns
.add_field ((Field
) sym
);
1506 } else if (sym is Interface
) {
1507 ns
.add_interface ((Interface
) sym
);
1508 } else if (sym is Method
) {
1509 ns
.add_method ((Method
) sym
);
1510 } else if (sym is Struct
) {
1511 ns
.add_struct ((Struct
) sym
);
1513 } else if (container is Struct
) {
1514 unowned Struct st
= (Struct
) container
;
1516 if (sym is Constant
) {
1517 st
.add_constant ((Constant
) sym
);
1518 } else if (sym is Field
) {
1519 st
.add_field ((Field
) sym
);
1520 } else if (sym is Method
) {
1521 st
.add_method ((Method
) sym
);
1522 } else if (sym is Property
) {
1523 st
.add_property ((Property
) sym
);
1525 } else if (container is ErrorDomain
) {
1526 unowned ErrorDomain ed
= (ErrorDomain
) container
;
1528 if (sym is ErrorCode
) {
1529 ed
.add_code ((ErrorCode
) sym
);
1530 } else if (sym is Method
) {
1531 ed
.add_method ((Method
) sym
);
1534 Report
.error (sym
.source_reference
, "impossible to add `%s' to container `%s'".printf (sym
.name
, container
.name
));
1538 static bool is_container (Symbol sym
) {
1539 return sym is ObjectTypeSymbol
|| sym is Struct
|| sym is Namespace
|| sym is ErrorDomain
|| sym is Enum
;
1542 UnresolvedSymbol?
parse_symbol_from_string (string symbol_string
, SourceReference? source_reference
= null) {
1543 UnresolvedSymbol? sym
= null;
1544 foreach (unowned
string s
in symbol_string
.split (".")) {
1545 sym
= new
UnresolvedSymbol (sym
, s
, source_reference
);
1548 Report
.error (source_reference
, "a symbol must be specified");
1553 void set_symbol_mapping (UnresolvedSymbol map_from
, Symbol map_to
) {
1554 // last mapping is the most up-to-date
1555 if (map_from is UnresolvedSymbol
) {
1556 unresolved_symbols_map
[(UnresolvedSymbol
) map_from
] = map_to
;
1560 void assume_parameter_names (Signal sig
, Symbol sym
, bool skip_first
) {
1561 var iter
= ((Callable
) sym
).get_parameters ().iterator ();
1563 foreach (var param
in sig
.get_parameters ()) {
1564 if (!iter
.next ()) {
1565 // unreachable for valid GIR
1568 if (skip_first
&& first
) {
1569 if (!iter
.next ()) {
1570 // unreachable for valid GIR
1575 param
.name
= iter
.get ().name
;
1579 Node?
find_invoker (Node node
) {
1580 /* most common use case is invoker has at least the given method prefix
1581 and the same parameter names */
1582 var m
= (Method
) node
.symbol
;
1583 var prefix
= "%s_".printf (m
.name
);
1584 foreach (var n
in node
.parent
.members
) {
1585 if (!n
.name
.has_prefix (prefix
)) {
1588 Method? invoker
= n
.symbol as Method
;
1589 if (invoker
== null || (m
.get_parameters().size
!= invoker
.get_parameters().size
)) {
1592 var iter
= invoker
.get_parameters ().iterator ();
1593 foreach (var param
in m
.get_parameters ()) {
1594 assert (iter
.next ());
1595 if (param
.name
!= iter
.get().name
) {
1600 if (invoker
!= null) {
1608 Metadata
get_current_metadata () {
1609 var selector
= reader
.name
;
1610 var child_name
= reader
.get_attribute ("name");
1611 if (child_name
== null) {
1612 child_name
= reader
.get_attribute ("glib:name");
1614 // Give a transparent union the generic name "union"
1615 if (selector
== "union" && child_name
== null) {
1616 child_name
= "union";
1618 if (child_name
== null) {
1619 return Metadata
.empty
;
1621 selector
= selector
.replace ("-", "_");
1622 child_name
= child_name
.replace ("-", "_");
1624 if (selector
.has_prefix ("glib:")) {
1625 selector
= selector
.substring ("glib:".length
);
1628 return metadata
.match_child (child_name
, selector
);
1631 bool push_metadata () {
1632 var new_metadata
= get_current_metadata ();
1634 if (new_metadata
.has_argument (ArgumentType
.SKIP
)) {
1635 if (new_metadata
.get_bool (ArgumentType
.SKIP
)) {
1638 } else if (reader
.get_attribute ("introspectable") == "0" || reader
.get_attribute ("private") == "1") {
1642 metadata_stack
.add (metadata
);
1643 metadata
= new_metadata
;
1648 void pop_metadata () {
1649 metadata
= metadata_stack
.remove_at (metadata_stack
.size
- 1);
1652 bool parse_type_arguments_from_string (DataType parent_type
, string type_arguments
, SourceReference? source_reference
= null) {
1653 int type_arguments_length
= (int) type_arguments
.length
;
1654 GLib
.StringBuilder current
= new GLib
.StringBuilder
.sized (type_arguments_length
);
1657 for (var c
= 0 ; c
< type_arguments_length
; c
++) {
1658 if (type_arguments
[c
] == '<' || type_arguments
[c
] == '[') {
1660 current
.append_unichar (type_arguments
[c
]);
1661 } else if (type_arguments
[c
] == '>' || type_arguments
[c
] == ']') {
1663 current
.append_unichar (type_arguments
[c
]);
1664 } else if (type_arguments
[c
] == ',') {
1666 var dt
= parse_type_from_string (current
.str
, true, source_reference
);
1670 parent_type
.add_type_argument (dt
);
1671 current
.truncate ();
1673 current
.append_unichar (type_arguments
[c
]);
1676 current
.append_unichar (type_arguments
[c
]);
1680 var dt
= parse_type_from_string (current
.str
, true, source_reference
);
1684 parent_type
.add_type_argument (dt
);
1689 DataType?
parse_type_from_string (string type_string
, bool owned_by_default
, SourceReference? source_reference
= null) {
1690 if (type_from_string_regex
== null) {
1692 type_from_string_regex
= new GLib
.Regex ("^(?:(owned|unowned|weak) +)?([0-9a-zA-Z_\\.]+)(?:<(.+)>)?(\\*+)?(\\[,*\\])?(\\?)?$", GLib
.RegexCompileFlags
.ANCHORED
| GLib
.RegexCompileFlags
.DOLLAR_ENDONLY
| GLib
.RegexCompileFlags
.OPTIMIZE
);
1693 } catch (GLib
.RegexError e
) {
1694 GLib
.error ("Unable to compile regex: %s", e
.message
);
1698 GLib
.MatchInfo match
;
1699 if (!type_from_string_regex
.match (type_string
, 0, out match
)) {
1700 Report
.error (source_reference
, "unable to parse type");
1704 DataType? type
= null;
1706 var ownership_data
= match
.fetch (1);
1707 var type_name
= match
.fetch (2);
1708 var type_arguments_data
= match
.fetch (3);
1709 var pointers_data
= match
.fetch (4);
1710 var array_data
= match
.fetch (5);
1711 var nullable_data
= match
.fetch (6);
1713 var nullable
= nullable_data
!= null && nullable_data
.length
> 0;
1715 if (ownership_data
== null && type_name
== "void") {
1716 if (array_data
== null && !nullable
) {
1717 type
= new
VoidType (source_reference
);
1718 if (pointers_data
!= null) {
1719 for (int i
=0; i
< pointers_data
.length
; i
++) {
1720 type
= new
PointerType (type
);
1725 Report
.error (source_reference
, "invalid void type");
1730 bool value_owned
= owned_by_default
;
1732 if (ownership_data
== "owned") {
1733 if (owned_by_default
) {
1734 Report
.error (source_reference
, "unexpected `owned' keyword");
1738 } else if (ownership_data
== "unowned") {
1739 if (owned_by_default
) {
1740 value_owned
= false;
1742 Report
.error (source_reference
, "unexpected `unowned' keyword");
1747 var sym
= parse_symbol_from_string (type_name
, source_reference
);
1751 type
= new UnresolvedType
.from_symbol (sym
, source_reference
);
1753 if (type_arguments_data
!= null && type_arguments_data
.length
> 0) {
1754 if (!parse_type_arguments_from_string (type
, type_arguments_data
, source_reference
)) {
1759 if (pointers_data
!= null) {
1760 for (int i
=0; i
< pointers_data
.length
; i
++) {
1761 type
= new
PointerType (type
);
1765 if (array_data
!= null && array_data
.length
!= 0) {
1766 type
.value_owned
= true;
1767 type
= new
ArrayType (type
, (int) array_data
.length
- 1, source_reference
);
1770 type
.nullable
= nullable
;
1771 type
.value_owned
= value_owned
;
1775 string?
element_get_string (string attribute_name
, ArgumentType arg_type
) {
1776 if (metadata
.has_argument (arg_type
)) {
1777 return metadata
.get_string (arg_type
);
1779 return reader
.get_attribute (attribute_name
);
1784 * The changed is a faster way to check whether the type has changed and it may affect the C declaration.
1786 DataType?
element_get_type (DataType orig_type
, bool owned_by_default
, ref bool no_array_length
, ref bool array_null_terminated
, out bool changed
= null) {
1788 var type
= orig_type
;
1790 if (metadata
.has_argument (ArgumentType
.TYPE
)) {
1791 type
= parse_type_from_string (metadata
.get_string (ArgumentType
.TYPE
), owned_by_default
, metadata
.get_source_reference (ArgumentType
.TYPE
));
1793 } else if (!(type is VoidType
)) {
1794 if (metadata
.has_argument (ArgumentType
.TYPE_ARGUMENTS
)) {
1795 type
.remove_all_type_arguments ();
1796 parse_type_arguments_from_string (type
, metadata
.get_string (ArgumentType
.TYPE_ARGUMENTS
), metadata
.get_source_reference (ArgumentType
.TYPE_ARGUMENTS
));
1799 if (!(type is ArrayType
) && metadata
.get_bool (ArgumentType
.ARRAY
)) {
1800 type
.value_owned
= true;
1801 type
= new
ArrayType (type
, 1, type
.source_reference
);
1805 if (owned_by_default
) {
1806 type
.value_owned
= !metadata
.get_bool (ArgumentType
.UNOWNED
, !type
.value_owned
);
1808 type
.value_owned
= metadata
.get_bool (ArgumentType
.OWNED
, type
.value_owned
);
1810 type
.nullable
= metadata
.get_bool (ArgumentType
.NULLABLE
, type
.nullable
);
1813 if (type is ArrayType
) {
1814 if (!(orig_type is ArrayType
)) {
1815 no_array_length
= true;
1817 array_null_terminated
= metadata
.get_bool (ArgumentType
.ARRAY_NULL_TERMINATED
, array_null_terminated
);
1823 string?
element_get_name (string? gir_name
= null) {
1824 var name
= gir_name
;
1826 name
= reader
.get_attribute ("name");
1828 var pattern
= metadata
.get_string (ArgumentType
.NAME
);
1829 if (pattern
!= null) {
1830 if (pattern
.index_of_char ('(') < 0) {
1831 // shortcut for "(.+)/replacement"
1835 string replacement
= "\\1"; // replace the whole name with the match by default
1836 var split
= pattern
.split ("/");
1837 if (split
.length
> 1) {
1839 replacement
= split
[1];
1841 var regex
= new
Regex (pattern
, RegexCompileFlags
.ANCHORED
, RegexMatchFlags
.ANCHORED
);
1842 name
= regex
.replace (name
, -1, 0, replacement
);
1848 if (name
!= null && name
.has_suffix ("Enum")) {
1849 name
= name
.substring (0, name
.length
- "Enum".length
);
1856 string?
element_get_type_id () {
1857 var type_id
= metadata
.get_string (ArgumentType
.TYPE_ID
);
1858 if (type_id
!= null) {
1862 type_id
= reader
.get_attribute ("glib:get-type");
1863 if (type_id
!= null) {
1869 void set_array_ccode (Symbol sym
, ParameterInfo info
) {
1870 sym
.set_attribute_double ("CCode", "array_length_pos", info
.vala_idx
);
1871 if (sym is Parameter
) {
1872 sym
.set_attribute_string ("CCode", "array_length_cname", info
.param
.name
);
1874 var type_name
= info
.param
.variable_type
.to_qualified_string ();
1875 if (type_name
!= "int") {
1876 var st
= root
.lookup (type_name
);
1878 if (sym is Method
) {
1879 var m
= (Method
) sym
;
1880 m
.set_attribute_string ("CCode", "array_length_type", st
.get_cname ());
1882 var param
= (Parameter
) sym
;
1883 param
.set_attribute_string ("CCode", "array_length_type", st
.get_cname ());
1889 void set_type_id_ccode (Symbol sym
) {
1890 if (sym
.has_attribute_argument ("CCode", "has_type_id")
1891 || sym
.has_attribute_argument ("CCode", "type_id"))
1894 var type_id
= element_get_type_id ();
1895 if (type_id
== null) {
1896 sym
.set_attribute_bool ("CCode", "has_type_id", false);
1898 sym
.set_attribute_string ("CCode", "type_id", type_id
);
1902 void parse_repository () {
1903 start_element ("repository");
1904 if (reader
.get_attribute ("version") != GIR_VERSION
) {
1905 Report
.error (get_current_src (), "unsupported GIR version %s (supported: %s)".printf (reader
.get_attribute ("version"), GIR_VERSION
));
1909 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1910 if (reader
.name
== "namespace") {
1912 } else if (reader
.name
== "include") {
1914 } else if (reader
.name
== "package") {
1915 var pkg
= parse_package ();
1916 this
.current_source_file
.package_name
= pkg
;
1917 if (context
.has_package (pkg
)) {
1918 // package already provided elsewhere, stop parsing this GIR
1919 // if it was not passed explicitly
1920 if (!this
.current_source_file
.explicit
) {
1924 context
.add_package (pkg
);
1926 } else if (reader
.name
== "c:include") {
1930 Report
.error (get_current_src (), "unknown child element `%s' in `repository'".printf (reader
.name
));
1934 end_element ("repository");
1937 void parse_include () {
1938 start_element ("include");
1939 var pkg
= reader
.get_attribute ("name");
1940 var version
= reader
.get_attribute ("version");
1941 if (version
!= null) {
1942 pkg
= "%s-%s".printf (pkg
, version
);
1944 // add the package to the queue
1945 context
.add_external_package (pkg
);
1947 end_element ("include");
1950 string parse_package () {
1951 start_element ("package");
1952 var pkg
= reader
.get_attribute ("name");
1954 end_element ("package");
1958 void parse_c_include () {
1959 start_element ("c:include");
1960 cheader_filenames
+= reader
.get_attribute ("name");
1962 end_element ("c:include");
1965 void skip_element () {
1970 if (current_token
== MarkupTokenType
.START_ELEMENT
) {
1972 } else if (current_token
== MarkupTokenType
.END_ELEMENT
) {
1974 } else if (current_token
== MarkupTokenType
.EOF
) {
1975 Report
.error (get_current_src (), "unexpected end of file");
1982 Node?
resolve_node (Node parent_scope
, UnresolvedSymbol unresolved_sym
, bool create_namespace
= false) {
1983 if (unresolved_sym
.inner
== null) {
1984 var scope
= parent_scope
;
1985 while (scope
!= null) {
1986 var node
= scope
.lookup (unresolved_sym
.name
, create_namespace
, unresolved_sym
.source_reference
);
1990 scope
= scope
.parent
;
1993 var inner
= resolve_node (parent_scope
, unresolved_sym
.inner
, create_namespace
);
1994 if (inner
!= null) {
1995 return inner
.lookup (unresolved_sym
.name
, create_namespace
, unresolved_sym
.source_reference
);
2001 Symbol?
resolve_symbol (Node parent_scope
, UnresolvedSymbol unresolved_sym
) {
2002 var node
= resolve_node (parent_scope
, unresolved_sym
);
2009 void push_node (string name
, bool merge
) {
2010 var parent
= current
;
2011 if (metadata
.has_argument (ArgumentType
.PARENT
)) {
2012 var target
= parse_symbol_from_string (metadata
.get_string (ArgumentType
.PARENT
), metadata
.get_source_reference (ArgumentType
.PARENT
));
2013 parent
= resolve_node (root
, target
, true);
2016 var node
= parent
.lookup (name
);
2017 if (node
== null || (node
.symbol
!= null && !merge
)) {
2018 node
= new
Node (name
);
2019 node
.new_symbol
= true;
2020 parent
.add_member (node
);
2022 Node
.new_namespaces
.remove (node
);
2024 node
.element_type
= reader
.name
;
2025 node
.girdata
= reader
.get_attributes ();
2026 node
.metadata
= metadata
;
2027 node
.source_reference
= get_current_src ();
2029 var gir_name
= node
.get_gir_name ();
2030 if (parent
!= current
|| gir_name
!= name
) {
2031 set_symbol_mapping (new
UnresolvedSymbol (null, gir_name
), node
.get_unresolved_symbol ());
2034 tree_stack
.add (current
);
2039 old_current
= current
;
2040 current
= tree_stack
.remove_at (tree_stack
.size
- 1);
2043 void parse_namespace () {
2044 start_element ("namespace");
2046 string? cprefix
= reader
.get_attribute ("c:identifier-prefixes");
2047 if (cprefix
!= null) {
2048 int idx
= cprefix
.index_of (",");
2050 cprefix
= cprefix
.substring (0, idx
);
2054 string? lower_case_cprefix
= reader
.get_attribute ("c:symbol-prefixes");
2055 string vala_namespace
= cprefix
;
2056 string gir_namespace
= reader
.get_attribute ("name");
2057 string gir_version
= reader
.get_attribute ("version");
2059 if (lower_case_cprefix
!= null) {
2060 int idx
= lower_case_cprefix
.index_of (",");
2062 lower_case_cprefix
= lower_case_cprefix
.substring (0, idx
);
2066 if (provided_namespaces
.contains ("%s-%s".printf (gir_namespace
, gir_version
))) {
2071 // load metadata, first look into metadata directories then in the same directory of the .gir.
2072 string? metadata_filename
= context
.get_metadata_path (current_source_file
.filename
);
2073 if (metadata_filename
!= null && FileUtils
.test (metadata_filename
, FileTest
.EXISTS
)) {
2074 var metadata_parser
= new
MetadataParser ();
2075 var metadata_file
= new
SourceFile (context
, current_source_file
.file_type
, metadata_filename
);
2076 context
.add_source_file (metadata_file
);
2077 metadata
= metadata_parser
.parse_metadata (metadata_file
);
2078 metadata_roots
.add (metadata
);
2081 var ns_metadata
= metadata
.match_child (gir_namespace
);
2082 if (ns_metadata
.has_argument (ArgumentType
.NAME
)) {
2083 vala_namespace
= ns_metadata
.get_string (ArgumentType
.NAME
);
2085 if (vala_namespace
== null) {
2086 vala_namespace
= gir_namespace
;
2089 current_source_file
.gir_namespace
= gir_namespace
;
2090 current_source_file
.gir_version
= gir_version
;
2093 push_node (vala_namespace
, true);
2094 if (current
.new_symbol
) {
2095 ns
= new
Namespace (vala_namespace
, current
.source_reference
);
2096 current
.symbol
= ns
;
2098 ns
= (Namespace
) current
.symbol
;
2099 ns
.attributes
= null;
2100 ns
.source_reference
= current
.source_reference
;
2103 current
.metadata
= ns_metadata
;
2105 if (ns_metadata
.has_argument (ArgumentType
.CPREFIX
)) {
2106 cprefix
= ns_metadata
.get_string (ArgumentType
.CPREFIX
);
2109 if (ns_metadata
.has_argument (ArgumentType
.LOWER_CASE_CPREFIX
)) {
2110 lower_case_cprefix
= ns_metadata
.get_string (ArgumentType
.LOWER_CASE_CPREFIX
);
2111 } else if (lower_case_cprefix
!= null) {
2112 lower_case_cprefix
+= "_";
2115 ns
.set_attribute_string ("CCode", "gir_namespace", gir_namespace
);
2116 ns
.set_attribute_string ("CCode", "gir_version", gir_version
);
2118 if (cprefix
!= null) {
2119 ns
.set_attribute_string ("CCode", "cprefix", cprefix
);
2120 if (lower_case_cprefix
== null) {
2121 ns
.set_attribute_string ("CCode", "lower_case_cprefix", Symbol
.camel_case_to_lower_case (cprefix
) + "_");
2125 if (lower_case_cprefix
!= null) {
2126 ns
.set_attribute_string ("CCode", "lower_case_cprefix", lower_case_cprefix
);
2129 if (cheader_filenames
!= null) {
2130 ns
.set_attribute_string ("CCode", "cheader_filename", string.joinv (",", cheader_filenames
));
2134 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2135 if (!push_metadata ()) {
2140 if (reader
.name
== "alias") {
2142 } else if (reader
.name
== "enumeration") {
2143 if (metadata
.has_argument (ArgumentType
.ERRORDOMAIN
)) {
2144 if (metadata
.get_bool (ArgumentType
.ERRORDOMAIN
)) {
2145 parse_error_domain ();
2147 parse_enumeration ();
2150 if ((reader
.get_attribute ("glib:error-quark") != null) || (reader
.get_attribute ("glib:error-domain") != null)) {
2151 parse_error_domain ();
2153 parse_enumeration ();
2156 } else if (reader
.name
== "bitfield") {
2158 } else if (reader
.name
== "function") {
2159 parse_method ("function");
2160 } else if (reader
.name
== "callback") {
2162 } else if (reader
.name
== "record") {
2163 if (metadata
.has_argument (ArgumentType
.STRUCT
)) {
2164 if (metadata
.get_bool (ArgumentType
.STRUCT
)) {
2167 parse_boxed ("record");
2169 } else if (element_get_type_id () != null) {
2170 parse_boxed ("record");
2171 } else if (!reader
.get_attribute ("name").has_suffix ("Private")) {
2172 if (reader
.get_attribute ("glib:is-gtype-struct-for") == null && reader
.get_attribute ("disguised") == "1") {
2173 parse_boxed ("record");
2180 } else if (reader
.name
== "class") {
2182 } else if (reader
.name
== "interface") {
2184 } else if (reader
.name
== "glib:boxed") {
2185 parse_boxed ("glib:boxed");
2186 } else if (reader
.name
== "union") {
2187 if (element_get_type_id () != null && !metadata
.get_bool (ArgumentType
.STRUCT
)) {
2188 parse_boxed ("union");
2192 } else if (reader
.name
== "constant") {
2196 Report
.error (get_current_src (), "unknown child element `%s' in `namespace'".printf (reader
.name
));
2203 end_element ("namespace");
2206 void parse_alias () {
2207 start_element ("alias");
2208 push_node (element_get_name (), true);
2209 // not enough information, symbol will be created while processing the tree
2213 if (current
.comment
== null) {
2214 current
.comment
= parse_symbol_doc ();
2216 parse_symbol_doc ();
2219 bool no_array_length
= false;
2220 bool array_null_terminated
= false;
2221 current
.base_type
= element_get_type (parse_type (null, null, true), true, ref no_array_length
, ref array_null_terminated
);
2223 if (metadata
.has_argument (ArgumentType
.BASE_TYPE
)) {
2224 current
.base_type
= parse_type_from_string (metadata
.get_string (ArgumentType
.BASE_TYPE
), true, metadata
.get_source_reference (ArgumentType
.BASE_TYPE
));
2228 end_element ("alias");
2231 private void calculate_common_prefix (ref string? common_prefix
, string cname
) {
2232 if (common_prefix
== null) {
2233 common_prefix
= cname
;
2234 while (common_prefix
.length
> 0 && !common_prefix
.has_suffix ("_")) {
2235 // FIXME: could easily be made faster
2236 common_prefix
= common_prefix
.substring (0, common_prefix
.length
- 1);
2239 while (!cname
.has_prefix (common_prefix
)) {
2240 common_prefix
= common_prefix
.substring (0, common_prefix
.length
- 1);
2243 while (common_prefix
.length
> 0 && (!common_prefix
.has_suffix ("_") ||
2244 (cname
.get_char (common_prefix
.length
).isdigit ()) && (cname
.length
- common_prefix
.length
) <= 1)) {
2245 // enum values may not consist solely of digits
2246 common_prefix
= common_prefix
.substring (0, common_prefix
.length
- 1);
2250 GirComment?
parse_symbol_doc () {
2251 GirComment? comment
= null;
2253 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2254 unowned
string reader_name
= reader
.name
;
2256 if (reader_name
== "doc") {
2257 start_element ("doc");
2261 if (current_token
== MarkupTokenType
.TEXT
) {
2262 comment
= new
GirComment (reader
.content
, current
.source_reference
);
2266 end_element ("doc");
2267 } else if (reader_name
== "doc-version" || reader_name
== "doc-deprecated" || reader_name
== "doc-stability") {
2277 Comment?
parse_doc () {
2278 Comment? comment
= null;
2280 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2281 unowned
string reader_name
= reader
.name
;
2283 if (reader_name
== "doc") {
2284 start_element ("doc");
2288 if (current_token
== MarkupTokenType
.TEXT
) {
2289 comment
= new
Comment (reader
.content
, current
.source_reference
);
2293 end_element ("doc");
2294 } else if (reader_name
== "doc-version" || reader_name
== "doc-deprecated" || reader_name
== "doc-stability") {
2304 void parse_enumeration (string element_name
= "enumeration", bool error_domain
= false) {
2305 start_element (element_name
);
2306 push_node (element_get_name (), true);
2309 if (current
.new_symbol
) {
2311 sym
= new
ErrorDomain (current
.name
, current
.source_reference
);
2313 var en
= new
Enum (current
.name
, current
.source_reference
);
2314 if (element_name
== "bitfield") {
2315 en
.set_attribute ("Flags", true);
2319 current
.symbol
= sym
;
2321 sym
= current
.symbol
;
2325 set_type_id_ccode (sym
);
2327 sym
.external
= true;
2328 sym
.access
= SymbolAccessibility
.PUBLIC
;
2330 string common_prefix
= null;
2331 bool has_member
= false;
2335 sym
.comment
= parse_symbol_doc ();
2337 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2338 if (!push_metadata ()) {
2343 if (reader
.name
== "member") {
2346 parse_error_member ();
2347 calculate_common_prefix (ref common_prefix
, old_current
.get_cname ());
2349 parse_enumeration_member ();
2350 calculate_common_prefix (ref common_prefix
, old_current
.get_cname ());
2352 } else if (reader
.name
== "function") {
2356 Report
.error (get_current_src (), "unknown child element `%s' in `%s'".printf (reader
.name
, element_name
));
2364 Report
.error (get_current_src (), "%s `%s' has no members".printf (element_name
, current
.name
));
2367 if (common_prefix
!= null) {
2368 sym
.set_attribute_string ("CCode", "cprefix", common_prefix
);
2372 end_element (element_name
);
2375 void parse_error_domain () {
2376 parse_enumeration ("enumeration", true);
2379 void parse_bitfield () {
2380 parse_enumeration ("bitfield");
2383 void parse_enumeration_member () {
2384 start_element ("member");
2385 push_node (element_get_name().ascii_up().replace ("-", "_"), false);
2387 var ev
= new
EnumValue (current
.name
, metadata
.get_expression (ArgumentType
.DEFAULT
), current
.source_reference
);
2388 current
.symbol
= ev
;
2391 ev
.comment
= parse_symbol_doc ();
2394 end_element ("member");
2397 void parse_error_member () {
2398 start_element ("member");
2399 push_node (element_get_name().ascii_up().replace ("-", "_"), false);
2402 string value
= reader
.get_attribute ("value");
2403 if (value
!= null) {
2404 ec
= new ErrorCode
.with_value (current
.name
, new
IntegerLiteral (value
));
2406 ec
= new
ErrorCode (current
.name
);
2408 current
.symbol
= ec
;
2411 ec
.comment
= parse_symbol_doc ();
2414 end_element ("member");
2417 DataType
parse_return_value (out string? ctype
= null, out int array_length_idx
= null, out bool no_array_length
= null, out bool array_null_terminated
= null, out Comment? comment
= null) {
2418 start_element ("return-value");
2420 string transfer
= reader
.get_attribute ("transfer-ownership");
2421 string nullable
= reader
.get_attribute ("nullable");
2422 string allow_none
= reader
.get_attribute ("allow-none");
2425 comment
= parse_doc ();
2427 var transfer_elements
= transfer
!= "container";
2428 var type
= parse_type (out ctype
, out array_length_idx
, transfer_elements
, out no_array_length
, out array_null_terminated
);
2429 if (transfer
== "full" || transfer
== "container") {
2430 type
.value_owned
= true;
2432 if (nullable
== "1" || allow_none
== "1") {
2433 type
.nullable
= true;
2435 type
= element_get_type (type
, true, ref no_array_length
, ref array_null_terminated
);
2437 end_element ("return-value");
2441 Parameter
parse_parameter (out int array_length_idx
= null, out int closure_idx
= null, out int destroy_idx
= null, out string? scope
= null, out Comment? comment
= null, string? default_name
= null) {
2444 array_length_idx
= -1;
2448 string element_type
= reader
.name
;
2449 if (current_token
!= MarkupTokenType
.START_ELEMENT
|| (element_type
!= "parameter" && element_type
!= "instance-parameter")) {
2450 Report
.error (get_current_src (), "expected start element of `parameter' or `instance-parameter'");
2452 start_element (element_type
);
2453 var name
= metadata
.get_string (ArgumentType
.NAME
);
2455 name
= reader
.get_attribute ("name");
2458 name
= default_name
;
2460 string direction
= null;
2461 if (metadata
.has_argument (ArgumentType
.OUT
)) {
2462 if (metadata
.get_bool (ArgumentType
.OUT
)) {
2465 } else if (metadata
.has_argument (ArgumentType
.REF
)) {
2466 if (metadata
.get_bool (ArgumentType
.REF
)) {
2467 direction
= "inout";
2470 direction
= reader
.get_attribute ("direction");
2472 string transfer
= reader
.get_attribute ("transfer-ownership");
2473 string nullable
= reader
.get_attribute ("nullable");
2474 string allow_none
= reader
.get_attribute ("allow-none");
2476 scope
= element_get_string ("scope", ArgumentType
.SCOPE
);
2478 string closure
= reader
.get_attribute ("closure");
2479 string destroy
= reader
.get_attribute ("destroy");
2480 if (closure
!= null && &closure_idx
!= null) {
2481 closure_idx
= int.parse (closure
);
2483 if (destroy
!= null && &destroy_idx
!= null) {
2484 destroy_idx
= int.parse (destroy
);
2486 if (metadata
.has_argument (ArgumentType
.CLOSURE
)) {
2487 closure_idx
= metadata
.get_integer (ArgumentType
.CLOSURE
);
2489 if (metadata
.has_argument (ArgumentType
.DESTROY
)) {
2490 destroy_idx
= metadata
.get_integer (ArgumentType
.DESTROY
);
2495 comment
= parse_doc ();
2497 if (reader
.name
== "varargs") {
2498 start_element ("varargs");
2500 param
= new Parameter
.with_ellipsis (get_current_src ());
2501 end_element ("varargs");
2504 bool no_array_length
;
2505 bool array_null_terminated
;
2506 var type
= parse_type (out ctype
, out array_length_idx
, transfer
!= "container", out no_array_length
, out array_null_terminated
);
2507 if (transfer
== "full" || transfer
== "container" || destroy
!= null) {
2508 type
.value_owned
= true;
2510 if (nullable
== "1" || (allow_none
== "1" && direction
!= "out")) {
2511 type
.nullable
= true;
2515 type
= element_get_type (type
, direction
== "out" || direction
== "inout", ref no_array_length
, ref array_null_terminated
, out changed
);
2517 // discard ctype, duplicated information
2521 param
= new
Parameter (name
, type
, get_current_src ());
2522 if (ctype
!= null) {
2523 param
.set_attribute_string ("CCode", "type", ctype
);
2525 if (direction
== "out") {
2526 param
.direction
= ParameterDirection
.OUT
;
2527 } else if (direction
== "inout") {
2528 param
.direction
= ParameterDirection
.REF
;
2530 if (type is ArrayType
) {
2531 if (metadata
.has_argument (ArgumentType
.ARRAY_LENGTH_IDX
)) {
2532 array_length_idx
= metadata
.get_integer (ArgumentType
.ARRAY_LENGTH_IDX
);
2534 if (no_array_length
|| array_null_terminated
) {
2535 param
.set_attribute_bool ("CCode", "array_length", !no_array_length
);
2537 if (array_null_terminated
) {
2538 param
.set_attribute_bool ("CCode", "array_null_terminated", array_null_terminated
);
2542 param
.initializer
= metadata
.get_expression (ArgumentType
.DEFAULT
);
2544 // empty tuple used for parameters without initializer
2545 if (param
.initializer is Tuple
) {
2546 param
.initializer
= null;
2549 end_element (element_type
);
2553 DataType
parse_type (out string? ctype
= null, out int array_length_idx
= null, bool transfer_elements
= true, out bool no_array_length
= null, out bool array_null_terminated
= null) {
2554 bool is_array
= false;
2555 string type_name
= reader
.get_attribute ("name");
2558 var fixed_length
= -1;
2559 array_length_idx
= -1;
2560 no_array_length
= true;
2561 array_null_terminated
= true;
2563 if (reader
.name
== "array") {
2565 start_element ("array");
2567 var src
= get_current_src ();
2569 if (type_name
== null) {
2570 if (reader
.get_attribute ("length") != null) {
2571 array_length_idx
= int.parse (reader
.get_attribute ("length"));
2572 no_array_length
= false;
2573 array_null_terminated
= false;
2575 if (reader
.get_attribute ("fixed-size") != null) {
2576 fixed_length
= int.parse (reader
.get_attribute ("fixed-size"));
2577 array_null_terminated
= false;
2579 if (reader
.get_attribute ("c:type") == "GStrv") {
2580 no_array_length
= true;
2581 array_null_terminated
= true;
2583 if (reader
.get_attribute ("zero-terminated") != null) {
2584 array_null_terminated
= int.parse (reader
.get_attribute ("zero-terminated")) != 0;
2587 var element_type
= parse_type ();
2588 element_type
.value_owned
= transfer_elements
;
2589 end_element ("array");
2591 var array_type
= new
ArrayType (element_type
, 1, src
);
2592 if (fixed_length
> 0) {
2593 array_type
.fixed_length
= true;
2594 array_type
.length
= new
IntegerLiteral (fixed_length
.to_string ());
2598 } else if (reader
.name
== "callback"){
2600 return new
DelegateType ((Delegate
) old_current
.symbol
);
2602 start_element ("type");
2605 ctype
= reader
.get_attribute("c:type");
2609 if (type_name
== "GLib.PtrArray"
2610 && current_token
== MarkupTokenType
.START_ELEMENT
) {
2611 type_name
= "GLib.GenericArray";
2614 if (type_name
== null) {
2618 DataType type
= parse_type_from_gir_name (type_name
, out no_array_length
, out array_null_terminated
, ctype
);
2620 // type arguments / element types
2621 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2622 if (type_name
== "GLib.ByteArray") {
2626 var element_type
= parse_type ();
2627 element_type
.value_owned
= transfer_elements
;
2628 type
.add_type_argument (element_type
);
2630 if (element_type is UnresolvedType
) {
2631 Node parent
= current ?? root
;
2632 while (parent
!= root
&& parent
.parent
!= null && parent
.parent
!= root
) {
2633 parent
= parent
.parent
;
2635 unresolved_type_arguments
[(UnresolvedType
) element_type
] = parent
;
2639 end_element (is_array ?
"array" : "type");
2643 DataType
parse_type_from_gir_name (string type_name
, out bool no_array_length
= null, out bool array_null_terminated
= null, string? ctype
= null) {
2644 no_array_length
= false;
2645 array_null_terminated
= false;
2647 DataType? type
= null;
2648 if (type_name
== "none") {
2649 type
= new
VoidType (get_current_src ());
2650 } else if (type_name
== "gpointer") {
2651 type
= new
PointerType (new
VoidType (get_current_src ()), get_current_src ());
2652 } else if (type_name
== "GObject.Strv") {
2653 var element_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, "string"));
2654 element_type
.value_owned
= true;
2655 type
= new
ArrayType (element_type
, 1, get_current_src ());
2656 no_array_length
= true;
2657 array_null_terminated
= true;
2659 bool known_type
= true;
2660 if (type_name
== "utf8") {
2661 type_name
= "string";
2662 } else if (type_name
== "gboolean") {
2663 type
= new
BooleanType ((Struct
) context
.root
.scope
.lookup ("bool"));
2664 } else if (type_name
== "gchar") {
2666 } else if (type_name
== "gshort") {
2667 type_name
= "short";
2668 } else if (type_name
== "gushort") {
2669 type_name
= "ushort";
2670 } else if (type_name
== "gint") {
2672 } else if (type_name
== "guint") {
2674 } else if (type_name
== "glong") {
2675 if (ctype
!= null && ctype
.has_prefix ("gssize")) {
2676 type_name
= "ssize_t";
2677 } else if (ctype
!= null && ctype
.has_prefix ("gintptr")) {
2678 type_name
= "intptr";
2682 } else if (type_name
== "gulong") {
2683 if (ctype
!= null && ctype
.has_prefix ("gsize")) {
2684 type_name
= "size_t";
2685 } else if (ctype
!= null && ctype
.has_prefix ("guintptr")) {
2686 type_name
= "uintptr";
2688 type_name
= "ulong";
2690 } else if (type_name
== "gint8") {
2692 } else if (type_name
== "guint8") {
2693 type_name
= "uint8";
2694 } else if (type_name
== "gint16") {
2695 type_name
= "int16";
2696 } else if (type_name
== "guint16") {
2697 type_name
= "uint16";
2698 } else if (type_name
== "gint32") {
2699 type_name
= "int32";
2700 } else if (type_name
== "guint32") {
2701 type_name
= "uint32";
2702 } else if (type_name
== "gint64") {
2703 type_name
= "int64";
2704 } else if (type_name
== "guint64") {
2705 type_name
= "uint64";
2706 } else if (type_name
== "gfloat") {
2707 type_name
= "float";
2708 } else if (type_name
== "gdouble") {
2709 type_name
= "double";
2710 } else if (type_name
== "filename") {
2711 type_name
= "string";
2712 } else if (type_name
== "GLib.offset") {
2713 type_name
= "int64";
2714 } else if (type_name
== "gsize") {
2715 type_name
= "size_t";
2716 } else if (type_name
== "gssize") {
2717 type_name
= "ssize_t";
2718 } else if (type_name
== "guintptr") {
2719 type_name
= "uintptr";
2720 } else if (type_name
== "gintptr") {
2721 type_name
= "intptr";
2722 } else if (type_name
== "GType") {
2723 type_name
= "GLib.Type";
2724 } else if (type_name
== "GLib.String") {
2725 type_name
= "GLib.StringBuilder";
2726 } else if (type_name
== "GObject.Class") {
2727 type_name
= "GLib.ObjectClass";
2728 } else if (type_name
== "gunichar") {
2729 type_name
= "unichar";
2730 } else if (type_name
== "GLib.Data") {
2731 type_name
= "GLib.Datalist";
2732 } else if (type_name
== "Atk.ImplementorIface") {
2733 type_name
= "Atk.Implementor";
2739 var sym
= parse_symbol_from_string (type_name
, get_current_src ());
2740 type
= new UnresolvedType
.from_symbol (sym
, get_current_src ());
2742 unresolved_gir_symbols
.add (sym
);
2750 void parse_record () {
2751 start_element ("record");
2752 push_node (element_get_name (), true);
2755 if (current
.new_symbol
) {
2756 st
= new
Struct (element_get_name (), current
.source_reference
);
2757 current
.symbol
= st
;
2759 st
= (Struct
) current
.symbol
;
2762 set_type_id_ccode (st
);
2765 st
.access
= SymbolAccessibility
.PUBLIC
;
2767 var gtype_struct_for
= reader
.get_attribute ("glib:is-gtype-struct-for");
2768 if (gtype_struct_for
!= null) {
2769 current
.gtype_struct_for
= parse_symbol_from_string (gtype_struct_for
, current
.source_reference
);
2770 unresolved_gir_symbols
.add (current
.gtype_struct_for
);
2773 bool first_field
= true;
2776 st
.comment
= parse_symbol_doc ();
2778 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2779 if (!push_metadata ()) {
2780 if (first_field
&& reader
.name
== "field") {
2781 first_field
= false;
2787 if (reader
.name
== "field") {
2788 if (reader
.get_attribute ("name") != "priv" && !(first_field
&& gtype_struct_for
!= null)) {
2793 first_field
= false;
2794 } else if (reader
.name
== "constructor") {
2795 parse_constructor ();
2796 } else if (reader
.name
== "method") {
2797 parse_method ("method");
2798 } else if (reader
.name
== "function") {
2800 } else if (reader
.name
== "union") {
2804 Report
.error (get_current_src (), "unknown child element `%s' in `record'".printf (reader
.name
));
2812 end_element ("record");
2815 void parse_class () {
2816 start_element ("class");
2817 push_node (element_get_name (), true);
2820 var parent
= reader
.get_attribute ("parent");
2821 if (current
.new_symbol
) {
2822 cl
= new
Class (current
.name
, current
.source_reference
);
2823 cl
.is_abstract
= metadata
.get_bool (ArgumentType
.ABSTRACT
, reader
.get_attribute ("abstract") == "1");
2825 if (parent
!= null) {
2826 cl
.add_base_type (parse_type_from_gir_name (parent
));
2828 current
.symbol
= cl
;
2830 cl
= (Class
) current
.symbol
;
2833 set_type_id_ccode (cl
);
2835 cl
.access
= SymbolAccessibility
.PUBLIC
;
2840 cl
.comment
= parse_symbol_doc ();
2842 var first_field
= true;
2843 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2844 if (!push_metadata ()) {
2845 if (first_field
&& reader
.name
== "field") {
2846 first_field
= false;
2852 if (reader
.name
== "implements") {
2853 start_element ("implements");
2854 cl
.add_base_type (parse_type_from_gir_name (reader
.get_attribute ("name")));
2856 end_element ("implements");
2857 } else if (reader
.name
== "constant") {
2859 } else if (reader
.name
== "field") {
2860 if (first_field
&& parent
!= null) {
2861 // first field is guaranteed to be the parent instance
2864 if (reader
.get_attribute ("name") != "priv") {
2870 first_field
= false;
2871 } else if (reader
.name
== "property") {
2873 } else if (reader
.name
== "constructor") {
2874 parse_constructor ();
2875 } else if (reader
.name
== "function") {
2876 parse_method ("function");
2877 } else if (reader
.name
== "method") {
2878 parse_method ("method");
2879 } else if (reader
.name
== "virtual-method") {
2880 parse_method ("virtual-method");
2881 } else if (reader
.name
== "union") {
2883 } else if (reader
.name
== "glib:signal") {
2887 Report
.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader
.name
));
2895 end_element ("class");
2898 void parse_interface () {
2899 start_element ("interface");
2900 push_node (element_get_name (), true);
2903 if (current
.new_symbol
) {
2904 iface
= new
Interface (current
.name
, current
.source_reference
);
2905 current
.symbol
= iface
;
2907 iface
= (Interface
) current
.symbol
;
2910 set_type_id_ccode (iface
);
2912 iface
.access
= SymbolAccessibility
.PUBLIC
;
2913 iface
.external
= true;
2918 iface
.comment
= parse_symbol_doc ();
2920 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2921 if (!push_metadata ()) {
2926 if (reader
.name
== "prerequisite") {
2927 start_element ("prerequisite");
2928 iface
.add_prerequisite (parse_type_from_gir_name (reader
.get_attribute ("name")));
2930 end_element ("prerequisite");
2931 } else if (reader
.name
== "field") {
2933 } else if (reader
.name
== "property") {
2935 } else if (reader
.name
== "virtual-method") {
2936 parse_method ("virtual-method");
2937 } else if (reader
.name
== "function") {
2938 parse_method ("function");
2939 } else if (reader
.name
== "method") {
2940 parse_method ("method");
2941 } else if (reader
.name
== "glib:signal") {
2945 Report
.error (get_current_src (), "unknown child element `%s' in `interface'".printf (reader
.name
));
2953 end_element ("interface");
2956 void parse_field () {
2957 start_element ("field");
2958 push_node (element_get_name (), false);
2960 string nullable
= reader
.get_attribute ("nullable");
2961 string allow_none
= reader
.get_attribute ("allow-none");
2964 var comment
= parse_symbol_doc ();
2966 bool no_array_length
;
2967 bool array_null_terminated
;
2968 int array_length_idx
;
2969 var type
= parse_type (null, out array_length_idx
, true, out no_array_length
, out array_null_terminated
);
2970 type
= element_get_type (type
, true, ref no_array_length
, ref array_null_terminated
);
2972 string name
= current
.name
;
2973 string cname
= current
.girdata
["name"];
2975 var field
= new
Field (name
, type
, null, current
.source_reference
);
2976 field
.access
= SymbolAccessibility
.PUBLIC
;
2977 field
.comment
= comment
;
2978 if (name
!= cname
) {
2979 field
.set_attribute_string ("CCode", "cname", cname
);
2981 if (type is ArrayType
) {
2982 if (!no_array_length
&& array_length_idx
> -1) {
2983 current
.array_length_idx
= array_length_idx
;
2985 if (no_array_length
|| array_null_terminated
) {
2986 field
.set_attribute_bool ("CCode", "array_length", !no_array_length
);
2988 if (array_null_terminated
) {
2989 field
.set_attribute_bool ("CCode", "array_null_terminated", true);
2992 if (nullable
== "1" || allow_none
== "1") {
2993 type
.nullable
= true;
2995 current
.symbol
= field
;
2998 end_element ("field");
3001 Property
parse_property () {
3002 start_element ("property");
3003 push_node (element_get_name().replace ("-", "_"), false);
3004 bool is_abstract
= metadata
.get_bool (ArgumentType
.ABSTRACT
, current
.parent
.symbol is Interface
);
3005 string transfer
= reader
.get_attribute ("transfer-ownership");
3009 var comment
= parse_symbol_doc ();
3011 bool no_array_length
;
3012 bool array_null_terminated
;
3013 var type
= parse_type (null, null, transfer
!= "container", out no_array_length
, out array_null_terminated
);
3014 type
= element_get_type (type
, true, ref no_array_length
, ref array_null_terminated
);
3015 var prop
= new
Property (current
.name
, type
, null, null, current
.source_reference
);
3016 prop
.comment
= comment
;
3017 prop
.access
= SymbolAccessibility
.PUBLIC
;
3018 prop
.external
= true;
3019 prop
.is_abstract
= is_abstract
;
3020 if (no_array_length
|| array_null_terminated
) {
3021 prop
.set_attribute_bool ("CCode", "array_length", !no_array_length
);
3023 if (array_null_terminated
) {
3024 prop
.set_attribute_bool ("CCode", "array_null_terminated", true);
3026 current
.symbol
= prop
;
3029 end_element ("property");
3033 void parse_callback () {
3034 parse_function ("callback");
3037 void parse_constructor () {
3038 parse_function ("constructor");
3041 class ParameterInfo
{
3042 public ParameterInfo (Parameter param
, int array_length_idx
, int closure_idx
, int destroy_idx
, bool is_async
= false) {
3044 this
.array_length_idx
= array_length_idx
;
3045 this
.closure_idx
= closure_idx
;
3046 this
.destroy_idx
= destroy_idx
;
3047 this
.vala_idx
= 0.0F
;
3049 this
.is_async
= is_async
;
3052 public Parameter param
;
3053 public float vala_idx
;
3054 public int array_length_idx
;
3055 public int closure_idx
;
3056 public int destroy_idx
;
3058 public bool is_async
;
3061 void parse_function (string element_name
) {
3062 start_element (element_name
);
3063 push_node (element_get_name (reader
.get_attribute ("invoker")).replace ("-", "_"), false);
3066 if (metadata
.has_argument (ArgumentType
.SYMBOL_TYPE
)) {
3067 symbol_type
= metadata
.get_string (ArgumentType
.SYMBOL_TYPE
);
3069 symbol_type
= element_name
;
3072 string name
= current
.name
;
3073 string throws_string
= reader
.get_attribute ("throws");
3074 string invoker
= reader
.get_attribute ("invoker");
3078 var comment
= parse_symbol_doc ();
3080 DataType return_type
;
3081 string return_ctype
= null;
3082 int return_array_length_idx
= -1;
3083 bool return_no_array_length
= false;
3084 bool return_array_null_terminated
= false;
3085 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "return-value") {
3086 Comment? return_comment
;
3087 return_type
= parse_return_value (out return_ctype
, out return_array_length_idx
, out return_no_array_length
, out return_array_null_terminated
, out return_comment
);
3088 if (return_comment
!= null) {
3089 if (comment
== null) {
3090 comment
= new
GirComment (null, current
.source_reference
);
3092 comment
.return_content
= return_comment
;
3095 return_type
= new
VoidType ();
3100 if (symbol_type
== "callback") {
3101 s
= new
Delegate (name
, return_type
, current
.source_reference
);
3102 ((Delegate
) s
).has_target
= false;
3103 } else if (symbol_type
== "constructor") {
3104 if (name
== "new") {
3106 } else if (name
.has_prefix ("new_")) {
3107 name
= name
.substring ("new_".length
);
3109 var m
= new
CreationMethod (null, name
, current
.source_reference
);
3110 m
.has_construct_function
= false;
3112 if (name
!= null && !current
.name
.has_prefix ("new_")) {
3113 m
.set_attribute_string ("CCode", "cname", current
.girdata
["c:identifier"]);
3116 string parent_ctype
= null;
3117 if (current
.parent
.symbol is Class
) {
3118 parent_ctype
= current
.parent
.get_cname ();
3120 if (return_ctype
!= null && (parent_ctype
== null || return_ctype
!= parent_ctype
+ "*")) {
3121 m
.set_attribute_string ("CCode", "type", return_ctype
);
3124 } else if (symbol_type
== "glib:signal") {
3125 s
= new
Signal (name
, return_type
, current
.source_reference
);
3127 s
= new
Method (name
, return_type
, current
.source_reference
);
3130 s
.access
= SymbolAccessibility
.PUBLIC
;
3131 s
.comment
= comment
;
3134 // Transform fixed-array properties of return-type into ccode-attribute
3135 var array_type
= return_type as ArrayType
;
3136 if (array_type
!= null && array_type
.fixed_length
) {
3137 s
.set_attribute_string ("CCode", "array_length_cexpr", ((IntegerLiteral
) array_type
.length
).value
);
3138 array_type
.fixed_length
= false;
3139 array_type
.length
= null;
3143 if (current
.girdata
["name"] != name
.replace ("_", "-")) {
3144 s
.set_attribute_string ("CCode", "cname", current
.girdata
["name"]);
3150 if (symbol_type
== "virtual-method" || symbol_type
== "callback") {
3151 if (current
.parent
.symbol is Interface
) {
3152 m
.is_abstract
= true;
3154 m
.is_virtual
= true;
3156 if (invoker
== null && !metadata
.has_argument (ArgumentType
.VFUNC_NAME
)) {
3157 s
.set_attribute ("NoWrapper", true, s
.source_reference
);
3158 } if (current
.girdata
["name"] != name
) {
3159 m
.set_attribute_string ("CCode", "vfunc_name", current
.girdata
["name"]);
3161 } else if (symbol_type
== "function") {
3162 m
.binding
= MemberBinding
.STATIC
;
3164 if (metadata
.has_argument (ArgumentType
.FLOATING
)) {
3165 m
.returns_floating_reference
= metadata
.get_bool (ArgumentType
.FLOATING
);
3166 m
.return_type
.value_owned
= true;
3170 if (s is Method
&& !(s is CreationMethod
)) {
3171 var method
= (Method
) s
;
3172 if (metadata
.has_argument (ArgumentType
.VIRTUAL
)) {
3173 method
.is_virtual
= metadata
.get_bool (ArgumentType
.VIRTUAL
);
3174 method
.is_abstract
= false;
3175 } else if (metadata
.has_argument (ArgumentType
.ABSTRACT
)) {
3176 method
.is_abstract
= metadata
.get_bool (ArgumentType
.ABSTRACT
);
3177 method
.is_virtual
= false;
3179 if (metadata
.has_argument (ArgumentType
.VFUNC_NAME
)) {
3180 method
.set_attribute_string ("CCode", "vfunc_name", metadata
.get_string (ArgumentType
.VFUNC_NAME
));
3181 method
.is_virtual
= true;
3183 if (metadata
.has_argument (ArgumentType
.FINISH_VFUNC_NAME
)) {
3184 method
.set_attribute_string ("CCode", "finish_vfunc_name", metadata
.get_string (ArgumentType
.FINISH_VFUNC_NAME
));
3185 method
.is_virtual
= true;
3189 if (!(metadata
.get_expression (ArgumentType
.THROWS
) is NullLiteral
)) {
3190 if (metadata
.has_argument (ArgumentType
.THROWS
)) {
3191 var error_types
= metadata
.get_string(ArgumentType
.THROWS
).split(",");
3192 foreach (var error_type
in error_types
) {
3193 s
.add_error_type (parse_type_from_string (error_type
, true, metadata
.get_source_reference (ArgumentType
.THROWS
)));
3195 } else if (throws_string
== "1") {
3196 s
.add_error_type (new
ErrorType (null, null));
3202 m
.set_attribute ("PrintfFormat", metadata
.get_bool (ArgumentType
.PRINTF_FORMAT
));
3203 if (metadata
.has_argument (ArgumentType
.SENTINEL
)) {
3204 m
.set_attribute_string ("CCode", "sentinel", metadata
.get_string (ArgumentType
.SENTINEL
));
3208 if (return_type is ArrayType
&& metadata
.has_argument (ArgumentType
.ARRAY_LENGTH_IDX
)) {
3209 return_array_length_idx
= metadata
.get_integer (ArgumentType
.ARRAY_LENGTH_IDX
);
3211 if (return_no_array_length
|| return_array_null_terminated
) {
3212 s
.set_attribute_bool ("CCode", "array_length", !return_no_array_length
);
3214 if (return_array_null_terminated
) {
3215 s
.set_attribute_bool ("CCode", "array_null_terminated", true);
3218 current
.return_array_length_idx
= return_array_length_idx
;
3222 if (metadata
.has_argument (ArgumentType
.FINISH_NAME
)) {
3223 s
.set_attribute_string ("CCode", "finish_name", metadata
.get_string (ArgumentType
.FINISH_NAME
));
3225 if (metadata
.has_argument (ArgumentType
.FINISH_INSTANCE
)) {
3226 s
.set_attribute_bool ("CCode", "finish_instance", metadata
.get_bool (ArgumentType
.FINISH_INSTANCE
));
3229 int instance_idx
= -2;
3230 if (element_name
== "function" && symbol_type
== "method") {
3231 if (metadata
.has_argument (ArgumentType
.INSTANCE_IDX
)) {
3232 instance_idx
= metadata
.get_integer (ArgumentType
.INSTANCE_IDX
);
3233 if (instance_idx
!= 0) {
3234 s
.set_attribute_double ("CCode", "instance_pos", instance_idx
+ 0.5);
3237 Report
.error (get_current_src (), "instance_idx required when converting function to method");
3241 var parameters
= new ArrayList
<ParameterInfo
> ();
3242 current
.array_length_parameters
= new ArrayList
<int> ();
3243 current
.closure_parameters
= new ArrayList
<int> ();
3244 current
.destroy_parameters
= new ArrayList
<int> ();
3245 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "parameters") {
3246 start_element ("parameters");
3249 var current_parameter_idx
= -1;
3250 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
3251 current_parameter_idx
++;
3253 if (reader
.name
== "instance-parameter" &&
3254 !(symbol_type
== "function" || symbol_type
== "constructor")) {
3259 if (instance_idx
> -2 && instance_idx
== current_parameter_idx
) {
3264 if (!push_metadata ()) {
3269 int array_length_idx
, closure_idx
, destroy_idx
;
3271 string default_param_name
= null;
3272 Comment? param_comment
;
3273 default_param_name
= "arg%d".printf (parameters
.size
);
3274 var param
= parse_parameter (out array_length_idx
, out closure_idx
, out destroy_idx
, out scope
, out param_comment
, default_param_name
);
3275 if (array_length_idx
!= -1) {
3276 if (instance_idx
> -2 && instance_idx
< array_length_idx
) {
3279 current
.array_length_parameters
.add (array_length_idx
);
3281 if (closure_idx
!= -1) {
3282 if (instance_idx
> -2 && instance_idx
< closure_idx
) {
3285 if (current
.closure_parameters
.index_of (current_parameter_idx
) < 0) {
3286 current
.closure_parameters
.add (closure_idx
);
3289 if (destroy_idx
!= -1) {
3290 if (instance_idx
> -2 && instance_idx
< destroy_idx
) {
3293 if (current
.destroy_parameters
.index_of (current_parameter_idx
) < 0) {
3294 current
.destroy_parameters
.add (destroy_idx
);
3297 if (param_comment
!= null) {
3298 if (comment
== null) {
3299 comment
= new
GirComment (null, s
.source_reference
);
3300 s
.comment
= comment
;
3303 comment
.add_content_for_parameter ((param
.ellipsis
)?
"..." : param
.name
, param_comment
);
3306 var info
= new
ParameterInfo (param
, array_length_idx
, closure_idx
, destroy_idx
, scope
== "async");
3308 if (s is Method
&& scope
== "async") {
3309 var unresolved_type
= param
.variable_type as UnresolvedType
;
3310 if (unresolved_type
!= null && unresolved_type
.unresolved_symbol
.name
== "AsyncReadyCallback") {
3311 // GAsync-style method
3312 ((Method
) s
).coroutine
= true;
3317 parameters
.add (info
);
3320 end_element ("parameters");
3322 current
.parameters
= parameters
;
3324 for (int param_n
= parameters
.size
- 1 ; param_n
>= 0 ; param_n
--) {
3325 ParameterInfo pi
= parameters
[param_n
];
3326 if (!pi
.param
.ellipsis
&& pi
.param
.initializer
== null) {
3327 string type_string
= pi
.param
.variable_type
.to_string ();
3328 if (type_string
== "Gio.Cancellable?") {
3329 pi
.param
.initializer
= new Vala
.NullLiteral ();
3337 end_element (element_name
);
3340 void parse_method (string element_name
) {
3341 parse_function (element_name
);
3344 void parse_signal () {
3345 parse_function ("glib:signal");
3348 void parse_boxed (string element_name
) {
3349 start_element (element_name
);
3350 string name
= reader
.get_attribute ("name");
3352 name
= reader
.get_attribute ("glib:name");
3354 push_node (element_get_name (name
), true);
3357 bool require_copy_free
= false;
3358 if (current
.new_symbol
) {
3359 cl
= new
Class (current
.name
, current
.source_reference
);
3360 cl
.is_compact
= true;
3361 current
.symbol
= cl
;
3363 cl
= (Class
) current
.symbol
;
3366 set_type_id_ccode (cl
);
3367 require_copy_free
= cl
.has_attribute_argument ("CCode", "type_id");
3369 cl
.access
= SymbolAccessibility
.PUBLIC
;
3372 if (metadata
.has_argument (ArgumentType
.BASE_TYPE
)) {
3373 cl
.add_base_type (parse_type_from_string (metadata
.get_string (ArgumentType
.BASE_TYPE
), true, metadata
.get_source_reference (ArgumentType
.BASE_TYPE
)));
3378 cl
.comment
= parse_symbol_doc ();
3380 Node? ref_method
= null;
3381 Node? unref_method
= null;
3383 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
3384 if (!push_metadata ()) {
3389 if (reader
.name
== "field") {
3391 } else if (reader
.name
== "constructor") {
3392 parse_constructor ();
3393 } else if (reader
.name
== "method") {
3394 parse_method ("method");
3395 var cname
= old_current
.get_cname ();
3396 if (cname
.has_suffix ("_ref") && (ref_method
== null || old_current
.name
== "ref")) {
3397 ref_method
= old_current
;
3398 } else if (cname
.has_suffix ("_unref") && (unref_method
== null || old_current
.name
== "unref")) {
3399 unref_method
= old_current
;
3401 } else if (reader
.name
== "function") {
3403 } else if (reader
.name
== "union") {
3407 Report
.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader
.name
));
3414 // Add ccode-attributes for ref/unref methodes if available
3415 // otherwise fallback to default g_boxed_copy/free
3416 if (cl
.has_attribute_argument ("CCode", "ref_function") || cl
.has_attribute_argument ("CCode", "unref_function")
3417 || cl
.has_attribute_argument ("CCode", "copy_function") || cl
.has_attribute_argument ("CCode", "free_function")) {
3419 } else if (ref_method
!= null && unref_method
!= null) {
3420 cl
.set_attribute_string ("CCode", "ref_function", ref_method
.get_cname ());
3421 cl
.set_attribute_string ("CCode", "unref_function", unref_method
.get_cname ());
3422 } else if (require_copy_free
) {
3423 cl
.set_attribute_string ("CCode", "copy_function", "g_boxed_copy");
3424 cl
.set_attribute_string ("CCode", "free_function", "g_boxed_free");
3428 end_element (element_name
);
3431 void parse_union () {
3432 start_element ("union");
3434 string? element_name
= element_get_name ();
3435 if (element_name
== null) {
3438 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
3439 if (!push_metadata ()) {
3444 if (reader
.name
== "field") {
3448 Report
.error (get_current_src (), "unknown child element `%s' in `transparent union'".printf (reader
.name
));
3455 end_element ("union");
3459 push_node (element_name
, true);
3462 if (current
.new_symbol
) {
3463 st
= new
Struct (reader
.get_attribute ("name"), current
.source_reference
);
3464 current
.symbol
= st
;
3466 st
= (Struct
) current
.symbol
;
3468 st
.access
= SymbolAccessibility
.PUBLIC
;
3473 st
.comment
= parse_symbol_doc ();
3475 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
3476 if (!push_metadata ()) {
3481 if (reader
.name
== "field") {
3483 } else if (reader
.name
== "constructor") {
3484 parse_constructor ();
3485 } else if (reader
.name
== "method") {
3486 parse_method ("method");
3487 } else if (reader
.name
== "function") {
3489 } else if (reader
.name
== "record") {
3493 Report
.error (get_current_src (), "unknown child element `%s' in `union'".printf (reader
.name
));
3501 end_element ("union");
3504 void parse_constant () {
3505 start_element ("constant");
3506 push_node (element_get_name (), false);
3510 var comment
= parse_symbol_doc ();
3512 bool no_array_length
;
3513 bool array_null_terminated
;
3514 int array_length_idx
;
3515 var type
= parse_type (null, out array_length_idx
, true, out no_array_length
, out array_null_terminated
);
3516 type
= element_get_type (type
, true, ref no_array_length
, ref array_null_terminated
);
3517 var c
= new
Constant (current
.name
, type
, null, current
.source_reference
);
3519 c
.access
= SymbolAccessibility
.PUBLIC
;
3520 c
.comment
= comment
;
3522 if (no_array_length
|| array_null_terminated
) {
3523 c
.set_attribute_bool ("CCode", "array_length", !no_array_length
);
3525 if (array_null_terminated
) {
3526 c
.set_attribute_bool ("CCode", "array_null_terminated", true);
3530 end_element ("constant");
3534 void report_unused_metadata (Metadata metadata
) {
3535 if (metadata
== Metadata
.empty
) {
3539 if (metadata
.args
.size
== 0 && metadata
.children
.size
== 0) {
3540 Report
.warning (metadata
.source_reference
, "empty metadata");
3544 foreach (var arg_type
in metadata
.args
.get_keys ()) {
3545 var arg
= metadata
.args
[arg_type
];
3547 // if metadata is used and argument is not, then it's a unexpected argument
3548 Report
.warning (arg
.source_reference
, "argument never used");
3552 foreach (var child
in metadata
.children
) {
3554 Report
.warning (child
.source_reference
, "metadata never used");
3556 report_unused_metadata (child
);
3563 void resolve_gir_symbols () {
3564 // gir has simple namespaces, we won't get deeper than 2 levels here, except reparenting
3565 foreach (var map_from
in unresolved_gir_symbols
) {
3566 while (map_from
!= null) {
3567 var map_to
= unresolved_symbols_map
[map_from
];
3568 if (map_to
!= null) {
3569 // remap the original symbol to match the target
3570 map_from
.inner
= null;
3571 map_from
.name
= map_to
.name
;
3572 if (map_to is UnresolvedSymbol
) {
3573 var umap_to
= (UnresolvedSymbol
) map_to
;
3574 while (umap_to
.inner
!= null) {
3575 umap_to
= umap_to
.inner
;
3576 map_from
.inner
= new
UnresolvedSymbol (null, umap_to
.name
);
3577 map_from
= map_from
.inner
;
3580 while (map_to
.parent_symbol
!= null && map_to
.parent_symbol
!= context
.root
) {
3581 map_to
= map_to
.parent_symbol
;
3582 map_from
.inner
= new
UnresolvedSymbol (null, map_to
.name
);
3583 map_from
= map_from
.inner
;
3588 map_from
= map_from
.inner
;
3593 void create_new_namespaces () {
3594 foreach (var node
in Node
.new_namespaces
) {
3595 if (node
.symbol
== null) {
3596 node
.symbol
= new
Namespace (node
.name
, node
.source_reference
);
3601 void resolve_type_arguments () {
3602 var it
= unresolved_type_arguments
.map_iterator ();
3603 while (it
.next ()) {
3604 var element_type
= it
.get_key ();
3605 var parent
= it
.get_value ();
3606 var sym
= (TypeSymbol
) resolve_symbol (parent
, element_type
.unresolved_symbol
);
3608 // box structs in type arguments
3609 var st
= sym as Struct
;
3610 if (st
!= null && !st
.is_integer_type () && !st
.is_floating_type ()) {
3611 element_type
.nullable
= true;
3616 void process_interface (Node iface_node
) {
3617 /* Temporarily workaround G-I bug not adding GLib.Object prerequisite:
3618 ensure we have at least one instantiable prerequisite */
3619 Interface iface
= (Interface
) iface_node
.symbol
;
3620 bool has_instantiable_prereq
= false;
3621 foreach (DataType prereq
in iface
.get_prerequisites ()) {
3623 if (prereq is UnresolvedType
) {
3624 var unresolved_symbol
= ((UnresolvedType
) prereq
).unresolved_symbol
;
3625 sym
= resolve_symbol (iface_node
.parent
, unresolved_symbol
);
3627 sym
= prereq
.data_type
;
3630 has_instantiable_prereq
= true;
3635 if (!has_instantiable_prereq
) {
3636 iface
.add_prerequisite (new
ObjectType ((ObjectTypeSymbol
) glib_ns
.scope
.lookup ("Object")));
3640 void process_alias (Node alias
) {
3641 /* this is unfortunate because <alias> tag has no type information, thus we have
3642 to guess it from the base type */
3643 DataType base_type
= null;
3644 Symbol type_sym
= null;
3645 Node base_node
= null;
3646 bool simple_type
= false;
3647 if (alias
.base_type is UnresolvedType
) {
3648 base_type
= alias
.base_type
;
3649 base_node
= resolve_node (alias
.parent
, ((UnresolvedType
) base_type
).unresolved_symbol
);
3650 if (base_node
!= null) {
3651 type_sym
= base_node
.symbol
;
3653 } else if (alias
.base_type is PointerType
&& ((PointerType
) alias
.base_type
).base_type is VoidType
) {
3654 // gpointer, if it's a struct make it a simpletype
3657 base_type
= alias
.base_type
;
3658 type_sym
= base_type
.data_type
;
3659 if (type_sym
!= null) {
3660 base_node
= resolve_node (alias
.parent
, parse_symbol_from_string (type_sym
.get_full_name (), alias
.source_reference
));
3664 if (type_sym is Struct
&& ((Struct
) type_sym
).is_simple_type ()) {
3668 if (base_type
== null || type_sym
== null || type_sym is Struct
) {
3669 var st
= new
Struct (alias
.name
, alias
.source_reference
);
3670 st
.access
= SymbolAccessibility
.PUBLIC
;
3671 if (base_type
!= null) {
3672 // threat target="none" as a new struct
3673 st
.base_type
= base_type
;
3675 st
.comment
= alias
.comment
;
3677 st
.set_simple_type (simple_type
);
3679 } else if (type_sym is Class
) {
3680 var cl
= new
Class (alias
.name
, alias
.source_reference
);
3681 cl
.access
= SymbolAccessibility
.PUBLIC
;
3682 if (base_type
!= null) {
3683 cl
.add_base_type (base_type
);
3685 cl
.comment
= alias
.comment
;
3687 cl
.is_compact
= ((Class
) type_sym
).is_compact
;
3689 } else if (type_sym is Interface
) {
3690 // this is not a correct alias, but what can we do otherwise?
3691 var iface
= new
Interface (alias
.name
, alias
.source_reference
);
3692 iface
.access
= SymbolAccessibility
.PUBLIC
;
3693 if (base_type
!= null) {
3694 iface
.add_prerequisite (base_type
);
3696 iface
.comment
= alias
.comment
;
3697 iface
.external
= true;
3698 alias
.symbol
= iface
;
3699 } else if (type_sym is Delegate
) {
3700 var orig
= (Delegate
) type_sym
;
3701 if (base_node
!= null) {
3702 base_node
.process (this
);
3703 orig
= (Delegate
) base_node
.symbol
;
3706 var deleg
= new
Delegate (alias
.name
, orig
.return_type
.copy (), alias
.source_reference
);
3707 deleg
.access
= orig
.access
;
3709 foreach (var param
in orig
.get_parameters ()) {
3710 deleg
.add_parameter (param
.copy ());
3713 foreach (var error_type
in orig
.get_error_types ()) {
3714 deleg
.add_error_type (error_type
.copy ());
3717 foreach (var attribute
in orig
.attributes
) {
3718 deleg
.attributes
.append (attribute
);
3721 deleg
.external
= true;
3723 alias
.symbol
= deleg
;
3724 } else if (type_sym
!= null) {
3725 Report
.warning (alias
.source_reference
, "alias `%s' for `%s' is not supported".printf (alias
.get_full_name (), type_sym
.get_full_name ()));
3726 alias
.symbol
= type_sym
;
3727 alias
.merged
= true;
3730 // inherit atributes, like type_id
3731 if (type_sym is Class
|| (type_sym is Struct
&& !simple_type
)) {
3732 if (type_sym
.has_attribute_argument ("CCode", "has_type_id")) {
3733 alias
.symbol
.set_attribute_bool ("CCode", "has_type_id", type_sym
.get_attribute_bool ("CCode", "has_type_id"));
3734 } else if (type_sym
.has_attribute_argument ("CCode", "type_id")) {
3735 alias
.symbol
.set_attribute_string ("CCode", "type_id", type_sym
.get_attribute_string ("CCode", "type_id"));
3740 void process_callable (Node node
) {
3741 if (node
.element_type
== "alias" && node
.symbol is Delegate
) {
3742 // processed in parse_alias
3746 var s
= node
.symbol
;
3747 List
<ParameterInfo
> parameters
= node
.parameters
;
3749 DataType return_type
= null;
3750 if (s is Callable
) {
3751 return_type
= ((Callable
) s
).return_type
;
3754 if (return_type is ArrayType
&& node
.return_array_length_idx
>= 0) {
3755 if (node
.return_array_length_idx
>= parameters
.size
) {
3756 Report
.error (return_type
.source_reference
, "invalid array length index");
3758 parameters
[node
.return_array_length_idx
].keep
= false;
3759 node
.array_length_parameters
.add (node
.return_array_length_idx
);
3761 } else if (return_type is VoidType
&& parameters
.size
> 0) {
3762 int n_out_parameters
= 0;
3763 foreach (var info
in parameters
) {
3764 if (info
.param
.direction
== ParameterDirection
.OUT
) {
3769 if (n_out_parameters
== 1) {
3770 ParameterInfo last_param
= parameters
[parameters
.size
-1];
3771 if (last_param
.param
.direction
== ParameterDirection
.OUT
) {
3772 // use last out real-non-null-struct parameter as return type
3773 if (last_param
.param
.variable_type is UnresolvedType
) {
3774 var st
= resolve_symbol (node
.parent
, ((UnresolvedType
) last_param
.param
.variable_type
).unresolved_symbol
) as Struct
;
3775 if (st
!= null && !st
.is_simple_type () && !last_param
.param
.variable_type
.nullable
) {
3776 if (!node
.metadata
.get_bool (ArgumentType
.RETURN_VOID
, false)) {
3777 last_param
.keep
= false;
3778 return_type
= last_param
.param
.variable_type
.copy ();
3785 if (return_type is UnresolvedType
&& !return_type
.nullable
) {
3786 var st
= resolve_symbol (node
.parent
, ((UnresolvedType
) return_type
).unresolved_symbol
) as Struct
;
3788 bool is_simple_type
= false;
3789 Struct? base_st
= st
;
3791 while (base_st
!= null) {
3792 if (base_st
.is_simple_type ()) {
3793 is_simple_type
= true;
3797 if (base_st
.base_type is UnresolvedType
) {
3798 base_st
= resolve_symbol (node
.parent
, ((UnresolvedType
) base_st
.base_type
).unresolved_symbol
) as Struct
;
3800 base_st
= base_st
.base_struct
;
3804 if (!is_simple_type
) {
3805 return_type
.nullable
= true;
3811 // Do not mark out-parameters as nullable if they are simple-types,
3812 // since it would result in a boxed-type in vala
3813 foreach (ParameterInfo info
in parameters
) {
3814 var type
= info
.param
.variable_type
;
3815 if (info
.param
.direction
== ParameterDirection
.OUT
&& type
.nullable
) {
3817 if (type is UnresolvedType
) {
3818 st
= resolve_symbol (node
.parent
, ((UnresolvedType
) type
).unresolved_symbol
) as Struct
;
3819 } else if (type is ValueType
) {
3820 st
= type
.data_type as Struct
;
3822 if (st
!= null && st
.is_simple_type ()) {
3823 type
.nullable
= false;
3828 if (parameters
.size
> 1) {
3829 ParameterInfo last_param
= parameters
[parameters
.size
-1];
3830 if (last_param
.param
.ellipsis
) {
3831 var first_vararg_param
= parameters
[parameters
.size
-2];
3832 if (first_vararg_param
.param
.name
.has_prefix ("first_")) {
3833 first_vararg_param
.keep
= false;
3841 foreach (ParameterInfo info
in parameters
) {
3842 if (s is Delegate
&& info
.closure_idx
== i
) {
3843 var d
= (Delegate
) s
;
3844 d
.has_target
= true;
3845 d
.set_attribute_double ("CCode", "instance_pos", j
- 0.1);
3847 } else if (info
.keep
3848 && !node
.array_length_parameters
.contains (i
)
3849 && !node
.closure_parameters
.contains (i
)
3850 && !node
.destroy_parameters
.contains (i
)) {
3851 info
.vala_idx
= (float) j
;
3854 /* interpolate for vala_idx between this and last*/
3855 float last_idx
= 0.0F
;
3857 last_idx
= parameters
[last
].vala_idx
;
3859 for (int k
=last
+1; k
< i
; k
++) {
3860 parameters
[k
].vala_idx
= last_idx
+ (((j
- last_idx
) / (i
-last
)) * (k
-last
));
3866 // make sure that vala_idx is always set
3867 // the above if branch does not set vala_idx for
3868 // hidden parameters at the end of the parameter list
3869 info
.vala_idx
= (j
- 1) + (i
- last
) * 0.1F
;
3874 foreach (ParameterInfo info
in parameters
) {
3879 /* add_parameter sets carray_length_parameter_position and cdelegate_target_parameter_position
3881 if (s is Callable
) {
3882 ((Callable
) s
).add_parameter (info
.param
);
3885 if (info
.array_length_idx
!= -1) {
3886 if ((info
.array_length_idx
) >= parameters
.size
) {
3887 Report
.error (info
.param
.source_reference
, "invalid array_length index");
3890 set_array_ccode (info
.param
, parameters
[info
.array_length_idx
]);
3893 if (info
.closure_idx
!= -1) {
3894 if ((info
.closure_idx
) >= parameters
.size
) {
3895 Report
.error (info
.param
.source_reference
, "invalid closure index");
3898 if ("%g".printf (parameters
[info
.closure_idx
].vala_idx
) != "%g".printf (info
.vala_idx
+ 0.1)) {
3899 info
.param
.set_attribute_double ("CCode", "delegate_target_pos", parameters
[info
.closure_idx
].vala_idx
);
3902 if (info
.destroy_idx
!= -1) {
3903 if (info
.destroy_idx
>= parameters
.size
) {
3904 Report
.error (info
.param
.source_reference
, "invalid destroy index");
3907 if ("%g".printf (parameters
[info
.destroy_idx
].vala_idx
) != "%g".printf (info
.vala_idx
+ 0.2)) {
3908 info
.param
.set_attribute_double ("CCode", "destroy_notify_pos", parameters
[info
.destroy_idx
].vala_idx
);
3912 if (info
.is_async
) {
3913 var resolved_type
= info
.param
.variable_type
;
3914 if (resolved_type is UnresolvedType
) {
3915 var resolved_symbol
= resolve_symbol (node
.parent
, ((UnresolvedType
) resolved_type
).unresolved_symbol
);
3916 if (resolved_symbol is Delegate
) {
3917 resolved_type
= new
DelegateType ((Delegate
) resolved_symbol
);
3921 if (resolved_type is DelegateType
) {
3922 var d
= ((DelegateType
) resolved_type
).delegate_symbol
;
3923 if (!(d
.name
== "DestroyNotify" && d
.parent_symbol
.name
== "GLib")) {
3924 info
.param
.set_attribute_string ("CCode", "scope", "async");
3925 info
.param
.variable_type
.value_owned
= (info
.closure_idx
!= -1 && info
.destroy_idx
!= -1);
3929 var resolved_type
= info
.param
.variable_type
;
3930 if (resolved_type is DelegateType
) {
3931 info
.param
.variable_type
.value_owned
= (info
.closure_idx
!= -1 && info
.destroy_idx
!= -1);
3936 if (return_type is ArrayType
&& node
.return_array_length_idx
>= 0) {
3937 set_array_ccode (s
, parameters
[node
.return_array_length_idx
]);
3940 if (s is Callable
) {
3941 ((Callable
) s
).return_type
= return_type
;
3945 void find_parent (string cname
, Node current
, ref Node best
, ref int match
) {
3946 var old_best
= best
;
3947 if (current
.symbol is Namespace
) {
3948 foreach (var child
in current
.members
) {
3949 // symbol is null only for aliases that aren't yet processed
3950 if ((child
.symbol
== null || is_container (child
.symbol
)) && cname
.has_prefix (child
.get_lower_case_cprefix ())) {
3951 find_parent (cname
, child
, ref best
, ref match
);
3955 if (best
!= old_best
) {
3960 var current_match
= current
.get_lower_case_cprefix().length
;
3961 if (current_match
> match
) {
3962 match
= current_match
;
3967 bool same_gir (Symbol gir_component
, Symbol sym
) {
3968 var gir_name
= gir_component
.source_reference
.file
.gir_namespace
;
3969 var gir_version
= gir_component
.source_reference
.file
.gir_version
;
3970 return "%s-%s".printf (gir_name
, gir_version
) in sym
.source_reference
.file
.filename
;
3973 void process_namespace_method (Node ns
, Node node
) {
3974 /* transform static methods into instance methods if possible.
3975 In most of cases this is a .gir fault we are going to fix */
3977 var ns_cprefix
= ns
.get_lower_case_cprefix ();
3978 var method
= (Method
) node
.symbol
;
3979 var cname
= node
.get_cname ();
3981 Parameter first_param
= null;
3982 if (node
.parameters
.size
> 0) {
3983 first_param
= node
.parameters
[0].param
;
3985 if (first_param
!= null && first_param
.direction
== ParameterDirection
.IN
&& first_param
.variable_type is UnresolvedType
) {
3986 // check if it's a missed instance method (often happens for structs)
3987 var sym
= ((UnresolvedType
) first_param
.variable_type
).unresolved_symbol
;
3988 var parent
= resolve_node (ns
, sym
);
3989 if (parent
!= null && same_gir (method
, parent
.symbol
) && parent
.parent
== ns
&& is_container (parent
.symbol
) && cname
.has_prefix (parent
.get_lower_case_cprefix ())) {
3991 var new_name
= method
.name
.substring (parent
.get_lower_case_cprefix().length
- ns_cprefix
.length
);
3992 if (parent
.lookup (new_name
) == null) {
3993 ns
.remove_member (node
);
3994 node
.name
= new_name
;
3995 node
.parameters
.remove_at (0);
3996 method
.name
= new_name
;
3997 method
.binding
= MemberBinding
.INSTANCE
;
3998 parent
.add_member (node
);
4006 find_parent (cname
, ns
, ref parent
, ref match
);
4007 var new_name
= method
.name
.substring (parent
.get_lower_case_cprefix().length
- ns_cprefix
.length
);
4008 if (same_gir (method
, parent
.symbol
) && parent
.lookup (new_name
) == null) {
4009 ns
.remove_member (node
);
4010 node
.name
= new_name
;
4011 method
.name
= new_name
;
4012 parent
.add_member (node
);
4016 void process_virtual_method_field (Node node
, Delegate d
, UnresolvedSymbol gtype_struct_for
) {
4017 var gtype_node
= resolve_node (node
.parent
, gtype_struct_for
);
4018 if (gtype_node
== null || !(gtype_node
.symbol is ObjectTypeSymbol
)) {
4019 Report
.error (gtype_struct_for
.source_reference
, "Unknown symbol `%s' for virtual method field `%s'".printf (gtype_struct_for
.to_string (), node
.to_string ()));
4021 var nodes
= gtype_node
.lookup_all (d
.name
);
4022 if (nodes
== null) {
4025 foreach (var n
in nodes
) {
4030 foreach (var n
in nodes
) {
4035 if (sym is Signal
) {
4036 var sig
= (Signal
) sym
;
4037 sig
.is_virtual
= true;
4038 assume_parameter_names (sig
, d
, true);
4039 } else if (sym is Property
) {
4040 var prop
= (Property
) sym
;
4041 prop
.is_virtual
= true;
4046 void process_async_method (Node node
) {
4047 var m
= (Method
) node
.symbol
;
4048 string finish_method_base
;
4049 if (m
.name
== null) {
4050 assert (m is CreationMethod
);
4051 finish_method_base
= "new";
4052 } else if (m
.name
.has_suffix ("_async")) {
4053 finish_method_base
= m
.name
.substring (0, m
.name
.length
- "_async".length
);
4055 finish_method_base
= m
.name
;
4057 var finish_method_node
= node
.parent
.lookup (finish_method_base
+ "_finish");
4059 // check if the method is using non-standard finish method name
4060 if (finish_method_node
== null) {
4061 var method_cname
= node
.get_finish_cname ();
4062 foreach (var n
in node
.parent
.members
) {
4063 if (n
.symbol is Method
&& n
.get_cname () == method_cname
) {
4064 finish_method_node
= n
;
4072 if (finish_method_node
!= null && finish_method_node
.symbol is Method
) {
4073 finish_method_node
.process (this
);
4074 var finish_method
= (Method
) finish_method_node
.symbol
;
4075 if (finish_method is CreationMethod
) {
4076 method
= new
CreationMethod (((CreationMethod
) finish_method
).class_name
, null, m
.source_reference
);
4077 method
.access
= m
.access
;
4078 method
.binding
= m
.binding
;
4079 method
.external
= true;
4080 method
.coroutine
= true;
4081 method
.has_construct_function
= finish_method
.has_construct_function
;
4083 // cannot use List.copy()
4084 // as it returns a list of unowned elements
4085 foreach (Attribute a
in m
.attributes
) {
4086 method
.attributes
.append (a
);
4089 method
.set_attribute_string ("CCode", "cname", node
.get_cname ());
4090 if (finish_method_base
== "new") {
4092 } else if (finish_method_base
.has_prefix ("new_")) {
4093 method
.name
= m
.name
.substring ("new_".length
);
4095 foreach (var param
in m
.get_parameters ()) {
4096 method
.add_parameter (param
);
4098 node
.symbol
= method
;
4100 method
.return_type
= finish_method
.return_type
.copy ();
4101 var a
= finish_method
.get_attribute ("CCode");
4102 if (a
!= null && a
.has_argument ("array_length")) {
4103 method
.set_attribute_bool ("CCode", "array_length", a
.get_bool ("array_length"));
4105 if (a
!= null && a
.has_argument ("array_null_terminated")) {
4106 method
.set_attribute_bool ("CCode", "array_null_terminated", a
.get_bool ("array_null_terminated"));
4110 foreach (var param
in finish_method
.get_parameters ()) {
4111 if (param
.direction
== ParameterDirection
.OUT
) {
4112 var async_param
= param
.copy ();
4113 if (method
.scope
.lookup (param
.name
) != null) {
4114 // parameter name conflict
4115 async_param
.name
+= "_out";
4117 method
.add_parameter (async_param
);
4121 foreach (DataType error_type
in finish_method
.get_error_types ()) {
4122 method
.add_error_type (error_type
.copy ());
4124 finish_method_node
.processed
= true;
4125 finish_method_node
.merged
= true;
4129 /* Hash and equal functions */
4131 static uint unresolved_symbol_hash (UnresolvedSymbol? sym
) {
4132 var builder
= new
StringBuilder ();
4133 while (sym
!= null) {
4134 builder
.append (sym
.name
);
4137 return builder
.str
.hash ();
4140 static bool unresolved_symbol_equal (UnresolvedSymbol? sym1
, UnresolvedSymbol? sym2
) {
4141 while (sym1
!= sym2
) {
4142 if (sym1
== null || sym2
== null) {
4145 if (sym1
.name
!= sym2
.name
) {
4154 /* Helper methods */
4156 Node?
base_interface_property (Node prop_node
) {
4157 var cl
= prop_node
.parent
.symbol as Class
;
4162 foreach (DataType type
in cl
.get_base_types ()) {
4163 if (!(type is UnresolvedType
)) {
4167 var base_node
= resolve_node (prop_node
.parent
, ((UnresolvedType
) type
).unresolved_symbol
);
4168 if (base_node
!= null && base_node
.symbol is Interface
) {
4169 var base_prop_node
= base_node
.lookup (prop_node
.name
);
4170 if (base_prop_node
!= null && base_prop_node
.symbol is Property
) {
4171 var base_property
= (Property
) base_prop_node
.symbol
;
4172 if (base_property
.is_abstract
|| base_property
.is_virtual
) {
4174 return base_prop_node
;