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
,
92 public static ArgumentType?
from_string (string name
) {
93 var enum_class
= (EnumClass
) typeof(ArgumentType
).class_ref ();
94 var nick
= name
.replace ("_", "-");
95 unowned GLib
.EnumValue? enum_value
= enum_class
.get_value_by_nick (nick
);
96 if (enum_value
!= null) {
97 ArgumentType value
= (ArgumentType
) enum_value
.value
;
105 public Expression expression
;
106 public SourceReference source_reference
;
108 public bool used
= false;
110 public Argument (Expression expression
, SourceReference? source_reference
= null) {
111 this
.expression
= expression
;
112 this
.source_reference
= source_reference
;
116 class MetadataSet
: Metadata
{
117 public MetadataSet (string? selector
= null) {
121 public void add_sibling (Metadata metadata
) {
122 foreach (var child
in metadata
.children
) {
125 // merge arguments and take precedence
126 foreach (var key
in metadata
.args
.get_keys ()) {
127 args
[key
] = metadata
.args
[key
];
133 private static Metadata _empty
= null;
134 public static Metadata empty
{
136 if (_empty
== null) {
137 _empty
= new
Metadata ("");
143 public PatternSpec pattern_spec
;
144 public string? selector
;
145 public SourceReference source_reference
;
147 public bool used
= false;
148 public Vala
.Map
<ArgumentType
,Argument
> args
= new HashMap
<ArgumentType
,Argument
> ();
149 public ArrayList
<Metadata
> children
= new ArrayList
<Metadata
> ();
151 public Metadata (string pattern
, string? selector
= null, SourceReference? source_reference
= null) {
152 this
.pattern_spec
= new
PatternSpec (pattern
);
153 this
.selector
= selector
;
154 this
.source_reference
= source_reference
;
157 public void add_child (Metadata metadata
) {
158 children
.add (metadata
);
161 public Metadata
match_child (string name
, string? selector
= null) {
162 var result
= Metadata
.empty
;
163 foreach (var metadata
in children
) {
164 if ((selector
== null || metadata
.selector
== null || metadata
.selector
== selector
) && metadata
.pattern_spec
.match_string (name
)) {
165 metadata
.used
= true;
166 if (result
== Metadata
.empty
) {
170 var ms
= result as MetadataSet
;
173 ms
= new
MetadataSet (selector
);
174 ms
.add_sibling (result
);
176 ms
.add_sibling (metadata
);
184 public void add_argument (ArgumentType key
, Argument value
) {
185 args
.set (key
, value
);
188 public bool has_argument (ArgumentType key
) {
189 return args
.contains (key
);
192 public Expression?
get_expression (ArgumentType arg
) {
193 var val
= args
.get (arg
);
196 return val
.expression
;
201 public string?
get_string (ArgumentType arg
) {
202 var lit
= get_expression (arg
) as StringLiteral
;
209 public int get_integer (ArgumentType arg
) {
210 var unary
= get_expression (arg
) as UnaryExpression
;
211 if (unary
!= null && unary
.operator
== UnaryOperator
.MINUS
) {
212 var lit
= unary
.inner as IntegerLiteral
;
214 return -int.parse (lit
.value
);
217 var lit
= get_expression (arg
) as IntegerLiteral
;
219 return int.parse (lit
.value
);
226 public bool get_bool (ArgumentType arg
, bool default_value
= false) {
227 var lit
= get_expression (arg
) as BooleanLiteral
;
231 return default_value
;
234 public SourceReference?
get_source_reference (ArgumentType arg
) {
235 var val
= args
.get (arg
);
237 return val
.source_reference
;
243 class MetadataParser
{
246 * metadata ::= [ rule [ '\n' relativerule ]* ]
247 * rule ::= pattern ' ' [ args ]
248 * relativerule ::= '.' rule
249 * pattern ::= glob [ '#' selector ] [ '.' pattern ]
251 private Metadata tree
= new
Metadata ("");
252 private Scanner scanner
;
253 private SourceLocation begin
;
254 private SourceLocation end
;
255 private SourceLocation old_end
;
256 private TokenType current
;
257 private Metadata parent_metadata
;
259 public MetadataParser () {
263 SourceReference
get_current_src () {
264 return new
SourceReference (scanner
.source_file
, begin
, end
);
267 SourceReference
get_src (SourceLocation begin
, SourceLocation? end
= null) {
272 return new
SourceReference (scanner
.source_file
, begin
, e
);
275 public Metadata
parse_metadata (SourceFile metadata_file
) {
276 scanner
= new
Scanner (metadata_file
);
278 while (current
!= TokenType
.EOF
) {
279 if (!parse_rule ()) {
280 return Metadata
.empty
;
288 current
= scanner
.read_token (out begin
, out end
);
293 return old_end
.pos
!= begin
.pos
;
296 bool has_newline () {
297 return old_end
.line
!= begin
.line
;
300 string get_string (SourceLocation? begin
= null, SourceLocation? end
= null) {
309 return ((string) b
.pos
).substring (0, (int) (e
.pos
- b
.pos
));
312 string?
parse_identifier (bool is_glob
) {
313 var begin
= this
.begin
;
315 if (current
== TokenType
.DOT
|| current
== TokenType
.HASH
) {
317 Report
.error (get_src (begin
), "expected glob-style pattern");
319 Report
.error (get_src (begin
), "expected identifier");
325 while (current
!= TokenType
.EOF
&& current
!= TokenType
.DOT
&& current
!= TokenType
.HASH
) {
335 return get_string (begin
, old_end
);
338 string?
parse_selector () {
339 if (current
!= TokenType
.HASH
|| has_space ()) {
344 return parse_identifier (false);
347 Metadata?
parse_pattern () {
349 bool is_relative
= false;
350 if (current
== TokenType
.IDENTIFIER
|| current
== TokenType
.STAR
) {
352 parent_metadata
= tree
;
355 if (current
!= TokenType
.DOT
) {
356 Report
.error (get_current_src (), "expected pattern or `.', got %s".printf (current
.to_string ()));
363 if (parent_metadata
== null) {
364 Report
.error (get_current_src (), "cannot determinate parent metadata");
368 SourceLocation begin
= this
.begin
;
369 var pattern
= parse_identifier (true);
370 if (pattern
== null) {
373 metadata
= new
Metadata (pattern
, parse_selector (), get_src (begin
));
374 parent_metadata
.add_child (metadata
);
376 while (current
!= TokenType
.EOF
&& !has_space ()) {
377 if (current
!= TokenType
.DOT
) {
378 Report
.error (get_current_src (), "expected `.' got %s".printf (current
.to_string ()));
384 pattern
= parse_identifier (true);
385 if (pattern
== null) {
388 var child
= new
Metadata (pattern
, parse_selector (), get_src (begin
, old_end
));
389 metadata
.add_child (child
);
393 parent_metadata
= metadata
;
399 Expression?
parse_expression () {
400 var begin
= this
.begin
;
401 var src
= get_current_src ();
402 Expression expr
= null;
405 expr
= new
NullLiteral (src
);
408 expr
= new
BooleanLiteral (true, src
);
410 case TokenType
.FALSE
:
411 expr
= new
BooleanLiteral (false, src
);
413 case TokenType
.MINUS
:
415 var inner
= parse_expression ();
417 Report
.error (src
, "expected expression after `-', got %s".printf (current
.to_string ()));
419 expr
= new
UnaryExpression (UnaryOperator
.MINUS
, inner
, get_src (begin
));
422 case TokenType
.INTEGER_LITERAL
:
423 expr
= new
IntegerLiteral (get_string (), src
);
425 case TokenType
.REAL_LITERAL
:
426 expr
= new
RealLiteral (get_string (), src
);
428 case TokenType
.STRING_LITERAL
:
429 expr
= new
StringLiteral (get_string (), src
);
431 case TokenType
.IDENTIFIER
:
432 expr
= new
MemberAccess (null, get_string (), src
);
433 while (next () == TokenType
.DOT
) {
434 if (next () != TokenType
.IDENTIFIER
) {
435 Report
.error (get_current_src (), "expected identifier got %s".printf (current
.to_string ()));
438 expr
= new
MemberAccess (expr
, get_string (), get_current_src ());
441 case TokenType
.OPEN_PARENS
:
442 // empty tuple => no expression
443 if (next () != TokenType
.CLOSE_PARENS
) {
444 Report
.error (get_current_src (), "expected `)', got %s".printf (current
.to_string ()));
447 expr
= new
Tuple (src
);
450 Report
.error (src
, "expected literal or symbol got %s".printf (current
.to_string ()));
457 bool parse_args (Metadata metadata
) {
458 while (current
!= TokenType
.EOF
&& has_space () && !has_newline ()) {
459 SourceLocation begin
= this
.begin
;
460 var id
= parse_identifier (false);
464 var arg_type
= ArgumentType
.from_string (id
);
465 if (arg_type
== null) {
466 Report
.warning (get_src (begin
, old_end
), "unknown argument `%s'".printf (id
));
470 if (current
!= TokenType
.ASSIGN
) {
472 metadata
.add_argument (arg_type
, new
Argument (new
BooleanLiteral (true, get_src (begin
)), get_src (begin
)));
477 Expression expr
= parse_expression ();
481 metadata
.add_argument (arg_type
, new
Argument (expr
, get_src (begin
)));
489 var metadata
= parse_pattern ();
490 if (metadata
== null) {
494 if (current
== TokenType
.EOF
|| old_end
.line
!= end
.line
) {
498 return parse_args (metadata
);
507 public static ArrayList
<Node
> new_namespaces
= new ArrayList
<Node
> ();
509 public weak Node parent
;
510 public string element_type
;
512 public Map
<string,string> girdata
= null;
513 public Metadata metadata
= Metadata
.empty
;
514 public SourceReference source_reference
= null;
515 public ArrayList
<Node
> members
= new ArrayList
<Node
> (); // guarantees fields order
516 public HashMap
<string, ArrayList
<Node
>> scope
= new HashMap
<string, ArrayList
<Node
>> (str_hash
, str_equal
);
518 public GirComment comment
;
519 public Symbol symbol
;
520 public bool new_symbol
;
522 public bool processed
;
525 public int return_array_length_idx
= -1;
526 public List
<ParameterInfo
> parameters
;
527 public ArrayList
<int> array_length_parameters
;
528 public ArrayList
<int> closure_parameters
;
529 public ArrayList
<int> destroy_parameters
;
531 public UnresolvedSymbol gtype_struct_for
;
533 public DataType base_type
;
535 public int array_length_idx
= -1;
537 public bool deprecated
= false;
538 public uint64 deprecated_version
= 0;
539 public string? deprecated_since
= null;
540 public string? deprecated_replacement
= null;
542 public Node (string? name
) {
546 public void add_member (Node node
) {
547 var nodes
= scope
[node
.name
];
549 nodes
= new ArrayList
<Node
> ();
550 scope
[node
.name
] = nodes
;
557 public void remove_member (Node node
) {
558 var nodes
= scope
[node
.name
];
560 if (nodes
.size
== 0) {
561 scope
.remove (node
.name
);
563 members
.remove (node
);
567 public Node?
lookup (string name
, bool create_namespace
= false, SourceReference? source_reference
= null) {
568 var nodes
= scope
[name
];
575 if (symbol
!= null) {
576 sym
= symbol
.scope
.lookup (name
);
578 if (sym
!= null || create_namespace
) {
579 node
= new
Node (name
);
581 node
.new_symbol
= node
.symbol
== null;
582 node
.source_reference
= source_reference
;
586 new_namespaces
.add (node
);
593 public ArrayList
<Node
>?
lookup_all (string name
) {
597 public UnresolvedSymbol
get_unresolved_symbol () {
598 if (parent
.name
== null) {
599 return new
UnresolvedSymbol (null, name
);
601 return new
UnresolvedSymbol (parent
.get_unresolved_symbol (), name
);
605 public string get_full_name () {
606 if (parent
== null) {
611 return parent
.get_full_name ();
614 if (parent
.get_full_name () == null) {
618 return "%s.%s".printf (parent
.get_full_name (), name
);
621 public string get_default_gir_name () {
622 GLib
.StringBuilder default_name
= new GLib
.StringBuilder ();
624 for (unowned Node? node
= this
; node
!= null ; node
= node
.parent
) {
625 if (node
.symbol is Namespace
) {
626 if (node
.symbol
.get_attribute_string ("CCode", "gir_namespace") != null) {
631 default_name
.prepend (node
.name
);
634 return default_name
.str
;
637 public string get_gir_name () {
638 var gir_name
= girdata
["name"];
639 if (gir_name
== null) {
640 gir_name
= girdata
["glib:name"];
645 public string get_lower_case_cprefix () {
650 var prefix
= symbol
.get_attribute_string ("CCode", "lower_case_cprefix");
651 if (prefix
== null && (symbol is ObjectTypeSymbol
|| symbol is Struct
)) {
652 if (metadata
.has_argument (ArgumentType
.LOWER_CASE_CPREFIX
)) {
653 prefix
= metadata
.get_string (ArgumentType
.LOWER_CASE_CPREFIX
);
654 } else if (metadata
.has_argument (ArgumentType
.CPREFIX
)) {
655 prefix
= metadata
.get_string (ArgumentType
.CPREFIX
);
657 prefix
= symbol
.get_attribute_string ("CCode", "cprefix");
661 if (prefix
== null && girdata
!= null && (girdata
.contains ("c:symbol-prefix") || girdata
.contains("c:symbol-prefixes"))) {
662 /* Use the prefix in the gir. We look up prefixes up to the root.
663 If some node does not have girdata, we ignore it as i might be
664 a namespace created due to reparenting. */
665 unowned Node cur
= this
;
667 if (cur
.girdata
!= null) {
668 var p
= cur
.girdata
["c:symbol-prefix"];
670 p
= cur
.girdata
["c:symbol-prefixes"];
672 var idx
= p
.index_of (",");
674 p
= p
.substring (0, idx
);
680 prefix
= "%s_%s".printf (p
, prefix ??
"");
685 } while (cur
!= null);
688 if (prefix
== null) {
689 prefix
= get_default_lower_case_cprefix ();
694 public string get_default_lower_case_cprefix () {
695 return "%s%s_".printf (parent
.get_lower_case_cprefix (), get_lower_case_csuffix ());
698 public string get_lower_case_csuffix () {
699 var suffix
= symbol
.get_attribute_string ("CCode", "lower_case_csuffix");
701 // we can't rely on gir suffix if metadata changed the name
702 if (suffix
== null && girdata
!= null && girdata
["c:symbol-prefix"] != null && !metadata
.has_argument (ArgumentType
.NAME
)) {
703 suffix
= girdata
["c:symbol-prefix"];
705 if (suffix
== null) {
706 suffix
= get_default_lower_case_csuffix ();
711 public string get_default_lower_case_csuffix () {
712 return Symbol
.camel_case_to_lower_case (name
);
715 public string get_cprefix () {
720 if (metadata
.has_argument (ArgumentType
.CPREFIX
)) {
721 prefix
= metadata
.get_string (ArgumentType
.CPREFIX
);
723 prefix
= symbol
.get_attribute_string ("CCode", "cprefix");
725 if (prefix
== null && girdata
!= null && girdata
["c:identifier-prefixes"] != null) {
726 prefix
= girdata
["c:identifier-prefixes"];
727 int idx
= prefix
.index_of (",");
729 prefix
= prefix
.substring (0, idx
);
732 if (prefix
== null) {
733 if (symbol is Enum
|| symbol is ErrorDomain
) {
734 prefix
= "%s%s".printf (parent
.get_lower_case_cprefix ().ascii_up (), name
);
736 prefix
= get_cname ();
742 public string get_cname () {
747 if (metadata
.has_argument (ArgumentType
.CNAME
)) {
748 cname
= metadata
.get_string (ArgumentType
.CNAME
);
750 cname
= symbol
.get_attribute_string ("CCode", "cname");
752 if (girdata
!= null) {
754 cname
= girdata
["c:identifier"];
757 cname
= girdata
["c:type"];
761 cname
= get_default_cname ();
766 public string get_default_cname () {
770 if (symbol is Field
) {
771 if (((Field
) symbol
).binding
== MemberBinding
.STATIC
) {
772 return parent
.get_lower_case_cprefix () + name
;
776 } else if (symbol is Method
) {
777 return "%s%s".printf (parent
.get_lower_case_cprefix (), name
);
779 return "%s%s".printf (parent
.get_cprefix (), name
);
783 public string get_finish_cname () {
784 var finish_cname
= symbol
.get_attribute_string ("CCode", "finish_name");
785 if (finish_cname
== null) {
786 finish_cname
= get_cname ();
787 if (finish_cname
.has_suffix ("_async")) {
788 finish_cname
= finish_cname
.substring (0, finish_cname
.length
- "_async".length
);
790 finish_cname
= "%s_finish".printf (finish_cname
);
795 public string get_cheader_filename () {
796 if (metadata
.has_argument (ArgumentType
.CHEADER_FILENAME
)) {
797 return metadata
.get_string (ArgumentType
.CHEADER_FILENAME
);
799 var cheader_filename
= symbol
.get_attribute_string ("CCode", "cheader_filename");
800 if (cheader_filename
!= null) {
801 return cheader_filename
;
803 if (parent
.name
!= null) {
804 return parent
.get_cheader_filename ();
805 } else if (symbol
.source_reference
!= null) {
806 return symbol
.source_reference
.file
.get_cinclude_filename ();
811 private static uint64 parse_version_string (string version
) {
814 string[] tokens
= version
.split (".", 3);
816 foreach (unowned
string token
in tokens
) {
819 if (!int64.try_parse (token
, out t
))
831 public void process (GirParser parser
) {
836 if (symbol is Namespace
&& parent
== parser
.root
) {
837 // first process aliases since they have no assigned symbol
838 foreach (var node
in members
) {
839 if (node
.element_type
== "alias") {
840 parser
.process_alias (node
);
844 // auto reparent namespace methods, allowing node removals
845 for (int i
=0; i
< members
.size
; i
++) {
846 var node
= members
[i
];
847 if (node
.symbol is Method
&& node
.new_symbol
) {
848 parser
.process_namespace_method (this
, node
);
849 if (i
< members
.size
&& members
[i
] != node
) {
850 // node removed in the middle
857 if (symbol is Class
&& girdata
!= null) {
858 var class_struct
= girdata
["glib:type-struct"];
859 if (class_struct
!= null) {
860 var klass
= parser
.resolve_node (parent
, parser
.parse_symbol_from_string (class_struct
, source_reference
));
863 while ( i
< klass
.members
.size
) {
864 var node
= klass
.members
[i
];
865 if (node
.symbol is Method
) {
866 klass
.remove_member (node
);
867 this
.add_member (node
);
869 Method m
= (Method
) node
.symbol
;
870 m
.binding
= MemberBinding
.CLASS
;
880 foreach (var node
in members
) {
881 node
.process (parser
);
884 if (girdata
!= null) {
885 // GIR node processing
886 if (symbol is Method
) {
887 var m
= (Method
) symbol
;
888 parser
.process_callable (this
);
890 var colliding
= parent
.lookup_all (name
);
891 foreach (var node
in colliding
) {
892 var sym
= node
.symbol
;
893 if (sym is Field
&& !(m
.return_type is VoidType
) && m
.get_parameters().size
== 0) {
894 // assume method is getter
896 } else if (sym is Signal
) {
897 node
.process (parser
);
898 var sig
= (Signal
) sym
;
899 if (m
.is_virtual
|| m
.is_abstract
) {
900 sig
.is_virtual
= true;
902 sig
.set_attribute ("HasEmitter", true);
904 parser
.assume_parameter_names (sig
, m
, false);
905 if (m
.get_parameters().size
!= sig
.get_parameters().size
) {
906 Report
.warning (symbol
.source_reference
, "Signal `%s' conflicts with method of the same name".printf (get_full_name ()));
909 } else if (sym is Method
&& !(sym is CreationMethod
) && node
!= this
) {
910 if (m
.is_virtual
|| m
.is_abstract
) {
911 bool different_invoker
= false;
912 var attr
= m
.get_attribute ("NoWrapper");
914 /* no invoker but this method has the same name,
915 most probably the invoker has a different name
916 and g-ir-scanner missed it */
917 var invoker
= parser
.find_invoker (this
);
918 if (invoker
!= null) {
919 m
.set_attribute_string ("CCode", "vfunc_name", m
.name
);
920 m
.name
= invoker
.symbol
.name
;
921 m
.set_attribute ("NoWrapper", false);
922 invoker
.merged
= true;
923 different_invoker
= true;
926 if (!different_invoker
) {
928 Report
.warning (symbol
.source_reference
, "Virtual method `%s' conflicts with method of the same name".printf (get_full_name ()));
935 if (!(m is CreationMethod
)) {
936 if (metadata
.has_argument (ArgumentType
.DESTROYS_INSTANCE
)) {
937 m
.set_attribute ("DestroysInstance", metadata
.get_bool (ArgumentType
.DESTROYS_INSTANCE
));
939 if (metadata
.has_argument (ArgumentType
.RETURNS_MODIFIED_POINTER
)) {
940 m
.set_attribute ("ReturnsModifiedPointer", metadata
.get_bool (ArgumentType
.RETURNS_MODIFIED_POINTER
));
942 // merge custom vfunc
943 if (metadata
.has_argument (ArgumentType
.VFUNC_NAME
)) {
944 var vfunc
= parent
.lookup (metadata
.get_string (ArgumentType
.VFUNC_NAME
));
945 if (vfunc
!= null && vfunc
!= this
) {
946 vfunc
.processed
= true;
952 parser
.process_async_method (this
);
954 } else if (symbol is Property
) {
955 var colliding
= parent
.lookup_all (name
);
956 foreach (var node
in colliding
) {
957 if (node
.symbol is Signal
) {
958 // properties take precedence
959 node
.processed
= true;
961 } else if (node
.symbol is Method
) {
962 // getter in C, but not in Vala
967 var prop
= (Property
) symbol
;
969 // add accessors, can't do this before gir symbol resolution
970 var readable
= girdata
["readable"];
971 var writable
= girdata
["writable"];
972 var construct_
= girdata
["construct"];
973 var construct_only
= girdata
["construct-only"];
974 if (readable
!= "0") {
975 prop
.get_accessor
= new
PropertyAccessor (true, false, false, prop
.property_type
.copy (), null, null);
977 if (writable
== "1" || construct_only
== "1") {
978 prop
.set_accessor
= new
PropertyAccessor (false, (construct_only
!= "1") && (writable
== "1"), (construct_only
== "1") || (construct_
== "1"), prop
.property_type
.copy (), null, null);
981 // find virtual/abstract accessors to handle abstract properties properly
984 var getters
= parent
.lookup_all ("get_%s".printf (name
));
985 if (getters
!= null) {
986 foreach (var g
in getters
) {
987 if ((getter
== null || !g
.merged
) && g
.get_cname () == "%sget_%s".printf (parent
.get_lower_case_cprefix (), name
)) {
994 var setters
= parent
.lookup_all ("set_%s".printf (name
));
995 if (setters
!= null) {
996 foreach (var s
in setters
) {
997 if ((setter
== null || !s
.merged
) && s
.get_cname () == "%sset_%s".printf (parent
.get_lower_case_cprefix (), name
)) {
1003 prop
.set_attribute ("NoAccessorMethod", (readable
== "0" && construct_only
== "1"));
1004 if (prop
.get_accessor
!= null) {
1005 var m
= getter
!= null ? getter
.symbol as Method
: null;
1006 // ensure getter vfunc if the property is abstract
1008 getter
.process (parser
);
1009 if (m
.return_type is VoidType
|| m
.get_parameters().size
!= 0 || m
.get_error_types ().size
> 0) {
1010 prop
.set_attribute ("NoAccessorMethod", true);
1012 if (getter
.name
== name
) {
1013 foreach (var node
in colliding
) {
1014 if (node
.symbol is Method
) {
1020 prop
.get_accessor
.value_type
.value_owned
= m
.return_type
.value_owned
;
1022 if (!m
.is_abstract
&& !m
.is_virtual
&& prop
.is_abstract
) {
1023 prop
.set_attribute ("ConcreteAccessor", true);
1027 prop
.set_attribute ("NoAccessorMethod", true);
1031 if (prop
.get_attribute ("NoAccessorMethod") == null && prop
.set_accessor
!= null && prop
.set_accessor
.writable
) {
1032 var m
= setter
!= null ? setter
.symbol as Method
: null;
1033 // ensure setter vfunc if the property is abstract
1035 setter
.process (parser
);
1036 if (!(m
.return_type is VoidType
|| m
.return_type is BooleanType
) || m
.get_parameters ().size
!= 1 || m
.get_error_types ().size
> 0) {
1037 prop
.set_attribute ("NoAccessorMethod", true);
1038 prop
.set_attribute ("ConcreteAccessor", false);
1040 prop
.set_accessor
.value_type
.value_owned
= m
.get_parameters()[0].variable_type
.value_owned
;
1041 if (prop
.get_attribute ("ConcreteAccessor") != null && !m
.is_abstract
&& !m
.is_virtual
&& prop
.is_abstract
) {
1042 prop
.set_attribute ("ConcreteAccessor", true);
1043 prop
.set_attribute ("NoAccessorMethod", false);
1047 prop
.set_attribute ("NoAccessorMethod", true);
1048 prop
.set_attribute ("ConcreteAccessor", false);
1052 if (prop
.get_attribute ("NoAccessorMethod") != null) {
1053 if (!prop
.overrides
&& parent
.symbol is Class
) {
1055 // find base interface property with ConcreteAccessor and this overriding property with NoAccessorMethod
1056 var base_prop_node
= parser
.base_interface_property (this
);
1057 if (base_prop_node
!= null) {
1058 base_prop_node
.process (parser
);
1060 var base_property
= (Property
) base_prop_node
.symbol
;
1061 if (base_property
.get_attribute ("ConcreteAccessor") != null) {
1062 prop
.set_attribute ("NoAccessorMethod", false);
1063 if (prop
.get_accessor
!= null) {
1064 prop
.get_accessor
.value_type
.value_owned
= base_property
.get_accessor
.value_type
.value_owned
;
1066 if (prop
.set_accessor
!= null) {
1067 prop
.set_accessor
.value_type
.value_owned
= base_property
.set_accessor
.value_type
.value_owned
;
1075 if (metadata
.has_argument (ArgumentType
.NO_ACCESSOR_METHOD
)) {
1076 prop
.set_attribute ("NoAccessorMethod", metadata
.get_bool (ArgumentType
.NO_ACCESSOR_METHOD
));
1079 if (prop
.get_attribute ("NoAccessorMethod") != null) {
1081 if (prop
.get_accessor
!= null) {
1082 prop
.get_accessor
.value_type
.value_owned
= true;
1084 if (prop
.set_accessor
!= null) {
1085 prop
.set_accessor
.value_type
.value_owned
= false;
1088 } else if (symbol is Field
) {
1089 var field
= (Field
) symbol
;
1090 var colliding
= parent
.lookup_all (name
);
1091 if (colliding
.size
> 1) {
1092 // whatelse has precedence over the field
1096 if (metadata
.has_argument (ArgumentType
.DELEGATE_TARGET_CNAME
)) {
1097 field
.set_attribute_string ("CCode", "delegate_target_cname", metadata
.get_string (ArgumentType
.DELEGATE_TARGET_CNAME
));
1100 if (field
.variable_type is DelegateType
&& parent
.gtype_struct_for
!= null) {
1101 // virtual method field
1102 var d
= ((DelegateType
) field
.variable_type
).delegate_symbol
;
1103 parser
.process_virtual_method_field (this
, d
, parent
.gtype_struct_for
);
1105 } else if (field
.variable_type is ArrayType
) {
1107 if (metadata
.has_argument (ArgumentType
.ARRAY_LENGTH_FIELD
)) {
1108 array_length
= parent
.lookup (metadata
.get_string (ArgumentType
.ARRAY_LENGTH_FIELD
));
1109 } else if (array_length_idx
> -1 && parent
.members
.size
> array_length_idx
) {
1110 array_length
= parent
.members
[array_length_idx
];
1112 array_length
= parent
.lookup ("n_%s".printf (field
.name
));
1113 if (array_length
== null) {
1114 array_length
= parent
.lookup ("num_%s".printf (field
.name
));
1115 if (array_length
== null) {
1116 array_length
= parent
.lookup ("%s_length".printf (field
.name
));
1120 if (array_length
!= null && array_length
.symbol is Field
) {
1121 var length_field
= (Field
) array_length
.symbol
;
1123 field
.set_attribute_string ("CCode", "array_length_cname", length_field
.name
);
1124 var length_type
= length_field
.variable_type
.to_qualified_string ();
1125 if (length_type
!= "int") {
1126 var st
= parser
.root
.lookup (length_type
);
1128 field
.set_attribute_string ("CCode", "array_length_type", st
.get_cname ());
1131 field
.remove_attribute_argument ("CCode", "array_length");
1132 field
.remove_attribute_argument ("CCode", "array_null_terminated");
1135 } else if (symbol is Signal
|| symbol is Delegate
) {
1136 parser
.process_callable (this
);
1137 } else if (symbol is Interface
) {
1138 parser
.process_interface (this
);
1139 } else if (symbol is Struct
) {
1140 if (parent
.symbol is ObjectTypeSymbol
|| parent
.symbol is Struct
) {
1142 foreach (var fn
in members
) {
1143 var f
= fn
.symbol as Field
;
1145 if (f
.binding
== MemberBinding
.INSTANCE
) {
1146 f
.set_attribute_string ("CCode", "cname", "%s.%s".printf (name
, fn
.get_cname ()));
1148 f
.name
= "%s_%s".printf (symbol
.name
, f
.name
);
1150 parent
.add_member (fn
);
1155 // record for a gtype
1156 var gtype_struct_for
= girdata
["glib:is-gtype-struct-for"];
1157 if (gtype_struct_for
!= null) {
1158 var iface
= parser
.resolve_node (parent
, parser
.parse_symbol_from_string (gtype_struct_for
, source_reference
));
1159 if (iface
!= null && iface
.symbol is Interface
&& "%sIface".printf (iface
.get_cname ()) != get_cname ()) {
1160 // set the interface struct name
1161 iface
.symbol
.set_attribute_string ("CCode", "type_cname", get_cname ());
1169 if (metadata
.has_argument (ArgumentType
.REPLACEMENT
)) {
1171 deprecated_replacement
= metadata
.get_string (ArgumentType
.REPLACEMENT
);
1173 if (metadata
.has_argument (ArgumentType
.DEPRECATED_SINCE
)) {
1175 deprecated_since
= metadata
.get_string (ArgumentType
.DEPRECATED_SINCE
);
1176 } else if (girdata
["deprecated-version"] != null) {
1178 deprecated_since
= girdata
.get ("deprecated-version");
1180 if (metadata
.has_argument (ArgumentType
.DEPRECATED
)) {
1181 deprecated
= metadata
.get_bool (ArgumentType
.DEPRECATED
, true);
1183 deprecated_since
= null;
1184 deprecated_replacement
= null;
1186 } else if (girdata
["deprecated"] != null) {
1189 if (deprecated_since
!= null) {
1190 deprecated_version
= parse_version_string (deprecated_since
);
1194 if (metadata
.has_argument (ArgumentType
.EXPERIMENTAL
)) {
1195 symbol
.set_attribute_bool ("Version", "experimental", metadata
.get_bool (ArgumentType
.EXPERIMENTAL
));
1199 if (metadata
.has_argument (ArgumentType
.SINCE
)) {
1200 symbol
.version
.since
= metadata
.get_string (ArgumentType
.SINCE
);
1201 } else if (symbol is Namespace
== false && girdata
["version"] != null) {
1202 symbol
.version
.since
= girdata
.get ("version");
1205 if (parent
.symbol is Namespace
) {
1206 // always write cheader filename for namespace children
1207 symbol
.set_attribute_string ("CCode", "cheader_filename", get_cheader_filename ());
1208 } else if (metadata
.has_argument (ArgumentType
.CHEADER_FILENAME
)) {
1209 symbol
.set_attribute_string ("CCode", "cheader_filename", metadata
.get_string (ArgumentType
.CHEADER_FILENAME
));
1211 if (get_cname () != get_default_cname ()) {
1212 symbol
.set_attribute_string ("CCode", "cname", get_cname ());
1215 // lower_case_cprefix
1216 if (get_lower_case_cprefix () != get_default_lower_case_cprefix ()) {
1217 symbol
.set_attribute_string ("CCode", "lower_case_cprefix", get_lower_case_cprefix ());
1219 // lower_case_csuffix
1220 if (get_lower_case_csuffix () != get_default_lower_case_csuffix ()) {
1221 symbol
.set_attribute_string ("CCode", "lower_case_csuffix", get_lower_case_csuffix ());
1224 // set gir name if the symbol has been renamed
1225 string gir_name
= get_gir_name ();
1226 string default_gir_name
= get_default_gir_name ();
1227 if (is_container (symbol
) && !(symbol is Namespace
) && (name
!= gir_name
|| gir_name
!= default_gir_name
)) {
1228 symbol
.set_attribute_string ("GIR", "name", gir_name
);
1232 if (!(new_symbol
&& merged
) && is_container (symbol
)) {
1233 foreach (var node
in members
) {
1234 if (this
.deprecated_version
> 0 && node
.deprecated_version
> 0) {
1235 if (this
.deprecated_version
<= node
.deprecated_version
) {
1236 node
.deprecated
= false;
1237 node
.deprecated_since
= null;
1238 node
.deprecated_replacement
= null;
1241 if (node
.deprecated
) {
1242 node
.symbol
.version
.deprecated
= true;
1244 if (node
.deprecated_since
!= null) {
1245 node
.symbol
.version
.deprecated_since
= node
.deprecated_since
;
1247 if (node
.deprecated_replacement
!= null) {
1248 node
.symbol
.version
.replacement
= node
.deprecated_replacement
;
1251 if (node
.new_symbol
&& !node
.merged
&& !metadata
.get_bool (ArgumentType
.HIDDEN
)) {
1252 add_symbol_to_container (symbol
, node
.symbol
);
1256 var cl
= symbol as Class
;
1257 if (cl
!= null && !cl
.is_compact
&& cl
.default_construction_method
== null) {
1258 // always provide constructor in generated bindings
1259 // to indicate that implicit Object () chainup is allowed
1260 var cm
= new
CreationMethod (null, null, cl
.source_reference
);
1261 cm
.has_construct_function
= false;
1262 cm
.access
= SymbolAccessibility
.PROTECTED
;
1270 public string to_string () {
1271 if (parent
.name
== null) {
1274 return "%s.%s".printf (parent
.to_string (), name
);
1279 static GLib
.Regex type_from_string_regex
;
1281 MarkupReader reader
;
1283 CodeContext context
;
1286 SourceFile current_source_file
;
1288 ArrayList
<Metadata
> metadata_roots
= new ArrayList
<Metadata
> ();
1290 SourceLocation begin
;
1292 MarkupTokenType current_token
;
1294 string[] cheader_filenames
;
1296 ArrayList
<Metadata
> metadata_stack
;
1298 ArrayList
<Node
> tree_stack
;
1302 Set
<string> provided_namespaces
= new HashSet
<string> (str_hash
, str_equal
);
1303 HashMap
<UnresolvedSymbol
,Symbol
> unresolved_symbols_map
= new HashMap
<UnresolvedSymbol
,Symbol
> (unresolved_symbol_hash
, unresolved_symbol_equal
);
1304 ArrayList
<UnresolvedSymbol
> unresolved_gir_symbols
= new ArrayList
<UnresolvedSymbol
> ();
1305 ArrayList
<DataType
> unresolved_type_arguments
= new ArrayList
<DataType
> ();
1308 * Parses all .gir source files in the specified code
1309 * context and builds a code tree.
1311 * @param context a code context
1313 public void parse (CodeContext context
) {
1314 this
.context
= context
;
1315 glib_ns
= context
.root
.scope
.lookup ("GLib") as Namespace
;
1317 root
= new
Node (null);
1318 root
.symbol
= context
.root
;
1319 tree_stack
= new ArrayList
<Node
> ();
1324 context
.accept (this
);
1326 resolve_gir_symbols ();
1327 create_new_namespaces ();
1328 resolve_type_arguments ();
1330 root
.process (this
);
1332 foreach (var metadata
in metadata_roots
) {
1333 report_unused_metadata (metadata
);
1336 this
.context
= null;
1339 void map_vala_to_gir () {
1340 foreach (var source_file
in context
.get_source_files ()) {
1341 string gir_namespace
= source_file
.gir_namespace
;
1342 string gir_version
= source_file
.gir_version
;
1343 Namespace ns
= null;
1344 if (gir_namespace
== null) {
1345 foreach (var node
in source_file
.get_nodes ()) {
1346 if (node is Namespace
) {
1347 ns
= (Namespace
) node
;
1348 gir_namespace
= ns
.get_attribute_string ("CCode", "gir_namespace");
1349 if (gir_namespace
!= null) {
1350 gir_version
= ns
.get_attribute_string ("CCode", "gir_version");
1356 if (gir_namespace
== null) {
1360 provided_namespaces
.add ("%s-%s".printf (gir_namespace
, gir_version
));
1362 var gir_symbol
= new
UnresolvedSymbol (null, gir_namespace
);
1363 if (gir_namespace
!= ns
.name
) {
1364 set_symbol_mapping (gir_symbol
, ns
);
1367 foreach (var node
in source_file
.get_nodes ()) {
1368 if (node
.has_attribute_argument ("GIR", "name")) {
1369 var map_from
= new
UnresolvedSymbol (gir_symbol
, node
.get_attribute_string ("GIR", "name"));
1370 set_symbol_mapping (map_from
, (Symbol
) node
);
1376 public override void visit_source_file (SourceFile source_file
) {
1377 if (source_file
.filename
.has_suffix (".gir")) {
1378 parse_file (source_file
);
1382 public void parse_file (SourceFile source_file
) {
1383 var has_global_context
= (context
!= null);
1384 if (!has_global_context
) {
1385 context
= source_file
.context
;
1388 metadata_stack
= new ArrayList
<Metadata
> ();
1389 metadata
= Metadata
.empty
;
1390 cheader_filenames
= null;
1392 this
.current_source_file
= source_file
;
1393 reader
= new
MarkupReader (source_file
.filename
);
1400 parse_repository ();
1403 this
.current_source_file
= null;
1404 if (!has_global_context
) {
1410 current_token
= reader
.read_token (out begin
, out end
);
1413 void start_element (string name
) {
1414 if (current_token
!= MarkupTokenType
.START_ELEMENT
|| reader
.name
!= name
) {
1416 Report
.error (get_current_src (), "expected start element of `%s'".printf (name
));
1420 void end_element (string name
) {
1421 while (current_token
!= MarkupTokenType
.END_ELEMENT
|| reader
.name
!= name
) {
1422 Report
.warning (get_current_src (), "expected end element of `%s'".printf (name
));
1428 SourceReference
get_current_src () {
1429 return new
SourceReference (this
.current_source_file
, begin
, end
);
1432 const string GIR_VERSION
= "1.2";
1434 static void add_symbol_to_container (Symbol container
, Symbol sym
) {
1435 if (container is Class
) {
1436 unowned Class cl
= (Class
) container
;
1439 cl
.add_class ((Class
) sym
);
1440 } else if (sym is Constant
) {
1441 cl
.add_constant ((Constant
) sym
);
1442 } else if (sym is Enum
) {
1443 cl
.add_enum ((Enum
) sym
);
1444 } else if (sym is Field
) {
1445 cl
.add_field ((Field
) sym
);
1446 } else if (sym is Method
) {
1447 cl
.add_method ((Method
) sym
);
1448 } else if (sym is Property
) {
1449 cl
.add_property ((Property
) sym
);
1450 } else if (sym is Signal
) {
1451 cl
.add_signal ((Signal
) sym
);
1452 } else if (sym is Struct
) {
1453 cl
.add_struct ((Struct
) sym
);
1455 } else if (container is Enum
) {
1456 unowned Enum en
= (Enum
) container
;
1458 if (sym is EnumValue
) {
1459 en
.add_value ((EnumValue
) sym
);
1460 } else if (sym is Constant
) {
1461 en
.add_constant ((Constant
) sym
);
1462 } else if (sym is Method
) {
1463 en
.add_method ((Method
) sym
);
1465 } else if (container is Interface
) {
1466 unowned Interface iface
= (Interface
) container
;
1469 iface
.add_class ((Class
) sym
);
1470 } else if (sym is Constant
) {
1471 iface
.add_constant ((Constant
) sym
);
1472 } else if (sym is Enum
) {
1473 iface
.add_enum ((Enum
) sym
);
1474 } else if (sym is Field
) {
1475 iface
.add_field ((Field
) sym
);
1476 } else if (sym is Method
) {
1477 iface
.add_method ((Method
) sym
);
1478 } else if (sym is Property
) {
1479 iface
.add_property ((Property
) sym
);
1480 } else if (sym is Signal
) {
1481 iface
.add_signal ((Signal
) sym
);
1482 } else if (sym is Struct
) {
1483 iface
.add_struct ((Struct
) sym
);
1485 } else if (container is Namespace
) {
1486 unowned Namespace ns
= (Namespace
) container
;
1488 if (sym is Namespace
) {
1489 ns
.add_namespace ((Namespace
) sym
);
1490 } else if (sym is Class
) {
1491 ns
.add_class ((Class
) sym
);
1492 } else if (sym is Constant
) {
1493 ns
.add_constant ((Constant
) sym
);
1494 } else if (sym is Delegate
) {
1495 ns
.add_delegate ((Delegate
) sym
);
1496 } else if (sym is Enum
) {
1497 ns
.add_enum ((Enum
) sym
);
1498 } else if (sym is ErrorDomain
) {
1499 ns
.add_error_domain ((ErrorDomain
) sym
);
1500 } else if (sym is Field
) {
1501 ns
.add_field ((Field
) sym
);
1502 } else if (sym is Interface
) {
1503 ns
.add_interface ((Interface
) sym
);
1504 } else if (sym is Method
) {
1505 ns
.add_method ((Method
) sym
);
1506 } else if (sym is Struct
) {
1507 ns
.add_struct ((Struct
) sym
);
1509 } else if (container is Struct
) {
1510 unowned Struct st
= (Struct
) container
;
1512 if (sym is Constant
) {
1513 st
.add_constant ((Constant
) sym
);
1514 } else if (sym is Field
) {
1515 st
.add_field ((Field
) sym
);
1516 } else if (sym is Method
) {
1517 st
.add_method ((Method
) sym
);
1518 } else if (sym is Property
) {
1519 st
.add_property ((Property
) sym
);
1521 } else if (container is ErrorDomain
) {
1522 unowned ErrorDomain ed
= (ErrorDomain
) container
;
1524 if (sym is ErrorCode
) {
1525 ed
.add_code ((ErrorCode
) sym
);
1526 } else if (sym is Method
) {
1527 ed
.add_method ((Method
) sym
);
1530 Report
.error (sym
.source_reference
, "impossible to add `%s' to container `%s'".printf (sym
.name
, container
.name
));
1534 static bool is_container (Symbol sym
) {
1535 return sym is ObjectTypeSymbol
|| sym is Struct
|| sym is Namespace
|| sym is ErrorDomain
|| sym is Enum
;
1538 UnresolvedSymbol?
parse_symbol_from_string (string symbol_string
, SourceReference? source_reference
= null) {
1539 UnresolvedSymbol? sym
= null;
1540 foreach (unowned
string s
in symbol_string
.split (".")) {
1541 sym
= new
UnresolvedSymbol (sym
, s
, source_reference
);
1544 Report
.error (source_reference
, "a symbol must be specified");
1549 void set_symbol_mapping (UnresolvedSymbol map_from
, Symbol map_to
) {
1550 // last mapping is the most up-to-date
1551 if (map_from is UnresolvedSymbol
) {
1552 unresolved_symbols_map
[(UnresolvedSymbol
) map_from
] = map_to
;
1556 void assume_parameter_names (Signal sig
, Symbol sym
, bool skip_first
) {
1557 var iter
= ((Callable
) sym
).get_parameters ().iterator ();
1559 foreach (var param
in sig
.get_parameters ()) {
1560 if (!iter
.next ()) {
1561 // unreachable for valid GIR
1564 if (skip_first
&& first
) {
1565 if (!iter
.next ()) {
1566 // unreachable for valid GIR
1571 param
.name
= iter
.get ().name
;
1575 Node?
find_invoker (Node node
) {
1576 /* most common use case is invoker has at least the given method prefix
1577 and the same parameter names */
1578 var m
= (Method
) node
.symbol
;
1579 var prefix
= "%s_".printf (m
.name
);
1580 foreach (var n
in node
.parent
.members
) {
1581 if (!n
.name
.has_prefix (prefix
)) {
1584 Method? invoker
= n
.symbol as Method
;
1585 if (invoker
== null || (m
.get_parameters().size
!= invoker
.get_parameters().size
)) {
1588 var iter
= invoker
.get_parameters ().iterator ();
1589 foreach (var param
in m
.get_parameters ()) {
1590 assert (iter
.next ());
1591 if (param
.name
!= iter
.get().name
) {
1596 if (invoker
!= null) {
1604 Metadata
get_current_metadata () {
1605 var selector
= reader
.name
;
1606 var child_name
= reader
.get_attribute ("name");
1607 if (child_name
== null) {
1608 child_name
= reader
.get_attribute ("glib:name");
1610 // Give a transparent union the generic name "union"
1611 if (selector
== "union" && child_name
== null) {
1612 child_name
= "union";
1614 if (child_name
== null) {
1615 return Metadata
.empty
;
1617 selector
= selector
.replace ("-", "_");
1618 child_name
= child_name
.replace ("-", "_");
1620 if (selector
.has_prefix ("glib:")) {
1621 selector
= selector
.substring ("glib:".length
);
1624 return metadata
.match_child (child_name
, selector
);
1627 bool push_metadata () {
1628 var new_metadata
= get_current_metadata ();
1630 if (new_metadata
.has_argument (ArgumentType
.SKIP
)) {
1631 if (new_metadata
.get_bool (ArgumentType
.SKIP
)) {
1634 } else if (reader
.get_attribute ("introspectable") == "0" || reader
.get_attribute ("private") == "1") {
1638 metadata_stack
.add (metadata
);
1639 metadata
= new_metadata
;
1644 void pop_metadata () {
1645 metadata
= metadata_stack
.remove_at (metadata_stack
.size
- 1);
1648 bool parse_type_arguments_from_string (DataType parent_type
, string type_arguments
, SourceReference? source_reference
= null) {
1649 int type_arguments_length
= (int) type_arguments
.length
;
1650 GLib
.StringBuilder current
= new GLib
.StringBuilder
.sized (type_arguments_length
);
1653 for (var c
= 0 ; c
< type_arguments_length
; c
++) {
1654 if (type_arguments
[c
] == '<' || type_arguments
[c
] == '[') {
1656 current
.append_unichar (type_arguments
[c
]);
1657 } else if (type_arguments
[c
] == '>' || type_arguments
[c
] == ']') {
1659 current
.append_unichar (type_arguments
[c
]);
1660 } else if (type_arguments
[c
] == ',') {
1662 var dt
= parse_type_from_string (current
.str
, true, source_reference
);
1666 parent_type
.add_type_argument (dt
);
1667 current
.truncate ();
1669 current
.append_unichar (type_arguments
[c
]);
1672 current
.append_unichar (type_arguments
[c
]);
1676 var dt
= parse_type_from_string (current
.str
, true, source_reference
);
1680 parent_type
.add_type_argument (dt
);
1685 DataType?
parse_type_from_string (string type_string
, bool owned_by_default
, SourceReference? source_reference
= null) {
1686 if (type_from_string_regex
== null) {
1688 type_from_string_regex
= new GLib
.Regex ("^(?:(owned|unowned|weak) +)?([0-9a-zA-Z_\\.]+)(?:<(.+)>)?(\\*+)?(\\[,*\\])?(\\?)?$", GLib
.RegexCompileFlags
.ANCHORED
| GLib
.RegexCompileFlags
.DOLLAR_ENDONLY
| GLib
.RegexCompileFlags
.OPTIMIZE
);
1689 } catch (GLib
.RegexError e
) {
1690 GLib
.error ("Unable to compile regex: %s", e
.message
);
1694 GLib
.MatchInfo match
;
1695 if (!type_from_string_regex
.match (type_string
, 0, out match
)) {
1696 Report
.error (source_reference
, "unable to parse type");
1700 DataType? type
= null;
1702 var ownership_data
= match
.fetch (1);
1703 var type_name
= match
.fetch (2);
1704 var type_arguments_data
= match
.fetch (3);
1705 var pointers_data
= match
.fetch (4);
1706 var array_data
= match
.fetch (5);
1707 var nullable_data
= match
.fetch (6);
1709 var nullable
= nullable_data
!= null && nullable_data
.length
> 0;
1711 if (ownership_data
== null && type_name
== "void") {
1712 if (array_data
== null && !nullable
) {
1713 type
= new
VoidType (source_reference
);
1714 if (pointers_data
!= null) {
1715 for (int i
=0; i
< pointers_data
.length
; i
++) {
1716 type
= new
PointerType (type
);
1721 Report
.error (source_reference
, "invalid void type");
1726 bool value_owned
= owned_by_default
;
1728 if (ownership_data
== "owned") {
1729 if (owned_by_default
) {
1730 Report
.error (source_reference
, "unexpected `owned' keyword");
1734 } else if (ownership_data
== "unowned") {
1735 if (owned_by_default
) {
1736 value_owned
= false;
1738 Report
.error (source_reference
, "unexpected `unowned' keyword");
1743 var sym
= parse_symbol_from_string (type_name
, source_reference
);
1747 type
= new UnresolvedType
.from_symbol (sym
, source_reference
);
1749 if (type_arguments_data
!= null && type_arguments_data
.length
> 0) {
1750 if (!parse_type_arguments_from_string (type
, type_arguments_data
, source_reference
)) {
1755 if (pointers_data
!= null) {
1756 for (int i
=0; i
< pointers_data
.length
; i
++) {
1757 type
= new
PointerType (type
);
1761 if (array_data
!= null && array_data
.length
!= 0) {
1762 type
.value_owned
= true;
1763 type
= new
ArrayType (type
, (int) array_data
.length
- 1, source_reference
);
1766 type
.nullable
= nullable
;
1767 type
.value_owned
= value_owned
;
1771 string?
element_get_string (string attribute_name
, ArgumentType arg_type
) {
1772 if (metadata
.has_argument (arg_type
)) {
1773 return metadata
.get_string (arg_type
);
1775 return reader
.get_attribute (attribute_name
);
1780 * The changed is a faster way to check whether the type has changed and it may affect the C declaration.
1782 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) {
1784 var type
= orig_type
;
1786 if (metadata
.has_argument (ArgumentType
.TYPE
)) {
1787 type
= parse_type_from_string (metadata
.get_string (ArgumentType
.TYPE
), owned_by_default
, metadata
.get_source_reference (ArgumentType
.TYPE
));
1789 } else if (!(type is VoidType
)) {
1790 if (metadata
.has_argument (ArgumentType
.TYPE_ARGUMENTS
)) {
1791 type
.remove_all_type_arguments ();
1792 parse_type_arguments_from_string (type
, metadata
.get_string (ArgumentType
.TYPE_ARGUMENTS
), metadata
.get_source_reference (ArgumentType
.TYPE_ARGUMENTS
));
1795 if (!(type is ArrayType
) && metadata
.get_bool (ArgumentType
.ARRAY
)) {
1796 type
.value_owned
= true;
1797 type
= new
ArrayType (type
, 1, type
.source_reference
);
1801 if (owned_by_default
) {
1802 type
.value_owned
= !metadata
.get_bool (ArgumentType
.UNOWNED
, !type
.value_owned
);
1804 type
.value_owned
= metadata
.get_bool (ArgumentType
.OWNED
, type
.value_owned
);
1806 type
.nullable
= metadata
.get_bool (ArgumentType
.NULLABLE
, type
.nullable
);
1809 if (type is ArrayType
) {
1810 if (!(orig_type is ArrayType
)) {
1811 no_array_length
= true;
1813 array_null_terminated
= metadata
.get_bool (ArgumentType
.ARRAY_NULL_TERMINATED
, array_null_terminated
);
1819 string?
element_get_name (string? gir_name
= null) {
1820 var name
= gir_name
;
1822 name
= reader
.get_attribute ("name");
1824 var pattern
= metadata
.get_string (ArgumentType
.NAME
);
1825 if (pattern
!= null) {
1826 if (pattern
.index_of_char ('(') < 0) {
1827 // shortcut for "(.+)/replacement"
1831 string replacement
= "\\1"; // replace the whole name with the match by default
1832 var split
= pattern
.split ("/");
1833 if (split
.length
> 1) {
1835 replacement
= split
[1];
1837 var regex
= new
Regex (pattern
, RegexCompileFlags
.ANCHORED
, RegexMatchFlags
.ANCHORED
);
1838 name
= regex
.replace (name
, -1, 0, replacement
);
1844 if (name
!= null && name
.has_suffix ("Enum")) {
1845 name
= name
.substring (0, name
.length
- "Enum".length
);
1852 string?
element_get_type_id () {
1853 var type_id
= metadata
.get_string (ArgumentType
.TYPE_ID
);
1854 if (type_id
!= null) {
1858 type_id
= reader
.get_attribute ("glib:get-type");
1859 if (type_id
!= null) {
1865 void set_array_ccode (Symbol sym
, ParameterInfo info
) {
1866 sym
.set_attribute_double ("CCode", "array_length_pos", info
.vala_idx
);
1867 if (sym is Parameter
) {
1868 sym
.set_attribute_string ("CCode", "array_length_cname", info
.param
.name
);
1870 var type_name
= info
.param
.variable_type
.to_qualified_string ();
1871 if (type_name
!= "int") {
1872 var st
= root
.lookup (type_name
);
1874 if (sym is Method
) {
1875 var m
= (Method
) sym
;
1876 m
.set_attribute_string ("CCode", "array_length_type", st
.get_cname ());
1878 var param
= (Parameter
) sym
;
1879 param
.set_attribute_string ("CCode", "array_length_type", st
.get_cname ());
1885 void set_type_id_ccode (Symbol sym
) {
1886 if (sym
.has_attribute_argument ("CCode", "has_type_id")
1887 || sym
.has_attribute_argument ("CCode", "type_id"))
1890 var type_id
= element_get_type_id ();
1891 if (type_id
== null) {
1892 sym
.set_attribute_bool ("CCode", "has_type_id", false);
1894 sym
.set_attribute_string ("CCode", "type_id", type_id
);
1898 void parse_repository () {
1899 start_element ("repository");
1900 if (reader
.get_attribute ("version") != GIR_VERSION
) {
1901 Report
.error (get_current_src (), "unsupported GIR version %s (supported: %s)".printf (reader
.get_attribute ("version"), GIR_VERSION
));
1905 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1906 if (reader
.name
== "namespace") {
1908 } else if (reader
.name
== "include") {
1910 } else if (reader
.name
== "package") {
1911 var pkg
= parse_package ();
1912 this
.current_source_file
.package_name
= pkg
;
1913 if (context
.has_package (pkg
)) {
1914 // package already provided elsewhere, stop parsing this GIR
1915 // if it was not passed explicitly
1916 if (!this
.current_source_file
.explicit
) {
1920 context
.add_package (pkg
);
1922 } else if (reader
.name
== "c:include") {
1926 Report
.error (get_current_src (), "unknown child element `%s' in `repository'".printf (reader
.name
));
1930 end_element ("repository");
1933 void parse_include () {
1934 start_element ("include");
1935 var pkg
= reader
.get_attribute ("name");
1936 var version
= reader
.get_attribute ("version");
1937 if (version
!= null) {
1938 pkg
= "%s-%s".printf (pkg
, version
);
1940 // add the package to the queue
1941 context
.add_external_package (pkg
);
1943 end_element ("include");
1946 string parse_package () {
1947 start_element ("package");
1948 var pkg
= reader
.get_attribute ("name");
1950 end_element ("package");
1954 void parse_c_include () {
1955 start_element ("c:include");
1956 cheader_filenames
+= reader
.get_attribute ("name");
1958 end_element ("c:include");
1961 void skip_element () {
1966 if (current_token
== MarkupTokenType
.START_ELEMENT
) {
1968 } else if (current_token
== MarkupTokenType
.END_ELEMENT
) {
1970 } else if (current_token
== MarkupTokenType
.EOF
) {
1971 Report
.error (get_current_src (), "unexpected end of file");
1978 Node?
resolve_node (Node parent_scope
, UnresolvedSymbol unresolved_sym
, bool create_namespace
= false) {
1979 if (unresolved_sym
.inner
== null) {
1980 var scope
= parent_scope
;
1981 while (scope
!= null) {
1982 var node
= scope
.lookup (unresolved_sym
.name
, create_namespace
, unresolved_sym
.source_reference
);
1986 scope
= scope
.parent
;
1989 var inner
= resolve_node (parent_scope
, unresolved_sym
.inner
, create_namespace
);
1990 if (inner
!= null) {
1991 return inner
.lookup (unresolved_sym
.name
, create_namespace
, unresolved_sym
.source_reference
);
1997 Symbol?
resolve_symbol (Node parent_scope
, UnresolvedSymbol unresolved_sym
) {
1998 var node
= resolve_node (parent_scope
, unresolved_sym
);
2005 void push_node (string name
, bool merge
) {
2006 var parent
= current
;
2007 if (metadata
.has_argument (ArgumentType
.PARENT
)) {
2008 var target
= parse_symbol_from_string (metadata
.get_string (ArgumentType
.PARENT
), metadata
.get_source_reference (ArgumentType
.PARENT
));
2009 parent
= resolve_node (root
, target
, true);
2012 var node
= parent
.lookup (name
);
2013 if (node
== null || (node
.symbol
!= null && !merge
)) {
2014 node
= new
Node (name
);
2015 node
.new_symbol
= true;
2016 parent
.add_member (node
);
2018 Node
.new_namespaces
.remove (node
);
2020 node
.element_type
= reader
.name
;
2021 node
.girdata
= reader
.get_attributes ();
2022 node
.metadata
= metadata
;
2023 node
.source_reference
= get_current_src ();
2025 var gir_name
= node
.get_gir_name ();
2026 if (parent
!= current
|| gir_name
!= name
) {
2027 set_symbol_mapping (new
UnresolvedSymbol (null, gir_name
), node
.get_unresolved_symbol ());
2030 tree_stack
.add (current
);
2035 old_current
= current
;
2036 current
= tree_stack
.remove_at (tree_stack
.size
- 1);
2039 void parse_namespace () {
2040 start_element ("namespace");
2042 string? cprefix
= reader
.get_attribute ("c:identifier-prefixes");
2043 if (cprefix
!= null) {
2044 int idx
= cprefix
.index_of (",");
2046 cprefix
= cprefix
.substring (0, idx
);
2050 string? lower_case_cprefix
= reader
.get_attribute ("c:symbol-prefixes");
2051 string vala_namespace
= cprefix
;
2052 string gir_namespace
= reader
.get_attribute ("name");
2053 string gir_version
= reader
.get_attribute ("version");
2055 if (lower_case_cprefix
!= null) {
2056 int idx
= lower_case_cprefix
.index_of (",");
2058 lower_case_cprefix
= lower_case_cprefix
.substring (0, idx
);
2062 if (provided_namespaces
.contains ("%s-%s".printf (gir_namespace
, gir_version
))) {
2067 // load metadata, first look into metadata directories then in the same directory of the .gir.
2068 string? metadata_filename
= context
.get_metadata_path (current_source_file
.filename
);
2069 if (metadata_filename
!= null && FileUtils
.test (metadata_filename
, FileTest
.EXISTS
)) {
2070 var metadata_parser
= new
MetadataParser ();
2071 var metadata_file
= new
SourceFile (context
, current_source_file
.file_type
, metadata_filename
);
2072 context
.add_source_file (metadata_file
);
2073 metadata
= metadata_parser
.parse_metadata (metadata_file
);
2074 metadata_roots
.add (metadata
);
2077 var ns_metadata
= metadata
.match_child (gir_namespace
);
2078 if (ns_metadata
.has_argument (ArgumentType
.NAME
)) {
2079 vala_namespace
= ns_metadata
.get_string (ArgumentType
.NAME
);
2081 if (vala_namespace
== null) {
2082 vala_namespace
= gir_namespace
;
2085 current_source_file
.gir_namespace
= gir_namespace
;
2086 current_source_file
.gir_version
= gir_version
;
2089 push_node (vala_namespace
, true);
2090 if (current
.new_symbol
) {
2091 ns
= new
Namespace (vala_namespace
, current
.source_reference
);
2092 current
.symbol
= ns
;
2094 ns
= (Namespace
) current
.symbol
;
2095 ns
.attributes
= null;
2096 ns
.source_reference
= current
.source_reference
;
2099 current
.metadata
= ns_metadata
;
2101 if (ns_metadata
.has_argument (ArgumentType
.CPREFIX
)) {
2102 cprefix
= ns_metadata
.get_string (ArgumentType
.CPREFIX
);
2105 if (ns_metadata
.has_argument (ArgumentType
.LOWER_CASE_CPREFIX
)) {
2106 lower_case_cprefix
= ns_metadata
.get_string (ArgumentType
.LOWER_CASE_CPREFIX
);
2107 } else if (lower_case_cprefix
!= null) {
2108 lower_case_cprefix
+= "_";
2111 ns
.set_attribute_string ("CCode", "gir_namespace", gir_namespace
);
2112 ns
.set_attribute_string ("CCode", "gir_version", gir_version
);
2114 if (cprefix
!= null) {
2115 ns
.set_attribute_string ("CCode", "cprefix", cprefix
);
2116 if (lower_case_cprefix
== null) {
2117 ns
.set_attribute_string ("CCode", "lower_case_cprefix", Symbol
.camel_case_to_lower_case (cprefix
) + "_");
2121 if (lower_case_cprefix
!= null) {
2122 ns
.set_attribute_string ("CCode", "lower_case_cprefix", lower_case_cprefix
);
2125 if (cheader_filenames
!= null) {
2126 ns
.set_attribute_string ("CCode", "cheader_filename", string.joinv (",", cheader_filenames
));
2130 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2131 if (!push_metadata ()) {
2136 if (reader
.name
== "alias") {
2138 } else if (reader
.name
== "enumeration") {
2139 if (metadata
.has_argument (ArgumentType
.ERRORDOMAIN
)) {
2140 if (metadata
.get_bool (ArgumentType
.ERRORDOMAIN
)) {
2141 parse_error_domain ();
2143 parse_enumeration ();
2146 if ((reader
.get_attribute ("glib:error-quark") != null) || (reader
.get_attribute ("glib:error-domain") != null)) {
2147 parse_error_domain ();
2149 parse_enumeration ();
2152 } else if (reader
.name
== "bitfield") {
2154 } else if (reader
.name
== "function") {
2155 parse_method ("function");
2156 } else if (reader
.name
== "callback") {
2158 } else if (reader
.name
== "record") {
2159 if (metadata
.has_argument (ArgumentType
.STRUCT
)) {
2160 if (metadata
.get_bool (ArgumentType
.STRUCT
)) {
2163 parse_boxed ("record");
2165 } else if (element_get_type_id () != null) {
2166 parse_boxed ("record");
2167 } else if (!reader
.get_attribute ("name").has_suffix ("Private")) {
2168 if (reader
.get_attribute ("glib:is-gtype-struct-for") == null && reader
.get_attribute ("disguised") == "1") {
2169 parse_boxed ("record");
2176 } else if (reader
.name
== "class") {
2178 } else if (reader
.name
== "interface") {
2180 } else if (reader
.name
== "glib:boxed") {
2181 parse_boxed ("glib:boxed");
2182 } else if (reader
.name
== "union") {
2183 if (element_get_type_id () != null && !metadata
.get_bool (ArgumentType
.STRUCT
)) {
2184 parse_boxed ("union");
2188 } else if (reader
.name
== "constant") {
2192 Report
.error (get_current_src (), "unknown child element `%s' in `namespace'".printf (reader
.name
));
2199 end_element ("namespace");
2202 void parse_alias () {
2203 start_element ("alias");
2204 push_node (element_get_name (), true);
2205 // not enough information, symbol will be created while processing the tree
2209 if (current
.comment
== null) {
2210 current
.comment
= parse_symbol_doc ();
2212 parse_symbol_doc ();
2215 bool no_array_length
= false;
2216 bool array_null_terminated
= false;
2217 current
.base_type
= element_get_type (parse_type (null, null, true), true, ref no_array_length
, ref array_null_terminated
);
2219 if (metadata
.has_argument (ArgumentType
.BASE_TYPE
)) {
2220 current
.base_type
= parse_type_from_string (metadata
.get_string (ArgumentType
.BASE_TYPE
), true, metadata
.get_source_reference (ArgumentType
.BASE_TYPE
));
2224 end_element ("alias");
2227 private void calculate_common_prefix (ref string? common_prefix
, string cname
) {
2228 if (common_prefix
== null) {
2229 common_prefix
= cname
;
2230 while (common_prefix
.length
> 0 && !common_prefix
.has_suffix ("_")) {
2231 // FIXME: could easily be made faster
2232 common_prefix
= common_prefix
.substring (0, common_prefix
.length
- 1);
2235 while (!cname
.has_prefix (common_prefix
)) {
2236 common_prefix
= common_prefix
.substring (0, common_prefix
.length
- 1);
2239 while (common_prefix
.length
> 0 && (!common_prefix
.has_suffix ("_") ||
2240 (cname
.get_char (common_prefix
.length
).isdigit ()) && (cname
.length
- common_prefix
.length
) <= 1)) {
2241 // enum values may not consist solely of digits
2242 common_prefix
= common_prefix
.substring (0, common_prefix
.length
- 1);
2246 GirComment?
parse_symbol_doc () {
2247 GirComment? comment
= null;
2249 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2250 unowned
string reader_name
= reader
.name
;
2252 if (reader_name
== "doc") {
2253 start_element ("doc");
2257 if (current_token
== MarkupTokenType
.TEXT
) {
2258 comment
= new
GirComment (reader
.content
, current
.source_reference
);
2262 end_element ("doc");
2263 } else if (reader_name
== "doc-version" || reader_name
== "doc-deprecated" || reader_name
== "doc-stability") {
2273 Comment?
parse_doc () {
2274 Comment? comment
= null;
2276 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2277 unowned
string reader_name
= reader
.name
;
2279 if (reader_name
== "doc") {
2280 start_element ("doc");
2284 if (current_token
== MarkupTokenType
.TEXT
) {
2285 comment
= new
Comment (reader
.content
, current
.source_reference
);
2289 end_element ("doc");
2290 } else if (reader_name
== "doc-version" || reader_name
== "doc-deprecated" || reader_name
== "doc-stability") {
2300 void parse_enumeration (string element_name
= "enumeration", bool error_domain
= false) {
2301 start_element (element_name
);
2302 push_node (element_get_name (), true);
2305 if (current
.new_symbol
) {
2307 sym
= new
ErrorDomain (current
.name
, current
.source_reference
);
2309 var en
= new
Enum (current
.name
, current
.source_reference
);
2310 if (element_name
== "bitfield") {
2311 en
.set_attribute ("Flags", true);
2315 current
.symbol
= sym
;
2317 sym
= current
.symbol
;
2321 set_type_id_ccode (sym
);
2323 sym
.external
= true;
2324 sym
.access
= SymbolAccessibility
.PUBLIC
;
2326 string common_prefix
= null;
2327 bool has_member
= false;
2331 sym
.comment
= parse_symbol_doc ();
2333 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2334 if (!push_metadata ()) {
2339 if (reader
.name
== "member") {
2342 parse_error_member ();
2343 calculate_common_prefix (ref common_prefix
, old_current
.get_cname ());
2345 parse_enumeration_member ();
2346 calculate_common_prefix (ref common_prefix
, old_current
.get_cname ());
2348 } else if (reader
.name
== "function") {
2352 Report
.error (get_current_src (), "unknown child element `%s' in `%s'".printf (reader
.name
, element_name
));
2360 Report
.error (get_current_src (), "%s `%s' has no members".printf (element_name
, current
.name
));
2363 if (common_prefix
!= null) {
2364 sym
.set_attribute_string ("CCode", "cprefix", common_prefix
);
2368 end_element (element_name
);
2371 void parse_error_domain () {
2372 parse_enumeration ("enumeration", true);
2375 void parse_bitfield () {
2376 parse_enumeration ("bitfield");
2379 void parse_enumeration_member () {
2380 start_element ("member");
2381 push_node (element_get_name().ascii_up().replace ("-", "_"), false);
2383 var ev
= new
EnumValue (current
.name
, metadata
.get_expression (ArgumentType
.DEFAULT
), current
.source_reference
);
2384 current
.symbol
= ev
;
2387 ev
.comment
= parse_symbol_doc ();
2390 end_element ("member");
2393 void parse_error_member () {
2394 start_element ("member");
2395 push_node (element_get_name().ascii_up().replace ("-", "_"), false);
2398 string value
= reader
.get_attribute ("value");
2399 if (value
!= null) {
2400 ec
= new ErrorCode
.with_value (current
.name
, new
IntegerLiteral (value
));
2402 ec
= new
ErrorCode (current
.name
);
2404 current
.symbol
= ec
;
2407 ec
.comment
= parse_symbol_doc ();
2410 end_element ("member");
2413 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) {
2414 start_element ("return-value");
2416 string transfer
= reader
.get_attribute ("transfer-ownership");
2417 string nullable
= reader
.get_attribute ("nullable");
2418 string allow_none
= reader
.get_attribute ("allow-none");
2421 comment
= parse_doc ();
2423 var transfer_elements
= transfer
!= "container";
2424 var type
= parse_type (out ctype
, out array_length_idx
, transfer_elements
, out no_array_length
, out array_null_terminated
);
2425 if (transfer
== "full" || transfer
== "container") {
2426 type
.value_owned
= true;
2428 if (nullable
== "1" || allow_none
== "1") {
2429 type
.nullable
= true;
2431 type
= element_get_type (type
, true, ref no_array_length
, ref array_null_terminated
);
2433 end_element ("return-value");
2437 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) {
2440 array_length_idx
= -1;
2444 string element_type
= reader
.name
;
2445 if (current_token
!= MarkupTokenType
.START_ELEMENT
|| (element_type
!= "parameter" && element_type
!= "instance-parameter")) {
2446 Report
.error (get_current_src (), "expected start element of `parameter' or `instance-parameter'");
2448 start_element (element_type
);
2449 var name
= metadata
.get_string (ArgumentType
.NAME
);
2451 name
= reader
.get_attribute ("name");
2454 name
= default_name
;
2456 string direction
= null;
2457 if (metadata
.has_argument (ArgumentType
.OUT
)) {
2458 if (metadata
.get_bool (ArgumentType
.OUT
)) {
2461 } else if (metadata
.has_argument (ArgumentType
.REF
)) {
2462 if (metadata
.get_bool (ArgumentType
.REF
)) {
2463 direction
= "inout";
2466 direction
= reader
.get_attribute ("direction");
2468 string transfer
= reader
.get_attribute ("transfer-ownership");
2469 string nullable
= reader
.get_attribute ("nullable");
2470 string allow_none
= reader
.get_attribute ("allow-none");
2472 scope
= element_get_string ("scope", ArgumentType
.SCOPE
);
2474 string closure
= reader
.get_attribute ("closure");
2475 string destroy
= reader
.get_attribute ("destroy");
2476 if (closure
!= null && &closure_idx
!= null) {
2477 closure_idx
= int.parse (closure
);
2479 if (destroy
!= null && &destroy_idx
!= null) {
2480 destroy_idx
= int.parse (destroy
);
2482 if (metadata
.has_argument (ArgumentType
.CLOSURE
)) {
2483 closure_idx
= metadata
.get_integer (ArgumentType
.CLOSURE
);
2485 if (metadata
.has_argument (ArgumentType
.DESTROY
)) {
2486 destroy_idx
= metadata
.get_integer (ArgumentType
.DESTROY
);
2491 comment
= parse_doc ();
2493 if (reader
.name
== "varargs") {
2494 start_element ("varargs");
2496 param
= new Parameter
.with_ellipsis (get_current_src ());
2497 end_element ("varargs");
2500 bool no_array_length
;
2501 bool array_null_terminated
;
2502 var type
= parse_type (out ctype
, out array_length_idx
, transfer
!= "container", out no_array_length
, out array_null_terminated
);
2503 if (transfer
== "full" || transfer
== "container" || destroy
!= null) {
2504 type
.value_owned
= true;
2506 if (nullable
== "1" || (allow_none
== "1" && direction
!= "out")) {
2507 type
.nullable
= true;
2511 type
= element_get_type (type
, direction
== "out" || direction
== "inout", ref no_array_length
, ref array_null_terminated
, out changed
);
2513 // discard ctype, duplicated information
2517 param
= new
Parameter (name
, type
, get_current_src ());
2518 if (ctype
!= null) {
2519 param
.set_attribute_string ("CCode", "type", ctype
);
2521 if (direction
== "out") {
2522 param
.direction
= ParameterDirection
.OUT
;
2523 } else if (direction
== "inout") {
2524 param
.direction
= ParameterDirection
.REF
;
2526 if (type is ArrayType
) {
2527 if (metadata
.has_argument (ArgumentType
.ARRAY_LENGTH_IDX
)) {
2528 array_length_idx
= metadata
.get_integer (ArgumentType
.ARRAY_LENGTH_IDX
);
2530 if (no_array_length
|| array_null_terminated
) {
2531 param
.set_attribute_bool ("CCode", "array_length", !no_array_length
);
2533 if (array_null_terminated
) {
2534 param
.set_attribute_bool ("CCode", "array_null_terminated", array_null_terminated
);
2538 param
.initializer
= metadata
.get_expression (ArgumentType
.DEFAULT
);
2540 // empty tuple used for parameters without initializer
2541 if (param
.initializer is Tuple
) {
2542 param
.initializer
= null;
2545 end_element (element_type
);
2549 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) {
2550 bool is_array
= false;
2551 string type_name
= reader
.get_attribute ("name");
2554 var fixed_length
= -1;
2555 array_length_idx
= -1;
2556 no_array_length
= true;
2557 array_null_terminated
= true;
2559 if (reader
.name
== "array") {
2561 start_element ("array");
2563 var src
= get_current_src ();
2565 if (type_name
== null) {
2566 if (reader
.get_attribute ("length") != null) {
2567 array_length_idx
= int.parse (reader
.get_attribute ("length"));
2568 no_array_length
= false;
2569 array_null_terminated
= false;
2571 if (reader
.get_attribute ("fixed-size") != null) {
2572 fixed_length
= int.parse (reader
.get_attribute ("fixed-size"));
2573 array_null_terminated
= false;
2575 if (reader
.get_attribute ("c:type") == "GStrv") {
2576 no_array_length
= true;
2577 array_null_terminated
= true;
2579 if (reader
.get_attribute ("zero-terminated") != null) {
2580 array_null_terminated
= int.parse (reader
.get_attribute ("zero-terminated")) != 0;
2583 var element_type
= parse_type ();
2584 element_type
.value_owned
= transfer_elements
;
2585 end_element ("array");
2587 var array_type
= new
ArrayType (element_type
, 1, src
);
2588 if (fixed_length
> 0) {
2589 array_type
.fixed_length
= true;
2590 array_type
.length
= new
IntegerLiteral (fixed_length
.to_string ());
2594 } else if (reader
.name
== "callback"){
2596 return new
DelegateType ((Delegate
) old_current
.symbol
);
2598 start_element ("type");
2601 ctype
= reader
.get_attribute("c:type");
2605 if (type_name
== "GLib.PtrArray"
2606 && current_token
== MarkupTokenType
.START_ELEMENT
) {
2607 type_name
= "GLib.GenericArray";
2610 if (type_name
== null) {
2614 DataType type
= parse_type_from_gir_name (type_name
, out no_array_length
, out array_null_terminated
, ctype
);
2616 // type arguments / element types
2617 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2618 if (type_name
== "GLib.ByteArray") {
2622 var element_type
= parse_type ();
2623 element_type
.value_owned
= transfer_elements
;
2624 type
.add_type_argument (element_type
);
2625 unresolved_type_arguments
.add (element_type
);
2628 end_element (is_array ?
"array" : "type");
2632 DataType
parse_type_from_gir_name (string type_name
, out bool no_array_length
= null, out bool array_null_terminated
= null, string? ctype
= null) {
2633 no_array_length
= false;
2634 array_null_terminated
= false;
2636 DataType? type
= null;
2637 if (type_name
== "none") {
2638 type
= new
VoidType (get_current_src ());
2639 } else if (type_name
== "gpointer") {
2640 type
= new
PointerType (new
VoidType (get_current_src ()), get_current_src ());
2641 } else if (type_name
== "GObject.Strv") {
2642 var element_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, "string"));
2643 element_type
.value_owned
= true;
2644 type
= new
ArrayType (element_type
, 1, get_current_src ());
2645 no_array_length
= true;
2646 array_null_terminated
= true;
2648 bool known_type
= true;
2649 if (type_name
== "utf8") {
2650 type_name
= "string";
2651 } else if (type_name
== "gboolean") {
2652 type
= new
BooleanType ((Struct
) context
.root
.scope
.lookup ("bool"));
2653 } else if (type_name
== "gchar") {
2655 } else if (type_name
== "gshort") {
2656 type_name
= "short";
2657 } else if (type_name
== "gushort") {
2658 type_name
= "ushort";
2659 } else if (type_name
== "gint") {
2661 } else if (type_name
== "guint") {
2663 } else if (type_name
== "glong") {
2664 if (ctype
!= null && ctype
.has_prefix ("gssize")) {
2665 type_name
= "ssize_t";
2666 } else if (ctype
!= null && ctype
.has_prefix ("gintptr")) {
2667 type_name
= "intptr";
2671 } else if (type_name
== "gulong") {
2672 if (ctype
!= null && ctype
.has_prefix ("gsize")) {
2673 type_name
= "size_t";
2674 } else if (ctype
!= null && ctype
.has_prefix ("guintptr")) {
2675 type_name
= "uintptr";
2677 type_name
= "ulong";
2679 } else if (type_name
== "gint8") {
2681 } else if (type_name
== "guint8") {
2682 type_name
= "uint8";
2683 } else if (type_name
== "gint16") {
2684 type_name
= "int16";
2685 } else if (type_name
== "guint16") {
2686 type_name
= "uint16";
2687 } else if (type_name
== "gint32") {
2688 type_name
= "int32";
2689 } else if (type_name
== "guint32") {
2690 type_name
= "uint32";
2691 } else if (type_name
== "gint64") {
2692 type_name
= "int64";
2693 } else if (type_name
== "guint64") {
2694 type_name
= "uint64";
2695 } else if (type_name
== "gfloat") {
2696 type_name
= "float";
2697 } else if (type_name
== "gdouble") {
2698 type_name
= "double";
2699 } else if (type_name
== "filename") {
2700 type_name
= "string";
2701 } else if (type_name
== "GLib.offset") {
2702 type_name
= "int64";
2703 } else if (type_name
== "gsize") {
2704 type_name
= "size_t";
2705 } else if (type_name
== "gssize") {
2706 type_name
= "ssize_t";
2707 } else if (type_name
== "guintptr") {
2708 type_name
= "uintptr";
2709 } else if (type_name
== "gintptr") {
2710 type_name
= "intptr";
2711 } else if (type_name
== "GType") {
2712 type_name
= "GLib.Type";
2713 } else if (type_name
== "GLib.String") {
2714 type_name
= "GLib.StringBuilder";
2715 } else if (type_name
== "GObject.Class") {
2716 type_name
= "GLib.ObjectClass";
2717 } else if (type_name
== "gunichar") {
2718 type_name
= "unichar";
2719 } else if (type_name
== "GLib.Data") {
2720 type_name
= "GLib.Datalist";
2721 } else if (type_name
== "Atk.ImplementorIface") {
2722 type_name
= "Atk.Implementor";
2728 var sym
= parse_symbol_from_string (type_name
, get_current_src ());
2729 type
= new UnresolvedType
.from_symbol (sym
, get_current_src ());
2731 unresolved_gir_symbols
.add (sym
);
2739 void parse_record () {
2740 start_element ("record");
2741 push_node (element_get_name (), true);
2744 if (current
.new_symbol
) {
2745 st
= new
Struct (element_get_name (), current
.source_reference
);
2746 current
.symbol
= st
;
2748 st
= (Struct
) current
.symbol
;
2751 set_type_id_ccode (st
);
2754 st
.access
= SymbolAccessibility
.PUBLIC
;
2756 var gtype_struct_for
= reader
.get_attribute ("glib:is-gtype-struct-for");
2757 if (gtype_struct_for
!= null) {
2758 current
.gtype_struct_for
= parse_symbol_from_string (gtype_struct_for
, current
.source_reference
);
2759 unresolved_gir_symbols
.add (current
.gtype_struct_for
);
2762 bool first_field
= true;
2765 st
.comment
= parse_symbol_doc ();
2767 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2768 if (!push_metadata ()) {
2769 if (first_field
&& reader
.name
== "field") {
2770 first_field
= false;
2776 if (reader
.name
== "field") {
2777 if (reader
.get_attribute ("name") != "priv" && !(first_field
&& gtype_struct_for
!= null)) {
2782 first_field
= false;
2783 } else if (reader
.name
== "constructor") {
2784 parse_constructor ();
2785 } else if (reader
.name
== "method") {
2786 parse_method ("method");
2787 } else if (reader
.name
== "function") {
2789 } else if (reader
.name
== "union") {
2793 Report
.error (get_current_src (), "unknown child element `%s' in `record'".printf (reader
.name
));
2801 end_element ("record");
2804 void parse_class () {
2805 start_element ("class");
2806 push_node (element_get_name (), true);
2809 var parent
= reader
.get_attribute ("parent");
2810 if (current
.new_symbol
) {
2811 cl
= new
Class (current
.name
, current
.source_reference
);
2812 cl
.is_abstract
= metadata
.get_bool (ArgumentType
.ABSTRACT
, reader
.get_attribute ("abstract") == "1");
2814 if (parent
!= null) {
2815 cl
.add_base_type (parse_type_from_gir_name (parent
));
2817 current
.symbol
= cl
;
2819 cl
= (Class
) current
.symbol
;
2822 set_type_id_ccode (cl
);
2824 cl
.access
= SymbolAccessibility
.PUBLIC
;
2829 cl
.comment
= parse_symbol_doc ();
2831 var first_field
= true;
2832 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2833 if (!push_metadata ()) {
2834 if (first_field
&& reader
.name
== "field") {
2835 first_field
= false;
2841 if (reader
.name
== "implements") {
2842 start_element ("implements");
2843 cl
.add_base_type (parse_type_from_gir_name (reader
.get_attribute ("name")));
2845 end_element ("implements");
2846 } else if (reader
.name
== "constant") {
2848 } else if (reader
.name
== "field") {
2849 if (first_field
&& parent
!= null) {
2850 // first field is guaranteed to be the parent instance
2853 if (reader
.get_attribute ("name") != "priv") {
2859 first_field
= false;
2860 } else if (reader
.name
== "property") {
2862 } else if (reader
.name
== "constructor") {
2863 parse_constructor ();
2864 } else if (reader
.name
== "function") {
2865 parse_method ("function");
2866 } else if (reader
.name
== "method") {
2867 parse_method ("method");
2868 } else if (reader
.name
== "virtual-method") {
2869 parse_method ("virtual-method");
2870 } else if (reader
.name
== "union") {
2872 } else if (reader
.name
== "glib:signal") {
2876 Report
.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader
.name
));
2884 end_element ("class");
2887 void parse_interface () {
2888 start_element ("interface");
2889 push_node (element_get_name (), true);
2892 if (current
.new_symbol
) {
2893 iface
= new
Interface (current
.name
, current
.source_reference
);
2894 current
.symbol
= iface
;
2896 iface
= (Interface
) current
.symbol
;
2899 set_type_id_ccode (iface
);
2901 iface
.access
= SymbolAccessibility
.PUBLIC
;
2902 iface
.external
= true;
2907 iface
.comment
= parse_symbol_doc ();
2909 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2910 if (!push_metadata ()) {
2915 if (reader
.name
== "prerequisite") {
2916 start_element ("prerequisite");
2917 iface
.add_prerequisite (parse_type_from_gir_name (reader
.get_attribute ("name")));
2919 end_element ("prerequisite");
2920 } else if (reader
.name
== "field") {
2922 } else if (reader
.name
== "property") {
2924 } else if (reader
.name
== "virtual-method") {
2925 parse_method ("virtual-method");
2926 } else if (reader
.name
== "function") {
2927 parse_method ("function");
2928 } else if (reader
.name
== "method") {
2929 parse_method ("method");
2930 } else if (reader
.name
== "glib:signal") {
2934 Report
.error (get_current_src (), "unknown child element `%s' in `interface'".printf (reader
.name
));
2942 end_element ("interface");
2945 void parse_field () {
2946 start_element ("field");
2947 push_node (element_get_name (), false);
2949 string nullable
= reader
.get_attribute ("nullable");
2950 string allow_none
= reader
.get_attribute ("allow-none");
2953 var comment
= parse_symbol_doc ();
2955 bool no_array_length
;
2956 bool array_null_terminated
;
2957 int array_length_idx
;
2958 var type
= parse_type (null, out array_length_idx
, true, out no_array_length
, out array_null_terminated
);
2959 type
= element_get_type (type
, true, ref no_array_length
, ref array_null_terminated
);
2961 string name
= current
.name
;
2962 string cname
= current
.girdata
["name"];
2964 var field
= new
Field (name
, type
, null, current
.source_reference
);
2965 field
.access
= SymbolAccessibility
.PUBLIC
;
2966 field
.comment
= comment
;
2967 if (name
!= cname
) {
2968 field
.set_attribute_string ("CCode", "cname", cname
);
2970 if (type is ArrayType
) {
2971 if (!no_array_length
&& array_length_idx
> -1) {
2972 current
.array_length_idx
= array_length_idx
;
2974 if (no_array_length
|| array_null_terminated
) {
2975 field
.set_attribute_bool ("CCode", "array_length", !no_array_length
);
2977 if (array_null_terminated
) {
2978 field
.set_attribute_bool ("CCode", "array_null_terminated", true);
2981 if (nullable
== "1" || allow_none
== "1") {
2982 type
.nullable
= true;
2984 current
.symbol
= field
;
2987 end_element ("field");
2990 Property
parse_property () {
2991 start_element ("property");
2992 push_node (element_get_name().replace ("-", "_"), false);
2993 bool is_abstract
= metadata
.get_bool (ArgumentType
.ABSTRACT
, current
.parent
.symbol is Interface
);
2994 string transfer
= reader
.get_attribute ("transfer-ownership");
2998 var comment
= parse_symbol_doc ();
3000 bool no_array_length
;
3001 bool array_null_terminated
;
3002 var type
= parse_type (null, null, transfer
!= "container", out no_array_length
, out array_null_terminated
);
3003 type
= element_get_type (type
, true, ref no_array_length
, ref array_null_terminated
);
3004 var prop
= new
Property (current
.name
, type
, null, null, current
.source_reference
);
3005 prop
.comment
= comment
;
3006 prop
.access
= SymbolAccessibility
.PUBLIC
;
3007 prop
.external
= true;
3008 prop
.is_abstract
= is_abstract
;
3009 if (no_array_length
|| array_null_terminated
) {
3010 prop
.set_attribute_bool ("CCode", "array_length", !no_array_length
);
3012 if (array_null_terminated
) {
3013 prop
.set_attribute_bool ("CCode", "array_null_terminated", true);
3015 current
.symbol
= prop
;
3018 end_element ("property");
3022 void parse_callback () {
3023 parse_function ("callback");
3026 void parse_constructor () {
3027 parse_function ("constructor");
3030 class ParameterInfo
{
3031 public ParameterInfo (Parameter param
, int array_length_idx
, int closure_idx
, int destroy_idx
, bool is_async
= false) {
3033 this
.array_length_idx
= array_length_idx
;
3034 this
.closure_idx
= closure_idx
;
3035 this
.destroy_idx
= destroy_idx
;
3036 this
.vala_idx
= 0.0F
;
3038 this
.is_async
= is_async
;
3041 public Parameter param
;
3042 public float vala_idx
;
3043 public int array_length_idx
;
3044 public int closure_idx
;
3045 public int destroy_idx
;
3047 public bool is_async
;
3050 void parse_function (string element_name
) {
3051 start_element (element_name
);
3052 push_node (element_get_name (reader
.get_attribute ("invoker")).replace ("-", "_"), false);
3055 if (metadata
.has_argument (ArgumentType
.SYMBOL_TYPE
)) {
3056 symbol_type
= metadata
.get_string (ArgumentType
.SYMBOL_TYPE
);
3058 symbol_type
= element_name
;
3061 string name
= current
.name
;
3062 string throws_string
= reader
.get_attribute ("throws");
3063 string invoker
= reader
.get_attribute ("invoker");
3067 var comment
= parse_symbol_doc ();
3069 DataType return_type
;
3070 string return_ctype
= null;
3071 int return_array_length_idx
= -1;
3072 bool return_no_array_length
= false;
3073 bool return_array_null_terminated
= false;
3074 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "return-value") {
3075 Comment? return_comment
;
3076 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
);
3077 if (return_comment
!= null) {
3078 if (comment
== null) {
3079 comment
= new
GirComment (null, current
.source_reference
);
3081 comment
.return_content
= return_comment
;
3084 return_type
= new
VoidType ();
3089 if (symbol_type
== "callback") {
3090 s
= new
Delegate (name
, return_type
, current
.source_reference
);
3091 ((Delegate
) s
).has_target
= false;
3092 } else if (symbol_type
== "constructor") {
3093 if (name
== "new") {
3095 } else if (name
.has_prefix ("new_")) {
3096 name
= name
.substring ("new_".length
);
3098 var m
= new
CreationMethod (null, name
, current
.source_reference
);
3099 m
.has_construct_function
= false;
3101 if (name
!= null && !current
.name
.has_prefix ("new_")) {
3102 m
.set_attribute_string ("CCode", "cname", current
.girdata
["c:identifier"]);
3105 string parent_ctype
= null;
3106 if (current
.parent
.symbol is Class
) {
3107 parent_ctype
= current
.parent
.get_cname ();
3109 if (return_ctype
!= null && (parent_ctype
== null || return_ctype
!= parent_ctype
+ "*")) {
3110 m
.set_attribute_string ("CCode", "type", return_ctype
);
3113 } else if (symbol_type
== "glib:signal") {
3114 s
= new
Signal (name
, return_type
, current
.source_reference
);
3116 s
= new
Method (name
, return_type
, current
.source_reference
);
3119 s
.access
= SymbolAccessibility
.PUBLIC
;
3120 s
.comment
= comment
;
3123 // Transform fixed-array properties of return-type into ccode-attribute
3124 var array_type
= return_type as ArrayType
;
3125 if (array_type
!= null && array_type
.fixed_length
) {
3126 s
.set_attribute_string ("CCode", "array_length_cexpr", ((IntegerLiteral
) array_type
.length
).value
);
3127 array_type
.fixed_length
= false;
3128 array_type
.length
= null;
3132 if (current
.girdata
["name"] != name
.replace ("_", "-")) {
3133 s
.set_attribute_string ("CCode", "cname", current
.girdata
["name"]);
3139 if (symbol_type
== "virtual-method" || symbol_type
== "callback") {
3140 if (current
.parent
.symbol is Interface
) {
3141 m
.is_abstract
= true;
3143 m
.is_virtual
= true;
3145 if (invoker
== null && !metadata
.has_argument (ArgumentType
.VFUNC_NAME
)) {
3146 s
.set_attribute ("NoWrapper", true, s
.source_reference
);
3147 } if (current
.girdata
["name"] != name
) {
3148 m
.set_attribute_string ("CCode", "vfunc_name", current
.girdata
["name"]);
3150 } else if (symbol_type
== "function") {
3151 m
.binding
= MemberBinding
.STATIC
;
3153 if (metadata
.has_argument (ArgumentType
.FLOATING
)) {
3154 m
.returns_floating_reference
= metadata
.get_bool (ArgumentType
.FLOATING
);
3155 m
.return_type
.value_owned
= true;
3159 if (s is Method
&& !(s is CreationMethod
)) {
3160 var method
= (Method
) s
;
3161 if (metadata
.has_argument (ArgumentType
.VIRTUAL
)) {
3162 method
.is_virtual
= metadata
.get_bool (ArgumentType
.VIRTUAL
);
3163 method
.is_abstract
= false;
3164 } else if (metadata
.has_argument (ArgumentType
.ABSTRACT
)) {
3165 method
.is_abstract
= metadata
.get_bool (ArgumentType
.ABSTRACT
);
3166 method
.is_virtual
= false;
3168 if (metadata
.has_argument (ArgumentType
.VFUNC_NAME
)) {
3169 method
.set_attribute_string ("CCode", "vfunc_name", metadata
.get_string (ArgumentType
.VFUNC_NAME
));
3170 method
.is_virtual
= true;
3172 if (metadata
.has_argument (ArgumentType
.FINISH_VFUNC_NAME
)) {
3173 method
.set_attribute_string ("CCode", "finish_vfunc_name", metadata
.get_string (ArgumentType
.FINISH_VFUNC_NAME
));
3174 method
.is_virtual
= true;
3178 if (!(metadata
.get_expression (ArgumentType
.THROWS
) is NullLiteral
)) {
3179 if (metadata
.has_argument (ArgumentType
.THROWS
)) {
3180 var error_types
= metadata
.get_string(ArgumentType
.THROWS
).split(",");
3181 foreach (var error_type
in error_types
) {
3182 s
.add_error_type (parse_type_from_string (error_type
, true, metadata
.get_source_reference (ArgumentType
.THROWS
)));
3184 } else if (throws_string
== "1") {
3185 s
.add_error_type (new
ErrorType (null, null));
3191 m
.set_attribute ("PrintfFormat", metadata
.get_bool (ArgumentType
.PRINTF_FORMAT
));
3192 if (metadata
.has_argument (ArgumentType
.SENTINEL
)) {
3193 m
.set_attribute_string ("CCode", "sentinel", metadata
.get_string (ArgumentType
.SENTINEL
));
3197 if (return_type is ArrayType
&& metadata
.has_argument (ArgumentType
.ARRAY_LENGTH_IDX
)) {
3198 return_array_length_idx
= metadata
.get_integer (ArgumentType
.ARRAY_LENGTH_IDX
);
3200 if (return_no_array_length
|| return_array_null_terminated
) {
3201 s
.set_attribute_bool ("CCode", "array_length", !return_no_array_length
);
3203 if (return_array_null_terminated
) {
3204 s
.set_attribute_bool ("CCode", "array_null_terminated", true);
3207 current
.return_array_length_idx
= return_array_length_idx
;
3211 if (metadata
.has_argument (ArgumentType
.FINISH_NAME
)) {
3212 s
.set_attribute_string ("CCode", "finish_name", metadata
.get_string (ArgumentType
.FINISH_NAME
));
3214 if (metadata
.has_argument (ArgumentType
.FINISH_INSTANCE
)) {
3215 s
.set_attribute_bool ("CCode", "finish_instance", metadata
.get_bool (ArgumentType
.FINISH_INSTANCE
));
3218 int instance_idx
= -2;
3219 if (element_name
== "function" && symbol_type
== "method") {
3220 if (metadata
.has_argument (ArgumentType
.INSTANCE_IDX
)) {
3221 instance_idx
= metadata
.get_integer (ArgumentType
.INSTANCE_IDX
);
3222 if (instance_idx
!= 0) {
3223 s
.set_attribute_double ("CCode", "instance_pos", instance_idx
+ 0.5);
3226 Report
.error (get_current_src (), "instance_idx required when converting function to method");
3230 var parameters
= new ArrayList
<ParameterInfo
> ();
3231 current
.array_length_parameters
= new ArrayList
<int> ();
3232 current
.closure_parameters
= new ArrayList
<int> ();
3233 current
.destroy_parameters
= new ArrayList
<int> ();
3234 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "parameters") {
3235 start_element ("parameters");
3238 var current_parameter_idx
= -1;
3239 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
3240 current_parameter_idx
++;
3242 if (reader
.name
== "instance-parameter" &&
3243 !(symbol_type
== "function" || symbol_type
== "constructor")) {
3248 if (instance_idx
> -2 && instance_idx
== current_parameter_idx
) {
3253 if (!push_metadata ()) {
3258 int array_length_idx
, closure_idx
, destroy_idx
;
3260 string default_param_name
= null;
3261 Comment? param_comment
;
3262 default_param_name
= "arg%d".printf (parameters
.size
);
3263 var param
= parse_parameter (out array_length_idx
, out closure_idx
, out destroy_idx
, out scope
, out param_comment
, default_param_name
);
3264 if (array_length_idx
!= -1) {
3265 if (instance_idx
> -2 && instance_idx
< array_length_idx
) {
3268 current
.array_length_parameters
.add (array_length_idx
);
3270 if (closure_idx
!= -1) {
3271 if (instance_idx
> -2 && instance_idx
< closure_idx
) {
3274 if (current
.closure_parameters
.index_of (current_parameter_idx
) < 0) {
3275 current
.closure_parameters
.add (closure_idx
);
3278 if (destroy_idx
!= -1) {
3279 if (instance_idx
> -2 && instance_idx
< destroy_idx
) {
3282 if (current
.destroy_parameters
.index_of (current_parameter_idx
) < 0) {
3283 current
.destroy_parameters
.add (destroy_idx
);
3286 if (param_comment
!= null) {
3287 if (comment
== null) {
3288 comment
= new
GirComment (null, s
.source_reference
);
3289 s
.comment
= comment
;
3292 comment
.add_content_for_parameter ((param
.ellipsis
)?
"..." : param
.name
, param_comment
);
3295 var info
= new
ParameterInfo (param
, array_length_idx
, closure_idx
, destroy_idx
, scope
== "async");
3297 if (s is Method
&& scope
== "async") {
3298 var unresolved_type
= param
.variable_type as UnresolvedType
;
3299 if (unresolved_type
!= null && unresolved_type
.unresolved_symbol
.name
== "AsyncReadyCallback") {
3300 // GAsync-style method
3301 ((Method
) s
).coroutine
= true;
3306 parameters
.add (info
);
3309 end_element ("parameters");
3311 current
.parameters
= parameters
;
3313 for (int param_n
= parameters
.size
- 1 ; param_n
>= 0 ; param_n
--) {
3314 ParameterInfo pi
= parameters
[param_n
];
3315 if (!pi
.param
.ellipsis
&& pi
.param
.initializer
== null) {
3316 string type_string
= pi
.param
.variable_type
.to_string ();
3317 if (type_string
== "Gio.Cancellable?") {
3318 pi
.param
.initializer
= new Vala
.NullLiteral ();
3326 end_element (element_name
);
3329 void parse_method (string element_name
) {
3330 parse_function (element_name
);
3333 void parse_signal () {
3334 parse_function ("glib:signal");
3337 void parse_boxed (string element_name
) {
3338 start_element (element_name
);
3339 string name
= reader
.get_attribute ("name");
3341 name
= reader
.get_attribute ("glib:name");
3343 push_node (element_get_name (name
), true);
3346 bool require_copy_free
= false;
3347 if (current
.new_symbol
) {
3348 cl
= new
Class (current
.name
, current
.source_reference
);
3349 cl
.is_compact
= true;
3350 current
.symbol
= cl
;
3352 cl
= (Class
) current
.symbol
;
3355 set_type_id_ccode (cl
);
3356 require_copy_free
= cl
.has_attribute_argument ("CCode", "type_id");
3358 cl
.access
= SymbolAccessibility
.PUBLIC
;
3361 if (metadata
.has_argument (ArgumentType
.BASE_TYPE
)) {
3362 cl
.add_base_type (parse_type_from_string (metadata
.get_string (ArgumentType
.BASE_TYPE
), true, metadata
.get_source_reference (ArgumentType
.BASE_TYPE
)));
3367 cl
.comment
= parse_symbol_doc ();
3369 Node? ref_method
= null;
3370 Node? unref_method
= null;
3372 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
3373 if (!push_metadata ()) {
3378 if (reader
.name
== "field") {
3380 } else if (reader
.name
== "constructor") {
3381 parse_constructor ();
3382 } else if (reader
.name
== "method") {
3383 parse_method ("method");
3384 var cname
= old_current
.get_cname ();
3385 if (cname
.has_suffix ("_ref") && (ref_method
== null || old_current
.name
== "ref")) {
3386 ref_method
= old_current
;
3387 } else if (cname
.has_suffix ("_unref") && (unref_method
== null || old_current
.name
== "unref")) {
3388 unref_method
= old_current
;
3390 } else if (reader
.name
== "function") {
3392 } else if (reader
.name
== "union") {
3396 Report
.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader
.name
));
3403 // Add ccode-attributes for ref/unref methodes if available
3404 // otherwise fallback to default g_boxed_copy/free
3405 if (cl
.has_attribute_argument ("CCode", "ref_function") || cl
.has_attribute_argument ("CCode", "unref_function")
3406 || cl
.has_attribute_argument ("CCode", "copy_function") || cl
.has_attribute_argument ("CCode", "free_function")) {
3408 } else if (ref_method
!= null && unref_method
!= null) {
3409 cl
.set_attribute_string ("CCode", "ref_function", ref_method
.get_cname ());
3410 cl
.set_attribute_string ("CCode", "unref_function", unref_method
.get_cname ());
3411 } else if (require_copy_free
) {
3412 cl
.set_attribute_string ("CCode", "copy_function", "g_boxed_copy");
3413 cl
.set_attribute_string ("CCode", "free_function", "g_boxed_free");
3417 end_element (element_name
);
3420 void parse_union () {
3421 start_element ("union");
3423 string? element_name
= element_get_name ();
3424 if (element_name
== null) {
3427 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
3428 if (!push_metadata ()) {
3433 if (reader
.name
== "field") {
3437 Report
.error (get_current_src (), "unknown child element `%s' in `transparent union'".printf (reader
.name
));
3444 end_element ("union");
3448 push_node (element_name
, true);
3451 if (current
.new_symbol
) {
3452 st
= new
Struct (reader
.get_attribute ("name"), current
.source_reference
);
3453 current
.symbol
= st
;
3455 st
= (Struct
) current
.symbol
;
3457 st
.access
= SymbolAccessibility
.PUBLIC
;
3462 st
.comment
= parse_symbol_doc ();
3464 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
3465 if (!push_metadata ()) {
3470 if (reader
.name
== "field") {
3472 } else if (reader
.name
== "constructor") {
3473 parse_constructor ();
3474 } else if (reader
.name
== "method") {
3475 parse_method ("method");
3476 } else if (reader
.name
== "function") {
3478 } else if (reader
.name
== "record") {
3482 Report
.error (get_current_src (), "unknown child element `%s' in `union'".printf (reader
.name
));
3490 end_element ("union");
3493 void parse_constant () {
3494 start_element ("constant");
3495 push_node (element_get_name (), false);
3499 var comment
= parse_symbol_doc ();
3501 var type
= parse_type ();
3502 var c
= new
Constant (current
.name
, type
, null, current
.source_reference
);
3504 c
.access
= SymbolAccessibility
.PUBLIC
;
3505 c
.comment
= comment
;
3509 end_element ("constant");
3513 void report_unused_metadata (Metadata metadata
) {
3514 if (metadata
== Metadata
.empty
) {
3518 if (metadata
.args
.size
== 0 && metadata
.children
.size
== 0) {
3519 Report
.warning (metadata
.source_reference
, "empty metadata");
3523 foreach (var arg_type
in metadata
.args
.get_keys ()) {
3524 var arg
= metadata
.args
[arg_type
];
3526 // if metadata is used and argument is not, then it's a unexpected argument
3527 Report
.warning (arg
.source_reference
, "argument never used");
3531 foreach (var child
in metadata
.children
) {
3533 Report
.warning (child
.source_reference
, "metadata never used");
3535 report_unused_metadata (child
);
3542 void resolve_gir_symbols () {
3543 // gir has simple namespaces, we won't get deeper than 2 levels here, except reparenting
3544 foreach (var map_from
in unresolved_gir_symbols
) {
3545 while (map_from
!= null) {
3546 var map_to
= unresolved_symbols_map
[map_from
];
3547 if (map_to
!= null) {
3548 // remap the original symbol to match the target
3549 map_from
.inner
= null;
3550 map_from
.name
= map_to
.name
;
3551 if (map_to is UnresolvedSymbol
) {
3552 var umap_to
= (UnresolvedSymbol
) map_to
;
3553 while (umap_to
.inner
!= null) {
3554 umap_to
= umap_to
.inner
;
3555 map_from
.inner
= new
UnresolvedSymbol (null, umap_to
.name
);
3556 map_from
= map_from
.inner
;
3559 while (map_to
.parent_symbol
!= null && map_to
.parent_symbol
!= context
.root
) {
3560 map_to
= map_to
.parent_symbol
;
3561 map_from
.inner
= new
UnresolvedSymbol (null, map_to
.name
);
3562 map_from
= map_from
.inner
;
3567 map_from
= map_from
.inner
;
3572 void create_new_namespaces () {
3573 foreach (var node
in Node
.new_namespaces
) {
3574 if (node
.symbol
== null) {
3575 node
.symbol
= new
Namespace (node
.name
, node
.source_reference
);
3580 void resolve_type_arguments () {
3581 // box structs in type arguments
3582 foreach (var element_type
in unresolved_type_arguments
) {
3583 TypeSymbol sym
= null;
3584 if (element_type is UnresolvedType
) {
3585 sym
= (TypeSymbol
) resolve_symbol (root
, ((UnresolvedType
) element_type
).unresolved_symbol
);
3586 } else if (element_type
.data_type
!= null) {
3587 sym
= element_type
.data_type
;
3589 var st
= sym as Struct
;
3590 if (st
!= null && !st
.is_integer_type () && !st
.is_floating_type ()) {
3591 element_type
.nullable
= true;
3596 void process_interface (Node iface_node
) {
3597 /* Temporarily workaround G-I bug not adding GLib.Object prerequisite:
3598 ensure we have at least one instantiable prerequisite */
3599 Interface iface
= (Interface
) iface_node
.symbol
;
3600 bool has_instantiable_prereq
= false;
3601 foreach (DataType prereq
in iface
.get_prerequisites ()) {
3603 if (prereq is UnresolvedType
) {
3604 var unresolved_symbol
= ((UnresolvedType
) prereq
).unresolved_symbol
;
3605 sym
= resolve_symbol (iface_node
.parent
, unresolved_symbol
);
3607 sym
= prereq
.data_type
;
3610 has_instantiable_prereq
= true;
3615 if (!has_instantiable_prereq
) {
3616 iface
.add_prerequisite (new
ObjectType ((ObjectTypeSymbol
) glib_ns
.scope
.lookup ("Object")));
3620 void process_alias (Node alias
) {
3621 /* this is unfortunate because <alias> tag has no type information, thus we have
3622 to guess it from the base type */
3623 DataType base_type
= null;
3624 Symbol type_sym
= null;
3625 Node base_node
= null;
3626 bool simple_type
= false;
3627 if (alias
.base_type is UnresolvedType
) {
3628 base_type
= alias
.base_type
;
3629 base_node
= resolve_node (alias
.parent
, ((UnresolvedType
) base_type
).unresolved_symbol
);
3630 if (base_node
!= null) {
3631 type_sym
= base_node
.symbol
;
3633 } else if (alias
.base_type is PointerType
&& ((PointerType
) alias
.base_type
).base_type is VoidType
) {
3634 // gpointer, if it's a struct make it a simpletype
3637 base_type
= alias
.base_type
;
3638 type_sym
= base_type
.data_type
;
3639 if (type_sym
!= null) {
3640 base_node
= resolve_node (alias
.parent
, parse_symbol_from_string (type_sym
.get_full_name (), alias
.source_reference
));
3644 if (type_sym is Struct
&& ((Struct
) type_sym
).is_simple_type ()) {
3648 if (base_type
== null || type_sym
== null || type_sym is Struct
) {
3649 var st
= new
Struct (alias
.name
, alias
.source_reference
);
3650 st
.access
= SymbolAccessibility
.PUBLIC
;
3651 if (base_type
!= null) {
3652 // threat target="none" as a new struct
3653 st
.base_type
= base_type
;
3655 st
.comment
= alias
.comment
;
3657 st
.set_simple_type (simple_type
);
3659 } else if (type_sym is Class
) {
3660 var cl
= new
Class (alias
.name
, alias
.source_reference
);
3661 cl
.access
= SymbolAccessibility
.PUBLIC
;
3662 if (base_type
!= null) {
3663 cl
.add_base_type (base_type
);
3665 cl
.comment
= alias
.comment
;
3667 cl
.is_compact
= ((Class
) type_sym
).is_compact
;
3669 } else if (type_sym is Interface
) {
3670 // this is not a correct alias, but what can we do otherwise?
3671 var iface
= new
Interface (alias
.name
, alias
.source_reference
);
3672 iface
.access
= SymbolAccessibility
.PUBLIC
;
3673 if (base_type
!= null) {
3674 iface
.add_prerequisite (base_type
);
3676 iface
.comment
= alias
.comment
;
3677 iface
.external
= true;
3678 alias
.symbol
= iface
;
3679 } else if (type_sym is Delegate
) {
3680 var orig
= (Delegate
) type_sym
;
3681 if (base_node
!= null) {
3682 base_node
.process (this
);
3683 orig
= (Delegate
) base_node
.symbol
;
3686 var deleg
= new
Delegate (alias
.name
, orig
.return_type
.copy (), alias
.source_reference
);
3687 deleg
.access
= orig
.access
;
3689 foreach (var param
in orig
.get_parameters ()) {
3690 deleg
.add_parameter (param
.copy ());
3693 foreach (var error_type
in orig
.get_error_types ()) {
3694 deleg
.add_error_type (error_type
.copy ());
3697 foreach (var attribute
in orig
.attributes
) {
3698 deleg
.attributes
.append (attribute
);
3701 deleg
.external
= true;
3703 alias
.symbol
= deleg
;
3706 // inherit atributes, like type_id
3707 if (type_sym is Class
|| (type_sym is Struct
&& !simple_type
)) {
3708 if (type_sym
.has_attribute_argument ("CCode", "has_type_id")) {
3709 alias
.symbol
.set_attribute_bool ("CCode", "has_type_id", type_sym
.get_attribute_bool ("CCode", "has_type_id"));
3710 } else if (type_sym
.has_attribute_argument ("CCode", "type_id")) {
3711 alias
.symbol
.set_attribute_string ("CCode", "type_id", type_sym
.get_attribute_string ("CCode", "type_id"));
3716 void process_callable (Node node
) {
3717 if (node
.element_type
== "alias" && node
.symbol is Delegate
) {
3718 // processed in parse_alias
3722 var s
= node
.symbol
;
3723 List
<ParameterInfo
> parameters
= node
.parameters
;
3725 DataType return_type
= null;
3726 if (s is Callable
) {
3727 return_type
= ((Callable
) s
).return_type
;
3730 if (return_type is ArrayType
&& node
.return_array_length_idx
>= 0) {
3731 if (node
.return_array_length_idx
>= parameters
.size
) {
3732 Report
.error (return_type
.source_reference
, "invalid array length index");
3734 parameters
[node
.return_array_length_idx
].keep
= false;
3735 node
.array_length_parameters
.add (node
.return_array_length_idx
);
3737 } else if (return_type is VoidType
&& parameters
.size
> 0) {
3738 int n_out_parameters
= 0;
3739 foreach (var info
in parameters
) {
3740 if (info
.param
.direction
== ParameterDirection
.OUT
) {
3745 if (n_out_parameters
== 1) {
3746 ParameterInfo last_param
= parameters
[parameters
.size
-1];
3747 if (last_param
.param
.direction
== ParameterDirection
.OUT
) {
3748 // use last out real-non-null-struct parameter as return type
3749 if (last_param
.param
.variable_type is UnresolvedType
) {
3750 var st
= resolve_symbol (node
.parent
, ((UnresolvedType
) last_param
.param
.variable_type
).unresolved_symbol
) as Struct
;
3751 if (st
!= null && !st
.is_simple_type () && !last_param
.param
.variable_type
.nullable
) {
3752 if (!node
.metadata
.get_bool (ArgumentType
.RETURN_VOID
, false)) {
3753 last_param
.keep
= false;
3754 return_type
= last_param
.param
.variable_type
.copy ();
3761 if (return_type is UnresolvedType
&& !return_type
.nullable
) {
3762 var st
= resolve_symbol (node
.parent
, ((UnresolvedType
) return_type
).unresolved_symbol
) as Struct
;
3764 bool is_simple_type
= false;
3765 Struct? base_st
= st
;
3767 while (base_st
!= null) {
3768 if (base_st
.is_simple_type ()) {
3769 is_simple_type
= true;
3773 if (base_st
.base_type is UnresolvedType
) {
3774 base_st
= resolve_symbol (node
.parent
, ((UnresolvedType
) base_st
.base_type
).unresolved_symbol
) as Struct
;
3776 base_st
= base_st
.base_struct
;
3780 if (!is_simple_type
) {
3781 return_type
.nullable
= true;
3787 // Do not mark out-parameters as nullable if they are simple-types,
3788 // since it would result in a boxed-type in vala
3789 foreach (ParameterInfo info
in parameters
) {
3790 var type
= info
.param
.variable_type
;
3791 if (info
.param
.direction
== ParameterDirection
.OUT
&& type
.nullable
) {
3793 if (type is UnresolvedType
) {
3794 st
= resolve_symbol (node
.parent
, ((UnresolvedType
) type
).unresolved_symbol
) as Struct
;
3795 } else if (type is ValueType
) {
3796 st
= type
.data_type as Struct
;
3798 if (st
!= null && st
.is_simple_type ()) {
3799 type
.nullable
= false;
3804 if (parameters
.size
> 1) {
3805 ParameterInfo last_param
= parameters
[parameters
.size
-1];
3806 if (last_param
.param
.ellipsis
) {
3807 var first_vararg_param
= parameters
[parameters
.size
-2];
3808 if (first_vararg_param
.param
.name
.has_prefix ("first_")) {
3809 first_vararg_param
.keep
= false;
3817 foreach (ParameterInfo info
in parameters
) {
3818 if (s is Delegate
&& info
.closure_idx
== i
) {
3819 var d
= (Delegate
) s
;
3820 d
.has_target
= true;
3821 d
.set_attribute_double ("CCode", "instance_pos", j
- 0.1);
3823 } else if (info
.keep
3824 && !node
.array_length_parameters
.contains (i
)
3825 && !node
.closure_parameters
.contains (i
)
3826 && !node
.destroy_parameters
.contains (i
)) {
3827 info
.vala_idx
= (float) j
;
3830 /* interpolate for vala_idx between this and last*/
3831 float last_idx
= 0.0F
;
3833 last_idx
= parameters
[last
].vala_idx
;
3835 for (int k
=last
+1; k
< i
; k
++) {
3836 parameters
[k
].vala_idx
= last_idx
+ (((j
- last_idx
) / (i
-last
)) * (k
-last
));
3842 // make sure that vala_idx is always set
3843 // the above if branch does not set vala_idx for
3844 // hidden parameters at the end of the parameter list
3845 info
.vala_idx
= (j
- 1) + (i
- last
) * 0.1F
;
3850 foreach (ParameterInfo info
in parameters
) {
3855 /* add_parameter sets carray_length_parameter_position and cdelegate_target_parameter_position
3857 if (s is Callable
) {
3858 ((Callable
) s
).add_parameter (info
.param
);
3861 if (info
.array_length_idx
!= -1) {
3862 if ((info
.array_length_idx
) >= parameters
.size
) {
3863 Report
.error (info
.param
.source_reference
, "invalid array_length index");
3866 set_array_ccode (info
.param
, parameters
[info
.array_length_idx
]);
3869 if (info
.closure_idx
!= -1) {
3870 if ((info
.closure_idx
) >= parameters
.size
) {
3871 Report
.error (info
.param
.source_reference
, "invalid closure index");
3874 if ("%g".printf (parameters
[info
.closure_idx
].vala_idx
) != "%g".printf (info
.vala_idx
+ 0.1)) {
3875 info
.param
.set_attribute_double ("CCode", "delegate_target_pos", parameters
[info
.closure_idx
].vala_idx
);
3878 if (info
.destroy_idx
!= -1) {
3879 if (info
.destroy_idx
>= parameters
.size
) {
3880 Report
.error (info
.param
.source_reference
, "invalid destroy index");
3883 if ("%g".printf (parameters
[info
.destroy_idx
].vala_idx
) != "%g".printf (info
.vala_idx
+ 0.2)) {
3884 info
.param
.set_attribute_double ("CCode", "destroy_notify_pos", parameters
[info
.destroy_idx
].vala_idx
);
3888 if (info
.is_async
) {
3889 var resolved_type
= info
.param
.variable_type
;
3890 if (resolved_type is UnresolvedType
) {
3891 var resolved_symbol
= resolve_symbol (node
.parent
, ((UnresolvedType
) resolved_type
).unresolved_symbol
);
3892 if (resolved_symbol is Delegate
) {
3893 resolved_type
= new
DelegateType ((Delegate
) resolved_symbol
);
3897 if (resolved_type is DelegateType
) {
3898 var d
= ((DelegateType
) resolved_type
).delegate_symbol
;
3899 if (!(d
.name
== "DestroyNotify" && d
.parent_symbol
.name
== "GLib")) {
3900 info
.param
.set_attribute_string ("CCode", "scope", "async");
3901 info
.param
.variable_type
.value_owned
= (info
.closure_idx
!= -1 && info
.destroy_idx
!= -1);
3905 var resolved_type
= info
.param
.variable_type
;
3906 if (resolved_type is DelegateType
) {
3907 info
.param
.variable_type
.value_owned
= (info
.closure_idx
!= -1 && info
.destroy_idx
!= -1);
3912 if (return_type is ArrayType
&& node
.return_array_length_idx
>= 0) {
3913 set_array_ccode (s
, parameters
[node
.return_array_length_idx
]);
3916 if (s is Callable
) {
3917 ((Callable
) s
).return_type
= return_type
;
3921 void find_parent (string cname
, Node current
, ref Node best
, ref int match
) {
3922 var old_best
= best
;
3923 if (current
.symbol is Namespace
) {
3924 foreach (var child
in current
.members
) {
3925 // symbol is null only for aliases that aren't yet processed
3926 if ((child
.symbol
== null || is_container (child
.symbol
)) && cname
.has_prefix (child
.get_lower_case_cprefix ())) {
3927 find_parent (cname
, child
, ref best
, ref match
);
3931 if (best
!= old_best
) {
3936 var current_match
= current
.get_lower_case_cprefix().length
;
3937 if (current_match
> match
) {
3938 match
= current_match
;
3943 bool same_gir (Symbol gir_component
, Symbol sym
) {
3944 var gir_name
= gir_component
.source_reference
.file
.gir_namespace
;
3945 var gir_version
= gir_component
.source_reference
.file
.gir_version
;
3946 return "%s-%s".printf (gir_name
, gir_version
) in sym
.source_reference
.file
.filename
;
3949 void process_namespace_method (Node ns
, Node node
) {
3950 /* transform static methods into instance methods if possible.
3951 In most of cases this is a .gir fault we are going to fix */
3953 var ns_cprefix
= ns
.get_lower_case_cprefix ();
3954 var method
= (Method
) node
.symbol
;
3955 var cname
= node
.get_cname ();
3957 Parameter first_param
= null;
3958 if (node
.parameters
.size
> 0) {
3959 first_param
= node
.parameters
[0].param
;
3961 if (first_param
!= null && first_param
.direction
== ParameterDirection
.IN
&& first_param
.variable_type is UnresolvedType
) {
3962 // check if it's a missed instance method (often happens for structs)
3963 var sym
= ((UnresolvedType
) first_param
.variable_type
).unresolved_symbol
;
3964 var parent
= resolve_node (ns
, sym
);
3965 if (parent
!= null && same_gir (method
, parent
.symbol
) && parent
.parent
== ns
&& is_container (parent
.symbol
) && cname
.has_prefix (parent
.get_lower_case_cprefix ())) {
3967 var new_name
= method
.name
.substring (parent
.get_lower_case_cprefix().length
- ns_cprefix
.length
);
3968 if (parent
.lookup (new_name
) == null) {
3969 ns
.remove_member (node
);
3970 node
.name
= new_name
;
3971 node
.parameters
.remove_at (0);
3972 method
.name
= new_name
;
3973 method
.binding
= MemberBinding
.INSTANCE
;
3974 parent
.add_member (node
);
3982 find_parent (cname
, ns
, ref parent
, ref match
);
3983 var new_name
= method
.name
.substring (parent
.get_lower_case_cprefix().length
- ns_cprefix
.length
);
3984 if (same_gir (method
, parent
.symbol
) && parent
.lookup (new_name
) == null) {
3985 ns
.remove_member (node
);
3986 node
.name
= new_name
;
3987 method
.name
= new_name
;
3988 parent
.add_member (node
);
3992 void process_virtual_method_field (Node node
, Delegate d
, UnresolvedSymbol gtype_struct_for
) {
3993 var gtype_node
= resolve_node (node
.parent
, gtype_struct_for
);
3994 if (gtype_node
== null || !(gtype_node
.symbol is ObjectTypeSymbol
)) {
3995 Report
.error (gtype_struct_for
.source_reference
, "Unknown symbol `%s' for virtual method field `%s'".printf (gtype_struct_for
.to_string (), node
.to_string ()));
3997 var nodes
= gtype_node
.lookup_all (d
.name
);
3998 if (nodes
== null) {
4001 foreach (var n
in nodes
) {
4006 foreach (var n
in nodes
) {
4011 if (sym is Signal
) {
4012 var sig
= (Signal
) sym
;
4013 sig
.is_virtual
= true;
4014 assume_parameter_names (sig
, d
, true);
4015 } else if (sym is Property
) {
4016 var prop
= (Property
) sym
;
4017 prop
.is_virtual
= true;
4022 void process_async_method (Node node
) {
4023 var m
= (Method
) node
.symbol
;
4024 string finish_method_base
;
4025 if (m
.name
== null) {
4026 assert (m is CreationMethod
);
4027 finish_method_base
= "new";
4028 } else if (m
.name
.has_suffix ("_async")) {
4029 finish_method_base
= m
.name
.substring (0, m
.name
.length
- "_async".length
);
4031 finish_method_base
= m
.name
;
4033 var finish_method_node
= node
.parent
.lookup (finish_method_base
+ "_finish");
4035 // check if the method is using non-standard finish method name
4036 if (finish_method_node
== null) {
4037 var method_cname
= node
.get_finish_cname ();
4038 foreach (var n
in node
.parent
.members
) {
4039 if (n
.symbol is Method
&& n
.get_cname () == method_cname
) {
4040 finish_method_node
= n
;
4048 if (finish_method_node
!= null && finish_method_node
.symbol is Method
) {
4049 finish_method_node
.process (this
);
4050 var finish_method
= (Method
) finish_method_node
.symbol
;
4051 if (finish_method is CreationMethod
) {
4052 method
= new
CreationMethod (((CreationMethod
) finish_method
).class_name
, null, m
.source_reference
);
4053 method
.access
= m
.access
;
4054 method
.binding
= m
.binding
;
4055 method
.external
= true;
4056 method
.coroutine
= true;
4057 method
.has_construct_function
= finish_method
.has_construct_function
;
4059 // cannot use List.copy()
4060 // as it returns a list of unowned elements
4061 foreach (Attribute a
in m
.attributes
) {
4062 method
.attributes
.append (a
);
4065 method
.set_attribute_string ("CCode", "cname", node
.get_cname ());
4066 if (finish_method_base
== "new") {
4068 } else if (finish_method_base
.has_prefix ("new_")) {
4069 method
.name
= m
.name
.substring ("new_".length
);
4071 foreach (var param
in m
.get_parameters ()) {
4072 method
.add_parameter (param
);
4074 node
.symbol
= method
;
4076 method
.return_type
= finish_method
.return_type
.copy ();
4077 var a
= finish_method
.get_attribute ("CCode");
4078 if (a
!= null && a
.has_argument ("array_length")) {
4079 method
.set_attribute_bool ("CCode", "array_length", a
.get_bool ("array_length"));
4081 if (a
!= null && a
.has_argument ("array_null_terminated")) {
4082 method
.set_attribute_bool ("CCode", "array_null_terminated", a
.get_bool ("array_null_terminated"));
4086 foreach (var param
in finish_method
.get_parameters ()) {
4087 if (param
.direction
== ParameterDirection
.OUT
) {
4088 var async_param
= param
.copy ();
4089 if (method
.scope
.lookup (param
.name
) != null) {
4090 // parameter name conflict
4091 async_param
.name
+= "_out";
4093 method
.add_parameter (async_param
);
4097 foreach (DataType error_type
in finish_method
.get_error_types ()) {
4098 method
.add_error_type (error_type
.copy ());
4100 finish_method_node
.processed
= true;
4101 finish_method_node
.merged
= true;
4105 /* Hash and equal functions */
4107 static uint unresolved_symbol_hash (UnresolvedSymbol? sym
) {
4108 var builder
= new
StringBuilder ();
4109 while (sym
!= null) {
4110 builder
.append (sym
.name
);
4113 return builder
.str
.hash ();
4116 static bool unresolved_symbol_equal (UnresolvedSymbol? sym1
, UnresolvedSymbol? sym2
) {
4117 while (sym1
!= sym2
) {
4118 if (sym1
== null || sym2
== null) {
4121 if (sym1
.name
!= sym2
.name
) {
4130 /* Helper methods */
4132 Node?
base_interface_property (Node prop_node
) {
4133 var cl
= prop_node
.parent
.symbol as Class
;
4138 foreach (DataType type
in cl
.get_base_types ()) {
4139 if (!(type is UnresolvedType
)) {
4143 var base_node
= resolve_node (prop_node
.parent
, ((UnresolvedType
) type
).unresolved_symbol
);
4144 if (base_node
!= null && base_node
.symbol is Interface
) {
4145 var base_prop_node
= base_node
.lookup (prop_node
.name
);
4146 if (base_prop_node
!= null && base_prop_node
.symbol is Property
) {
4147 var base_property
= (Property
) base_prop_node
.symbol
;
4148 if (base_property
.is_abstract
|| base_property
.is_virtual
) {
4150 return base_prop_node
;