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
,
91 public static ArgumentType?
from_string (string name
) {
92 var enum_class
= (EnumClass
) typeof(ArgumentType
).class_ref ();
93 var nick
= name
.replace ("_", "-");
94 unowned GLib
.EnumValue? enum_value
= enum_class
.get_value_by_nick (nick
);
95 if (enum_value
!= null) {
96 ArgumentType value
= (ArgumentType
) enum_value
.value
;
104 public Expression expression
;
105 public SourceReference source_reference
;
107 public bool used
= false;
109 public Argument (Expression expression
, SourceReference? source_reference
= null) {
110 this
.expression
= expression
;
111 this
.source_reference
= source_reference
;
115 class MetadataSet
: Metadata
{
116 public MetadataSet (string? selector
= null) {
120 public void add_sibling (Metadata metadata
) {
121 foreach (var child
in metadata
.children
) {
124 // merge arguments and take precedence
125 foreach (var key
in metadata
.args
.get_keys ()) {
126 args
[key
] = metadata
.args
[key
];
132 private static Metadata _empty
= null;
133 public static Metadata empty
{
135 if (_empty
== null) {
136 _empty
= new
Metadata ("");
142 public PatternSpec pattern_spec
;
143 public string? selector
;
144 public SourceReference source_reference
;
146 public bool used
= false;
147 public Vala
.Map
<ArgumentType
,Argument
> args
= new HashMap
<ArgumentType
,Argument
> ();
148 public ArrayList
<Metadata
> children
= new ArrayList
<Metadata
> ();
150 public Metadata (string pattern
, string? selector
= null, SourceReference? source_reference
= null) {
151 this
.pattern_spec
= new
PatternSpec (pattern
);
152 this
.selector
= selector
;
153 this
.source_reference
= source_reference
;
156 public void add_child (Metadata metadata
) {
157 children
.add (metadata
);
160 public Metadata
match_child (string name
, string? selector
= null) {
161 var result
= Metadata
.empty
;
162 foreach (var metadata
in children
) {
163 if ((selector
== null || metadata
.selector
== null || metadata
.selector
== selector
) && metadata
.pattern_spec
.match_string (name
)) {
164 metadata
.used
= true;
165 if (result
== Metadata
.empty
) {
169 var ms
= result as MetadataSet
;
172 ms
= new
MetadataSet (selector
);
173 ms
.add_sibling (result
);
175 ms
.add_sibling (metadata
);
183 public void add_argument (ArgumentType key
, Argument value
) {
184 args
.set (key
, value
);
187 public bool has_argument (ArgumentType key
) {
188 return args
.contains (key
);
191 public Expression?
get_expression (ArgumentType arg
) {
192 var val
= args
.get (arg
);
195 return val
.expression
;
200 public string?
get_string (ArgumentType arg
) {
201 var lit
= get_expression (arg
) as StringLiteral
;
208 public int get_integer (ArgumentType arg
) {
209 var unary
= get_expression (arg
) as UnaryExpression
;
210 if (unary
!= null && unary
.operator
== UnaryOperator
.MINUS
) {
211 var lit
= unary
.inner as IntegerLiteral
;
213 return -int.parse (lit
.value
);
216 var lit
= get_expression (arg
) as IntegerLiteral
;
218 return int.parse (lit
.value
);
225 public bool get_bool (ArgumentType arg
, bool default_value
= false) {
226 var lit
= get_expression (arg
) as BooleanLiteral
;
230 return default_value
;
233 public SourceReference?
get_source_reference (ArgumentType arg
) {
234 var val
= args
.get (arg
);
236 return val
.source_reference
;
242 class MetadataParser
{
245 * metadata ::= [ rule [ '\n' relativerule ]* ]
246 * rule ::= pattern ' ' [ args ]
247 * relativerule ::= '.' rule
248 * pattern ::= glob [ '#' selector ] [ '.' pattern ]
250 private Metadata tree
= new
Metadata ("");
251 private Scanner scanner
;
252 private SourceLocation begin
;
253 private SourceLocation end
;
254 private SourceLocation old_end
;
255 private TokenType current
;
256 private Metadata parent_metadata
;
258 public MetadataParser () {
262 SourceReference
get_current_src () {
263 return new
SourceReference (scanner
.source_file
, begin
, end
);
266 SourceReference
get_src (SourceLocation begin
, SourceLocation? end
= null) {
271 return new
SourceReference (scanner
.source_file
, begin
, e
);
274 public Metadata
parse_metadata (SourceFile metadata_file
) {
275 scanner
= new
Scanner (metadata_file
);
277 while (current
!= TokenType
.EOF
) {
278 if (!parse_rule ()) {
279 return Metadata
.empty
;
287 current
= scanner
.read_token (out begin
, out end
);
292 return old_end
.pos
!= begin
.pos
;
295 bool has_newline () {
296 return old_end
.line
!= begin
.line
;
299 string get_string (SourceLocation? begin
= null, SourceLocation? end
= null) {
308 return ((string) b
.pos
).substring (0, (int) (e
.pos
- b
.pos
));
311 string?
parse_identifier (bool is_glob
) {
312 var begin
= this
.begin
;
314 if (current
== TokenType
.DOT
|| current
== TokenType
.HASH
) {
316 Report
.error (get_src (begin
), "expected glob-style pattern");
318 Report
.error (get_src (begin
), "expected identifier");
324 while (current
!= TokenType
.EOF
&& current
!= TokenType
.DOT
&& current
!= TokenType
.HASH
) {
334 return get_string (begin
, old_end
);
337 string?
parse_selector () {
338 if (current
!= TokenType
.HASH
|| has_space ()) {
343 return parse_identifier (false);
346 Metadata?
parse_pattern () {
348 bool is_relative
= false;
349 if (current
== TokenType
.IDENTIFIER
|| current
== TokenType
.STAR
) {
351 parent_metadata
= tree
;
354 if (current
!= TokenType
.DOT
) {
355 Report
.error (get_current_src (), "expected pattern or `.', got %s".printf (current
.to_string ()));
362 if (parent_metadata
== null) {
363 Report
.error (get_current_src (), "cannot determinate parent metadata");
367 SourceLocation begin
= this
.begin
;
368 var pattern
= parse_identifier (true);
369 if (pattern
== null) {
372 metadata
= new
Metadata (pattern
, parse_selector (), get_src (begin
));
373 parent_metadata
.add_child (metadata
);
375 while (current
!= TokenType
.EOF
&& !has_space ()) {
376 if (current
!= TokenType
.DOT
) {
377 Report
.error (get_current_src (), "expected `.' got %s".printf (current
.to_string ()));
383 pattern
= parse_identifier (true);
384 if (pattern
== null) {
387 var child
= new
Metadata (pattern
, parse_selector (), get_src (begin
, old_end
));
388 metadata
.add_child (child
);
392 parent_metadata
= metadata
;
398 Expression?
parse_expression () {
399 var begin
= this
.begin
;
400 var src
= get_current_src ();
401 Expression expr
= null;
404 expr
= new
NullLiteral (src
);
407 expr
= new
BooleanLiteral (true, src
);
409 case TokenType
.FALSE
:
410 expr
= new
BooleanLiteral (false, src
);
412 case TokenType
.MINUS
:
414 var inner
= parse_expression ();
416 Report
.error (src
, "expected expression after `-', got %s".printf (current
.to_string ()));
418 expr
= new
UnaryExpression (UnaryOperator
.MINUS
, inner
, get_src (begin
));
421 case TokenType
.INTEGER_LITERAL
:
422 expr
= new
IntegerLiteral (get_string (), src
);
424 case TokenType
.REAL_LITERAL
:
425 expr
= new
RealLiteral (get_string (), src
);
427 case TokenType
.STRING_LITERAL
:
428 expr
= new
StringLiteral (get_string (), src
);
430 case TokenType
.IDENTIFIER
:
431 expr
= new
MemberAccess (null, get_string (), src
);
432 while (next () == TokenType
.DOT
) {
433 if (next () != TokenType
.IDENTIFIER
) {
434 Report
.error (get_current_src (), "expected identifier got %s".printf (current
.to_string ()));
437 expr
= new
MemberAccess (expr
, get_string (), get_current_src ());
440 case TokenType
.OPEN_PARENS
:
441 // empty tuple => no expression
442 if (next () != TokenType
.CLOSE_PARENS
) {
443 Report
.error (get_current_src (), "expected `)', got %s".printf (current
.to_string ()));
446 expr
= new
Tuple (src
);
449 Report
.error (src
, "expected literal or symbol got %s".printf (current
.to_string ()));
456 bool parse_args (Metadata metadata
) {
457 while (current
!= TokenType
.EOF
&& has_space () && !has_newline ()) {
458 SourceLocation begin
= this
.begin
;
459 var id
= parse_identifier (false);
463 var arg_type
= ArgumentType
.from_string (id
);
464 if (arg_type
== null) {
465 Report
.warning (get_src (begin
, old_end
), "unknown argument `%s'".printf (id
));
469 if (current
!= TokenType
.ASSIGN
) {
471 metadata
.add_argument (arg_type
, new
Argument (new
BooleanLiteral (true, get_src (begin
)), get_src (begin
)));
476 Expression expr
= parse_expression ();
480 metadata
.add_argument (arg_type
, new
Argument (expr
, get_src (begin
)));
488 var metadata
= parse_pattern ();
489 if (metadata
== null) {
493 if (current
== TokenType
.EOF
|| old_end
.line
!= end
.line
) {
497 return parse_args (metadata
);
506 public static ArrayList
<Node
> new_namespaces
= new ArrayList
<Node
> ();
508 public weak Node parent
;
509 public string element_type
;
511 public Map
<string,string> girdata
= null;
512 public Metadata metadata
= Metadata
.empty
;
513 public SourceReference source_reference
= null;
514 public ArrayList
<Node
> members
= new ArrayList
<Node
> (); // guarantees fields order
515 public HashMap
<string, ArrayList
<Node
>> scope
= new HashMap
<string, ArrayList
<Node
>> (str_hash
, str_equal
);
517 public GirComment comment
;
518 public Symbol symbol
;
519 public bool new_symbol
;
521 public bool processed
;
524 public int return_array_length_idx
= -1;
525 public List
<ParameterInfo
> parameters
;
526 public ArrayList
<int> array_length_parameters
;
527 public ArrayList
<int> closure_parameters
;
528 public ArrayList
<int> destroy_parameters
;
530 public UnresolvedSymbol gtype_struct_for
;
532 public DataType base_type
;
534 public int array_length_idx
= -1;
536 public bool deprecated
= false;
537 public uint64 deprecated_version
= 0;
538 public string? deprecated_since
= null;
539 public string? deprecated_replacement
= null;
541 public Node (string? name
) {
545 public void add_member (Node node
) {
546 var nodes
= scope
[node
.name
];
548 nodes
= new ArrayList
<Node
> ();
549 scope
[node
.name
] = nodes
;
556 public void remove_member (Node node
) {
557 var nodes
= scope
[node
.name
];
559 if (nodes
.size
== 0) {
560 scope
.remove (node
.name
);
562 members
.remove (node
);
566 public Node?
lookup (string name
, bool create_namespace
= false, SourceReference? source_reference
= null) {
567 var nodes
= scope
[name
];
574 if (symbol
!= null) {
575 sym
= symbol
.scope
.lookup (name
);
577 if (sym
!= null || create_namespace
) {
578 node
= new
Node (name
);
580 node
.new_symbol
= node
.symbol
== null;
581 node
.source_reference
= source_reference
;
585 new_namespaces
.add (node
);
592 public ArrayList
<Node
>?
lookup_all (string name
) {
596 public UnresolvedSymbol
get_unresolved_symbol () {
597 if (parent
.name
== null) {
598 return new
UnresolvedSymbol (null, name
);
600 return new
UnresolvedSymbol (parent
.get_unresolved_symbol (), name
);
604 public string get_full_name () {
605 if (parent
== null) {
610 return parent
.get_full_name ();
613 if (parent
.get_full_name () == null) {
617 return "%s.%s".printf (parent
.get_full_name (), name
);
620 public string get_default_gir_name () {
621 GLib
.StringBuilder default_name
= new GLib
.StringBuilder ();
623 for (unowned Node? node
= this
; node
!= null ; node
= node
.parent
) {
624 if (node
.symbol is Namespace
) {
625 if (node
.symbol
.get_attribute_string ("CCode", "gir_namespace") != null) {
630 default_name
.prepend (node
.name
);
633 return default_name
.str
;
636 public string get_gir_name () {
637 var gir_name
= girdata
["name"];
638 if (gir_name
== null) {
639 gir_name
= girdata
["glib:name"];
644 public string get_lower_case_cprefix () {
649 var prefix
= symbol
.get_attribute_string ("CCode", "lower_case_cprefix");
650 if (prefix
== null && (symbol is ObjectTypeSymbol
|| symbol is Struct
)) {
651 if (metadata
.has_argument (ArgumentType
.LOWER_CASE_CPREFIX
)) {
652 prefix
= metadata
.get_string (ArgumentType
.LOWER_CASE_CPREFIX
);
653 } else if (metadata
.has_argument (ArgumentType
.CPREFIX
)) {
654 prefix
= metadata
.get_string (ArgumentType
.CPREFIX
);
656 prefix
= symbol
.get_attribute_string ("CCode", "cprefix");
660 if (prefix
== null && girdata
!= null && (girdata
.contains ("c:symbol-prefix") || girdata
.contains("c:symbol-prefixes"))) {
661 /* Use the prefix in the gir. We look up prefixes up to the root.
662 If some node does not have girdata, we ignore it as i might be
663 a namespace created due to reparenting. */
664 unowned Node cur
= this
;
666 if (cur
.girdata
!= null) {
667 var p
= cur
.girdata
["c:symbol-prefix"];
669 p
= cur
.girdata
["c:symbol-prefixes"];
671 var idx
= p
.index_of (",");
673 p
= p
.substring (0, idx
);
679 prefix
= "%s_%s".printf (p
, prefix ??
"");
684 } while (cur
!= null);
687 if (prefix
== null) {
688 prefix
= get_default_lower_case_cprefix ();
693 public string get_default_lower_case_cprefix () {
694 return "%s%s_".printf (parent
.get_lower_case_cprefix (), get_lower_case_csuffix ());
697 public string get_lower_case_csuffix () {
698 var suffix
= symbol
.get_attribute_string ("CCode", "lower_case_csuffix");
700 // we can't rely on gir suffix if metadata changed the name
701 if (suffix
== null && girdata
!= null && girdata
["c:symbol-prefix"] != null && !metadata
.has_argument (ArgumentType
.NAME
)) {
702 suffix
= girdata
["c:symbol-prefix"];
704 if (suffix
== null) {
705 suffix
= get_default_lower_case_csuffix ();
710 public string get_default_lower_case_csuffix () {
711 return Symbol
.camel_case_to_lower_case (name
);
714 public string get_cprefix () {
718 var prefix
= symbol
.get_attribute_string ("CCode", "cprefix");
719 if (prefix
== null && girdata
!= null && girdata
["c:identifier-prefixes"] != null) {
720 prefix
= girdata
["c:identifier-prefixes"];
721 int idx
= prefix
.index_of (",");
723 prefix
= prefix
.substring (0, idx
);
726 if (prefix
== null) {
727 if (symbol is Enum
|| symbol is ErrorDomain
) {
728 prefix
= "%s%s".printf (parent
.get_lower_case_cprefix ().ascii_up (), name
);
730 prefix
= get_cname ();
736 public string get_cname () {
740 var cname
= symbol
.get_attribute_string ("CCode", "cname");
741 if (girdata
!= null) {
743 cname
= girdata
["c:identifier"];
746 cname
= girdata
["c:type"];
750 cname
= get_default_cname ();
755 public string get_default_cname () {
759 if (symbol is Field
) {
760 if (((Field
) symbol
).binding
== MemberBinding
.STATIC
) {
761 return parent
.get_lower_case_cprefix () + name
;
765 } else if (symbol is Method
) {
766 return "%s%s".printf (parent
.get_lower_case_cprefix (), name
);
768 return "%s%s".printf (parent
.get_cprefix (), name
);
772 public string get_finish_cname () {
773 var finish_cname
= symbol
.get_attribute_string ("CCode", "finish_name");
774 if (finish_cname
== null) {
775 finish_cname
= get_cname ();
776 if (finish_cname
.has_suffix ("_async")) {
777 finish_cname
= finish_cname
.substring (0, finish_cname
.length
- "_async".length
);
779 finish_cname
= "%s_finish".printf (finish_cname
);
784 public string get_cheader_filename () {
785 if (metadata
.has_argument (ArgumentType
.CHEADER_FILENAME
)) {
786 return metadata
.get_string (ArgumentType
.CHEADER_FILENAME
);
788 var cheader_filename
= symbol
.get_attribute_string ("CCode", "cheader_filename");
789 if (cheader_filename
!= null) {
790 return cheader_filename
;
792 if (parent
.name
!= null) {
793 return parent
.get_cheader_filename ();
794 } else if (symbol
.source_reference
!= null) {
795 return symbol
.source_reference
.file
.get_cinclude_filename ();
800 private static uint64 parse_version_string (string version
) {
803 string[] tokens
= version
.split (".", 3);
805 foreach (unowned
string token
in tokens
) {
808 if (!int64.try_parse (token
, out t
))
820 public void process (GirParser parser
) {
825 if (symbol is Namespace
&& parent
== parser
.root
) {
826 // first process aliases since they have no assigned symbol
827 foreach (var node
in members
) {
828 if (node
.element_type
== "alias") {
829 parser
.process_alias (node
);
833 // auto reparent namespace methods, allowing node removals
834 for (int i
=0; i
< members
.size
; i
++) {
835 var node
= members
[i
];
836 if (node
.symbol is Method
&& node
.new_symbol
) {
837 parser
.process_namespace_method (this
, node
);
838 if (i
< members
.size
&& members
[i
] != node
) {
839 // node removed in the middle
846 if (symbol is Class
&& girdata
!= null) {
847 var class_struct
= girdata
["glib:type-struct"];
848 if (class_struct
!= null) {
849 var klass
= parser
.resolve_node (parent
, parser
.parse_symbol_from_string (class_struct
, source_reference
));
852 while ( i
< klass
.members
.size
) {
853 var node
= klass
.members
[i
];
854 if (node
.symbol is Method
) {
855 klass
.remove_member (node
);
856 this
.add_member (node
);
858 Method m
= (Method
) node
.symbol
;
859 m
.binding
= MemberBinding
.CLASS
;
869 foreach (var node
in members
) {
870 node
.process (parser
);
873 if (girdata
!= null) {
874 // GIR node processing
875 if (symbol is Method
) {
876 var m
= (Method
) symbol
;
877 parser
.process_callable (this
);
879 var colliding
= parent
.lookup_all (name
);
880 foreach (var node
in colliding
) {
881 var sym
= node
.symbol
;
882 if (sym is Field
&& !(m
.return_type is VoidType
) && m
.get_parameters().size
== 0) {
883 // assume method is getter
885 } else if (sym is Signal
) {
886 node
.process (parser
);
887 var sig
= (Signal
) sym
;
888 if (m
.is_virtual
|| m
.is_abstract
) {
889 sig
.is_virtual
= true;
891 sig
.set_attribute ("HasEmitter", true);
893 parser
.assume_parameter_names (sig
, m
, false);
894 if (m
.get_parameters().size
!= sig
.get_parameters().size
) {
895 Report
.warning (symbol
.source_reference
, "Signal `%s' conflicts with method of the same name".printf (get_full_name ()));
898 } else if (sym is Method
&& !(sym is CreationMethod
) && node
!= this
) {
899 if (m
.is_virtual
|| m
.is_abstract
) {
900 bool different_invoker
= false;
901 var attr
= m
.get_attribute ("NoWrapper");
903 /* no invoker but this method has the same name,
904 most probably the invoker has a different name
905 and g-ir-scanner missed it */
906 var invoker
= parser
.find_invoker (this
);
907 if (invoker
!= null) {
908 m
.set_attribute_string ("CCode", "vfunc_name", m
.name
);
909 m
.name
= invoker
.symbol
.name
;
910 m
.set_attribute ("NoWrapper", false);
911 invoker
.merged
= true;
912 different_invoker
= true;
915 if (!different_invoker
) {
917 Report
.warning (symbol
.source_reference
, "Virtual method `%s' conflicts with method of the same name".printf (get_full_name ()));
924 if (!(m is CreationMethod
)) {
925 if (metadata
.has_argument (ArgumentType
.DESTROYS_INSTANCE
)) {
926 m
.set_attribute ("DestroysInstance", metadata
.get_bool (ArgumentType
.DESTROYS_INSTANCE
));
928 if (metadata
.has_argument (ArgumentType
.RETURNS_MODIFIED_POINTER
)) {
929 m
.set_attribute ("ReturnsModifiedPointer", metadata
.get_bool (ArgumentType
.RETURNS_MODIFIED_POINTER
));
931 // merge custom vfunc
932 if (metadata
.has_argument (ArgumentType
.VFUNC_NAME
)) {
933 var vfunc
= parent
.lookup (metadata
.get_string (ArgumentType
.VFUNC_NAME
));
934 if (vfunc
!= null && vfunc
!= this
) {
935 vfunc
.processed
= true;
941 parser
.process_async_method (this
);
943 } else if (symbol is Property
) {
944 var colliding
= parent
.lookup_all (name
);
945 foreach (var node
in colliding
) {
946 if (node
.symbol is Signal
) {
947 // properties take precedence
948 node
.processed
= true;
950 } else if (node
.symbol is Method
) {
951 // getter in C, but not in Vala
956 var prop
= (Property
) symbol
;
958 // add accessors, can't do this before gir symbol resolution
959 var readable
= girdata
["readable"];
960 var writable
= girdata
["writable"];
961 var construct_
= girdata
["construct"];
962 var construct_only
= girdata
["construct-only"];
963 if (readable
!= "0") {
964 prop
.get_accessor
= new
PropertyAccessor (true, false, false, prop
.property_type
.copy (), null, null);
966 if (writable
== "1" || construct_only
== "1") {
967 prop
.set_accessor
= new
PropertyAccessor (false, (construct_only
!= "1") && (writable
== "1"), (construct_only
== "1") || (construct_
== "1"), prop
.property_type
.copy (), null, null);
970 // find virtual/abstract accessors to handle abstract properties properly
973 var getters
= parent
.lookup_all ("get_%s".printf (name
));
974 if (getters
!= null) {
975 foreach (var g
in getters
) {
976 if ((getter
== null || !g
.merged
) && g
.get_cname () == "%sget_%s".printf (parent
.get_lower_case_cprefix (), name
)) {
983 var setters
= parent
.lookup_all ("set_%s".printf (name
));
984 if (setters
!= null) {
985 foreach (var s
in setters
) {
986 if ((setter
== null || !s
.merged
) && s
.get_cname () == "%sset_%s".printf (parent
.get_lower_case_cprefix (), name
)) {
992 prop
.set_attribute ("NoAccessorMethod", (readable
== "0" && construct_only
== "1"));
993 if (prop
.get_accessor
!= null) {
994 var m
= getter
!= null ? getter
.symbol as Method
: null;
995 // ensure getter vfunc if the property is abstract
997 getter
.process (parser
);
998 if (m
.return_type is VoidType
|| m
.get_parameters().size
!= 0 || m
.get_error_types ().size
> 0) {
999 prop
.set_attribute ("NoAccessorMethod", true);
1001 if (getter
.name
== name
) {
1002 foreach (var node
in colliding
) {
1003 if (node
.symbol is Method
) {
1009 prop
.get_accessor
.value_type
.value_owned
= m
.return_type
.value_owned
;
1011 if (!m
.is_abstract
&& !m
.is_virtual
&& prop
.is_abstract
) {
1012 prop
.set_attribute ("ConcreteAccessor", true);
1016 prop
.set_attribute ("NoAccessorMethod", true);
1020 if (prop
.get_attribute ("NoAccessorMethod") == null && prop
.set_accessor
!= null && prop
.set_accessor
.writable
) {
1021 var m
= setter
!= null ? setter
.symbol as Method
: null;
1022 // ensure setter vfunc if the property is abstract
1024 setter
.process (parser
);
1025 if (!(m
.return_type is VoidType
|| m
.return_type is BooleanType
) || m
.get_parameters ().size
!= 1 || m
.get_error_types ().size
> 0) {
1026 prop
.set_attribute ("NoAccessorMethod", true);
1027 prop
.set_attribute ("ConcreteAccessor", false);
1029 prop
.set_accessor
.value_type
.value_owned
= m
.get_parameters()[0].variable_type
.value_owned
;
1030 if (prop
.get_attribute ("ConcreteAccessor") != null && !m
.is_abstract
&& !m
.is_virtual
&& prop
.is_abstract
) {
1031 prop
.set_attribute ("ConcreteAccessor", true);
1032 prop
.set_attribute ("NoAccessorMethod", false);
1036 prop
.set_attribute ("NoAccessorMethod", true);
1037 prop
.set_attribute ("ConcreteAccessor", false);
1041 if (prop
.get_attribute ("NoAccessorMethod") != null) {
1042 if (!prop
.overrides
&& parent
.symbol is Class
) {
1044 // find base interface property with ConcreteAccessor and this overriding property with NoAccessorMethod
1045 var base_prop_node
= parser
.base_interface_property (this
);
1046 if (base_prop_node
!= null) {
1047 base_prop_node
.process (parser
);
1049 var base_property
= (Property
) base_prop_node
.symbol
;
1050 if (base_property
.get_attribute ("ConcreteAccessor") != null) {
1051 prop
.set_attribute ("NoAccessorMethod", false);
1052 if (prop
.get_accessor
!= null) {
1053 prop
.get_accessor
.value_type
.value_owned
= base_property
.get_accessor
.value_type
.value_owned
;
1055 if (prop
.set_accessor
!= null) {
1056 prop
.set_accessor
.value_type
.value_owned
= base_property
.set_accessor
.value_type
.value_owned
;
1064 if (metadata
.has_argument (ArgumentType
.NO_ACCESSOR_METHOD
)) {
1065 prop
.set_attribute ("NoAccessorMethod", metadata
.get_bool (ArgumentType
.NO_ACCESSOR_METHOD
));
1068 if (prop
.get_attribute ("NoAccessorMethod") != null) {
1070 if (prop
.get_accessor
!= null) {
1071 prop
.get_accessor
.value_type
.value_owned
= true;
1073 if (prop
.set_accessor
!= null) {
1074 prop
.set_accessor
.value_type
.value_owned
= false;
1077 } else if (symbol is Field
) {
1078 var field
= (Field
) symbol
;
1079 var colliding
= parent
.lookup_all (name
);
1080 if (colliding
.size
> 1) {
1081 // whatelse has precedence over the field
1085 if (metadata
.has_argument (ArgumentType
.DELEGATE_TARGET_CNAME
)) {
1086 field
.set_attribute_string ("CCode", "delegate_target_cname", metadata
.get_string (ArgumentType
.DELEGATE_TARGET_CNAME
));
1089 if (field
.variable_type is DelegateType
&& parent
.gtype_struct_for
!= null) {
1090 // virtual method field
1091 var d
= ((DelegateType
) field
.variable_type
).delegate_symbol
;
1092 parser
.process_virtual_method_field (this
, d
, parent
.gtype_struct_for
);
1094 } else if (field
.variable_type is ArrayType
) {
1096 if (metadata
.has_argument (ArgumentType
.ARRAY_LENGTH_FIELD
)) {
1097 array_length
= parent
.lookup (metadata
.get_string (ArgumentType
.ARRAY_LENGTH_FIELD
));
1098 } else if (array_length_idx
> -1 && parent
.members
.size
> array_length_idx
) {
1099 array_length
= parent
.members
[array_length_idx
];
1101 array_length
= parent
.lookup ("n_%s".printf (field
.name
));
1102 if (array_length
== null) {
1103 array_length
= parent
.lookup ("num_%s".printf (field
.name
));
1104 if (array_length
== null) {
1105 array_length
= parent
.lookup ("%s_length".printf (field
.name
));
1109 if (array_length
!= null && array_length
.symbol is Field
) {
1110 var length_field
= (Field
) array_length
.symbol
;
1112 field
.set_attribute_string ("CCode", "array_length_cname", length_field
.name
);
1113 var length_type
= length_field
.variable_type
.to_qualified_string ();
1114 if (length_type
!= "int") {
1115 var st
= parser
.root
.lookup (length_type
);
1117 field
.set_attribute_string ("CCode", "array_length_type", st
.get_cname ());
1120 field
.remove_attribute_argument ("CCode", "array_length");
1121 field
.remove_attribute_argument ("CCode", "array_null_terminated");
1124 } else if (symbol is Signal
|| symbol is Delegate
) {
1125 parser
.process_callable (this
);
1126 } else if (symbol is Interface
) {
1127 parser
.process_interface (this
);
1128 } else if (symbol is Struct
) {
1129 if (parent
.symbol is ObjectTypeSymbol
|| parent
.symbol is Struct
) {
1131 foreach (var fn
in members
) {
1132 var f
= fn
.symbol as Field
;
1134 if (f
.binding
== MemberBinding
.INSTANCE
) {
1135 f
.set_attribute_string ("CCode", "cname", "%s.%s".printf (name
, fn
.get_cname ()));
1137 f
.name
= "%s_%s".printf (symbol
.name
, f
.name
);
1139 parent
.add_member (fn
);
1144 // record for a gtype
1145 var gtype_struct_for
= girdata
["glib:is-gtype-struct-for"];
1146 if (gtype_struct_for
!= null) {
1147 var iface
= parser
.resolve_node (parent
, parser
.parse_symbol_from_string (gtype_struct_for
, source_reference
));
1148 if (iface
!= null && iface
.symbol is Interface
&& "%sIface".printf (iface
.get_cname ()) != get_cname ()) {
1149 // set the interface struct name
1150 iface
.symbol
.set_attribute_string ("CCode", "type_cname", get_cname ());
1158 if (metadata
.has_argument (ArgumentType
.REPLACEMENT
)) {
1160 deprecated_replacement
= metadata
.get_string (ArgumentType
.REPLACEMENT
);
1162 if (metadata
.has_argument (ArgumentType
.DEPRECATED_SINCE
)) {
1164 deprecated_since
= metadata
.get_string (ArgumentType
.DEPRECATED_SINCE
);
1165 } else if (girdata
["deprecated-version"] != null) {
1167 deprecated_since
= girdata
.get ("deprecated-version");
1169 if (metadata
.has_argument (ArgumentType
.DEPRECATED
)) {
1170 deprecated
= metadata
.get_bool (ArgumentType
.DEPRECATED
, true);
1172 deprecated_since
= null;
1173 deprecated_replacement
= null;
1175 } else if (girdata
["deprecated"] != null) {
1178 if (deprecated_since
!= null) {
1179 deprecated_version
= parse_version_string (deprecated_since
);
1183 if (metadata
.has_argument (ArgumentType
.EXPERIMENTAL
)) {
1184 symbol
.set_attribute_bool ("Version", "experimental", metadata
.get_bool (ArgumentType
.EXPERIMENTAL
));
1188 if (metadata
.has_argument (ArgumentType
.SINCE
)) {
1189 symbol
.version
.since
= metadata
.get_string (ArgumentType
.SINCE
);
1190 } else if (symbol is Namespace
== false && girdata
["version"] != null) {
1191 symbol
.version
.since
= girdata
.get ("version");
1194 if (parent
.symbol is Namespace
) {
1195 // always write cheader filename for namespace children
1196 symbol
.set_attribute_string ("CCode", "cheader_filename", get_cheader_filename ());
1197 } else if (metadata
.has_argument (ArgumentType
.CHEADER_FILENAME
)) {
1198 symbol
.set_attribute_string ("CCode", "cheader_filename", metadata
.get_string (ArgumentType
.CHEADER_FILENAME
));
1200 if (get_cname () != get_default_cname ()) {
1201 symbol
.set_attribute_string ("CCode", "cname", get_cname ());
1204 // lower_case_cprefix
1205 if (get_lower_case_cprefix () != get_default_lower_case_cprefix ()) {
1206 symbol
.set_attribute_string ("CCode", "lower_case_cprefix", get_lower_case_cprefix ());
1208 // lower_case_csuffix
1209 if (get_lower_case_csuffix () != get_default_lower_case_csuffix ()) {
1210 symbol
.set_attribute_string ("CCode", "lower_case_csuffix", get_lower_case_csuffix ());
1213 // set gir name if the symbol has been renamed
1214 string gir_name
= get_gir_name ();
1215 string default_gir_name
= get_default_gir_name ();
1216 if (is_container (symbol
) && !(symbol is Namespace
) && (name
!= gir_name
|| gir_name
!= default_gir_name
)) {
1217 symbol
.set_attribute_string ("GIR", "name", gir_name
);
1221 if (!(new_symbol
&& merged
) && is_container (symbol
)) {
1222 foreach (var node
in members
) {
1223 if (this
.deprecated_version
> 0 && node
.deprecated_version
> 0) {
1224 if (this
.deprecated_version
<= node
.deprecated_version
) {
1225 node
.deprecated
= false;
1226 node
.deprecated_since
= null;
1227 node
.deprecated_replacement
= null;
1230 if (node
.deprecated
) {
1231 node
.symbol
.version
.deprecated
= true;
1233 if (node
.deprecated_since
!= null) {
1234 node
.symbol
.version
.deprecated_since
= node
.deprecated_since
;
1236 if (node
.deprecated_replacement
!= null) {
1237 node
.symbol
.version
.replacement
= node
.deprecated_replacement
;
1240 if (node
.new_symbol
&& !node
.merged
&& !metadata
.get_bool (ArgumentType
.HIDDEN
)) {
1241 add_symbol_to_container (symbol
, node
.symbol
);
1245 var cl
= symbol as Class
;
1246 if (cl
!= null && !cl
.is_compact
&& cl
.default_construction_method
== null) {
1247 // always provide constructor in generated bindings
1248 // to indicate that implicit Object () chainup is allowed
1249 var cm
= new
CreationMethod (null, null, cl
.source_reference
);
1250 cm
.has_construct_function
= false;
1251 cm
.access
= SymbolAccessibility
.PROTECTED
;
1259 public string to_string () {
1260 if (parent
.name
== null) {
1263 return "%s.%s".printf (parent
.to_string (), name
);
1268 static GLib
.Regex type_from_string_regex
;
1270 MarkupReader reader
;
1272 CodeContext context
;
1275 SourceFile current_source_file
;
1277 ArrayList
<Metadata
> metadata_roots
= new ArrayList
<Metadata
> ();
1279 SourceLocation begin
;
1281 MarkupTokenType current_token
;
1283 string[] cheader_filenames
;
1285 ArrayList
<Metadata
> metadata_stack
;
1287 ArrayList
<Node
> tree_stack
;
1291 Set
<string> provided_namespaces
= new HashSet
<string> (str_hash
, str_equal
);
1292 HashMap
<UnresolvedSymbol
,Symbol
> unresolved_symbols_map
= new HashMap
<UnresolvedSymbol
,Symbol
> (unresolved_symbol_hash
, unresolved_symbol_equal
);
1293 ArrayList
<UnresolvedSymbol
> unresolved_gir_symbols
= new ArrayList
<UnresolvedSymbol
> ();
1294 ArrayList
<DataType
> unresolved_type_arguments
= new ArrayList
<DataType
> ();
1297 * Parses all .gir source files in the specified code
1298 * context and builds a code tree.
1300 * @param context a code context
1302 public void parse (CodeContext context
) {
1303 this
.context
= context
;
1304 glib_ns
= context
.root
.scope
.lookup ("GLib") as Namespace
;
1306 root
= new
Node (null);
1307 root
.symbol
= context
.root
;
1308 tree_stack
= new ArrayList
<Node
> ();
1313 context
.accept (this
);
1315 resolve_gir_symbols ();
1316 create_new_namespaces ();
1317 resolve_type_arguments ();
1319 root
.process (this
);
1321 foreach (var metadata
in metadata_roots
) {
1322 report_unused_metadata (metadata
);
1326 void map_vala_to_gir () {
1327 foreach (var source_file
in context
.get_source_files ()) {
1328 string gir_namespace
= source_file
.gir_namespace
;
1329 string gir_version
= source_file
.gir_version
;
1330 Namespace ns
= null;
1331 if (gir_namespace
== null) {
1332 foreach (var node
in source_file
.get_nodes ()) {
1333 if (node is Namespace
) {
1334 ns
= (Namespace
) node
;
1335 gir_namespace
= ns
.get_attribute_string ("CCode", "gir_namespace");
1336 if (gir_namespace
!= null) {
1337 gir_version
= ns
.get_attribute_string ("CCode", "gir_version");
1343 if (gir_namespace
== null) {
1347 provided_namespaces
.add ("%s-%s".printf (gir_namespace
, gir_version
));
1349 var gir_symbol
= new
UnresolvedSymbol (null, gir_namespace
);
1350 if (gir_namespace
!= ns
.name
) {
1351 set_symbol_mapping (gir_symbol
, ns
);
1354 foreach (var node
in source_file
.get_nodes ()) {
1355 if (node
.has_attribute_argument ("GIR", "name")) {
1356 var map_from
= new
UnresolvedSymbol (gir_symbol
, node
.get_attribute_string ("GIR", "name"));
1357 set_symbol_mapping (map_from
, (Symbol
) node
);
1363 public override void visit_source_file (SourceFile source_file
) {
1364 if (source_file
.filename
.has_suffix (".gir")) {
1365 parse_file (source_file
);
1369 public void parse_file (SourceFile source_file
) {
1370 metadata_stack
= new ArrayList
<Metadata
> ();
1371 metadata
= Metadata
.empty
;
1372 cheader_filenames
= null;
1374 this
.current_source_file
= source_file
;
1375 reader
= new
MarkupReader (source_file
.filename
);
1382 parse_repository ();
1385 this
.current_source_file
= null;
1389 current_token
= reader
.read_token (out begin
, out end
);
1392 void start_element (string name
) {
1393 if (current_token
!= MarkupTokenType
.START_ELEMENT
|| reader
.name
!= name
) {
1395 Report
.error (get_current_src (), "expected start element of `%s'".printf (name
));
1399 void end_element (string name
) {
1400 while (current_token
!= MarkupTokenType
.END_ELEMENT
|| reader
.name
!= name
) {
1401 Report
.warning (get_current_src (), "expected end element of `%s'".printf (name
));
1407 SourceReference
get_current_src () {
1408 return new
SourceReference (this
.current_source_file
, begin
, end
);
1411 const string GIR_VERSION
= "1.2";
1413 static void add_symbol_to_container (Symbol container
, Symbol sym
) {
1414 if (container is Class
) {
1415 unowned Class cl
= (Class
) container
;
1418 cl
.add_class ((Class
) sym
);
1419 } else if (sym is Constant
) {
1420 cl
.add_constant ((Constant
) sym
);
1421 } else if (sym is Enum
) {
1422 cl
.add_enum ((Enum
) sym
);
1423 } else if (sym is Field
) {
1424 cl
.add_field ((Field
) sym
);
1425 } else if (sym is Method
) {
1426 cl
.add_method ((Method
) sym
);
1427 } else if (sym is Property
) {
1428 cl
.add_property ((Property
) sym
);
1429 } else if (sym is Signal
) {
1430 cl
.add_signal ((Signal
) sym
);
1431 } else if (sym is Struct
) {
1432 cl
.add_struct ((Struct
) sym
);
1434 } else if (container is Enum
) {
1435 unowned Enum en
= (Enum
) container
;
1437 if (sym is EnumValue
) {
1438 en
.add_value ((EnumValue
) sym
);
1439 } else if (sym is Constant
) {
1440 en
.add_constant ((Constant
) sym
);
1441 } else if (sym is Method
) {
1442 en
.add_method ((Method
) sym
);
1444 } else if (container is Interface
) {
1445 unowned Interface iface
= (Interface
) container
;
1448 iface
.add_class ((Class
) sym
);
1449 } else if (sym is Constant
) {
1450 iface
.add_constant ((Constant
) sym
);
1451 } else if (sym is Enum
) {
1452 iface
.add_enum ((Enum
) sym
);
1453 } else if (sym is Field
) {
1454 iface
.add_field ((Field
) sym
);
1455 } else if (sym is Method
) {
1456 iface
.add_method ((Method
) sym
);
1457 } else if (sym is Property
) {
1458 iface
.add_property ((Property
) sym
);
1459 } else if (sym is Signal
) {
1460 iface
.add_signal ((Signal
) sym
);
1461 } else if (sym is Struct
) {
1462 iface
.add_struct ((Struct
) sym
);
1464 } else if (container is Namespace
) {
1465 unowned Namespace ns
= (Namespace
) container
;
1467 if (sym is Namespace
) {
1468 ns
.add_namespace ((Namespace
) sym
);
1469 } else if (sym is Class
) {
1470 ns
.add_class ((Class
) sym
);
1471 } else if (sym is Constant
) {
1472 ns
.add_constant ((Constant
) sym
);
1473 } else if (sym is Delegate
) {
1474 ns
.add_delegate ((Delegate
) sym
);
1475 } else if (sym is Enum
) {
1476 ns
.add_enum ((Enum
) sym
);
1477 } else if (sym is ErrorDomain
) {
1478 ns
.add_error_domain ((ErrorDomain
) sym
);
1479 } else if (sym is Field
) {
1480 ns
.add_field ((Field
) sym
);
1481 } else if (sym is Interface
) {
1482 ns
.add_interface ((Interface
) sym
);
1483 } else if (sym is Method
) {
1484 ns
.add_method ((Method
) sym
);
1485 } else if (sym is Struct
) {
1486 ns
.add_struct ((Struct
) sym
);
1488 } else if (container is Struct
) {
1489 unowned Struct st
= (Struct
) container
;
1491 if (sym is Constant
) {
1492 st
.add_constant ((Constant
) sym
);
1493 } else if (sym is Field
) {
1494 st
.add_field ((Field
) sym
);
1495 } else if (sym is Method
) {
1496 st
.add_method ((Method
) sym
);
1497 } else if (sym is Property
) {
1498 st
.add_property ((Property
) sym
);
1500 } else if (container is ErrorDomain
) {
1501 unowned ErrorDomain ed
= (ErrorDomain
) container
;
1503 if (sym is ErrorCode
) {
1504 ed
.add_code ((ErrorCode
) sym
);
1505 } else if (sym is Method
) {
1506 ed
.add_method ((Method
) sym
);
1509 Report
.error (sym
.source_reference
, "impossible to add `%s' to container `%s'".printf (sym
.name
, container
.name
));
1513 static bool is_container (Symbol sym
) {
1514 return sym is ObjectTypeSymbol
|| sym is Struct
|| sym is Namespace
|| sym is ErrorDomain
|| sym is Enum
;
1517 UnresolvedSymbol?
parse_symbol_from_string (string symbol_string
, SourceReference? source_reference
= null) {
1518 UnresolvedSymbol? sym
= null;
1519 foreach (unowned
string s
in symbol_string
.split (".")) {
1520 sym
= new
UnresolvedSymbol (sym
, s
, source_reference
);
1523 Report
.error (source_reference
, "a symbol must be specified");
1528 void set_symbol_mapping (UnresolvedSymbol map_from
, Symbol map_to
) {
1529 // last mapping is the most up-to-date
1530 if (map_from is UnresolvedSymbol
) {
1531 unresolved_symbols_map
[(UnresolvedSymbol
) map_from
] = map_to
;
1535 void assume_parameter_names (Signal sig
, Symbol sym
, bool skip_first
) {
1536 var iter
= ((Callable
) sym
).get_parameters ().iterator ();
1538 foreach (var param
in sig
.get_parameters ()) {
1539 if (!iter
.next ()) {
1540 // unreachable for valid GIR
1543 if (skip_first
&& first
) {
1544 if (!iter
.next ()) {
1545 // unreachable for valid GIR
1550 param
.name
= iter
.get ().name
;
1554 Node?
find_invoker (Node node
) {
1555 /* most common use case is invoker has at least the given method prefix
1556 and the same parameter names */
1557 var m
= (Method
) node
.symbol
;
1558 var prefix
= "%s_".printf (m
.name
);
1559 foreach (var n
in node
.parent
.members
) {
1560 if (!n
.name
.has_prefix (prefix
)) {
1563 Method? invoker
= n
.symbol as Method
;
1564 if (invoker
== null || (m
.get_parameters().size
!= invoker
.get_parameters().size
)) {
1567 var iter
= invoker
.get_parameters ().iterator ();
1568 foreach (var param
in m
.get_parameters ()) {
1569 assert (iter
.next ());
1570 if (param
.name
!= iter
.get().name
) {
1575 if (invoker
!= null) {
1583 Metadata
get_current_metadata () {
1584 var selector
= reader
.name
;
1585 var child_name
= reader
.get_attribute ("name");
1586 if (child_name
== null) {
1587 child_name
= reader
.get_attribute ("glib:name");
1589 // Give a transparent union the generic name "union"
1590 if (selector
== "union" && child_name
== null) {
1591 child_name
= "union";
1593 if (child_name
== null) {
1594 return Metadata
.empty
;
1596 selector
= selector
.replace ("-", "_");
1597 child_name
= child_name
.replace ("-", "_");
1599 if (selector
.has_prefix ("glib:")) {
1600 selector
= selector
.substring ("glib:".length
);
1603 return metadata
.match_child (child_name
, selector
);
1606 bool push_metadata () {
1607 var new_metadata
= get_current_metadata ();
1609 if (new_metadata
.has_argument (ArgumentType
.SKIP
)) {
1610 if (new_metadata
.get_bool (ArgumentType
.SKIP
)) {
1613 } else if (reader
.get_attribute ("introspectable") == "0" || reader
.get_attribute ("private") == "1") {
1617 metadata_stack
.add (metadata
);
1618 metadata
= new_metadata
;
1623 void pop_metadata () {
1624 metadata
= metadata_stack
[metadata_stack
.size
- 1];
1625 metadata_stack
.remove_at (metadata_stack
.size
- 1);
1628 bool parse_type_arguments_from_string (DataType parent_type
, string type_arguments
, SourceReference? source_reference
= null) {
1629 int type_arguments_length
= (int) type_arguments
.length
;
1630 GLib
.StringBuilder current
= new GLib
.StringBuilder
.sized (type_arguments_length
);
1633 for (var c
= 0 ; c
< type_arguments_length
; c
++) {
1634 if (type_arguments
[c
] == '<' || type_arguments
[c
] == '[') {
1636 current
.append_unichar (type_arguments
[c
]);
1637 } else if (type_arguments
[c
] == '>' || type_arguments
[c
] == ']') {
1639 current
.append_unichar (type_arguments
[c
]);
1640 } else if (type_arguments
[c
] == ',') {
1642 var dt
= parse_type_from_string (current
.str
, true, source_reference
);
1646 parent_type
.add_type_argument (dt
);
1647 current
.truncate ();
1649 current
.append_unichar (type_arguments
[c
]);
1652 current
.append_unichar (type_arguments
[c
]);
1656 var dt
= parse_type_from_string (current
.str
, true, source_reference
);
1660 parent_type
.add_type_argument (dt
);
1665 DataType?
parse_type_from_string (string type_string
, bool owned_by_default
, SourceReference? source_reference
= null) {
1666 if (type_from_string_regex
== null) {
1668 type_from_string_regex
= new GLib
.Regex ("^(?:(owned|unowned|weak) +)?([0-9a-zA-Z_\\.]+)(?:<(.+)>)?(\\*+)?(\\[,*\\])?(\\?)?$", GLib
.RegexCompileFlags
.ANCHORED
| GLib
.RegexCompileFlags
.DOLLAR_ENDONLY
| GLib
.RegexCompileFlags
.OPTIMIZE
);
1669 } catch (GLib
.RegexError e
) {
1670 GLib
.error ("Unable to compile regex: %s", e
.message
);
1674 GLib
.MatchInfo match
;
1675 if (!type_from_string_regex
.match (type_string
, 0, out match
)) {
1676 Report
.error (source_reference
, "unable to parse type");
1680 DataType? type
= null;
1682 var ownership_data
= match
.fetch (1);
1683 var type_name
= match
.fetch (2);
1684 var type_arguments_data
= match
.fetch (3);
1685 var pointers_data
= match
.fetch (4);
1686 var array_data
= match
.fetch (5);
1687 var nullable_data
= match
.fetch (6);
1689 var nullable
= nullable_data
!= null && nullable_data
.length
> 0;
1691 if (ownership_data
== null && type_name
== "void") {
1692 if (array_data
== null && !nullable
) {
1693 type
= new
VoidType (source_reference
);
1694 if (pointers_data
!= null) {
1695 for (int i
=0; i
< pointers_data
.length
; i
++) {
1696 type
= new
PointerType (type
);
1701 Report
.error (source_reference
, "invalid void type");
1706 bool value_owned
= owned_by_default
;
1708 if (ownership_data
== "owned") {
1709 if (owned_by_default
) {
1710 Report
.error (source_reference
, "unexpected `owned' keyword");
1714 } else if (ownership_data
== "unowned") {
1715 if (owned_by_default
) {
1716 value_owned
= false;
1718 Report
.error (source_reference
, "unexpected `unowned' keyword");
1723 var sym
= parse_symbol_from_string (type_name
, source_reference
);
1727 type
= new UnresolvedType
.from_symbol (sym
, source_reference
);
1729 if (type_arguments_data
!= null && type_arguments_data
.length
> 0) {
1730 if (!parse_type_arguments_from_string (type
, type_arguments_data
, source_reference
)) {
1735 if (pointers_data
!= null) {
1736 for (int i
=0; i
< pointers_data
.length
; i
++) {
1737 type
= new
PointerType (type
);
1741 if (array_data
!= null && array_data
.length
!= 0) {
1742 type
.value_owned
= true;
1743 type
= new
ArrayType (type
, (int) array_data
.length
- 1, source_reference
);
1746 type
.nullable
= nullable
;
1747 type
.value_owned
= value_owned
;
1751 string?
element_get_string (string attribute_name
, ArgumentType arg_type
) {
1752 if (metadata
.has_argument (arg_type
)) {
1753 return metadata
.get_string (arg_type
);
1755 return reader
.get_attribute (attribute_name
);
1760 * The changed is a faster way to check whether the type has changed and it may affect the C declaration.
1762 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) {
1764 var type
= orig_type
;
1766 if (metadata
.has_argument (ArgumentType
.TYPE
)) {
1767 type
= parse_type_from_string (metadata
.get_string (ArgumentType
.TYPE
), owned_by_default
, metadata
.get_source_reference (ArgumentType
.TYPE
));
1769 } else if (!(type is VoidType
)) {
1770 if (metadata
.has_argument (ArgumentType
.TYPE_ARGUMENTS
)) {
1771 type
.remove_all_type_arguments ();
1772 parse_type_arguments_from_string (type
, metadata
.get_string (ArgumentType
.TYPE_ARGUMENTS
), metadata
.get_source_reference (ArgumentType
.TYPE_ARGUMENTS
));
1775 if (!(type is ArrayType
) && metadata
.get_bool (ArgumentType
.ARRAY
)) {
1776 type
.value_owned
= true;
1777 type
= new
ArrayType (type
, 1, type
.source_reference
);
1781 if (owned_by_default
) {
1782 type
.value_owned
= !metadata
.get_bool (ArgumentType
.UNOWNED
, !type
.value_owned
);
1784 type
.value_owned
= metadata
.get_bool (ArgumentType
.OWNED
, type
.value_owned
);
1786 type
.nullable
= metadata
.get_bool (ArgumentType
.NULLABLE
, type
.nullable
);
1789 if (type is ArrayType
) {
1790 if (!(orig_type is ArrayType
)) {
1791 no_array_length
= true;
1793 array_null_terminated
= metadata
.get_bool (ArgumentType
.ARRAY_NULL_TERMINATED
, array_null_terminated
);
1799 string?
element_get_name (string? gir_name
= null) {
1800 var name
= gir_name
;
1802 name
= reader
.get_attribute ("name");
1804 var pattern
= metadata
.get_string (ArgumentType
.NAME
);
1805 if (pattern
!= null) {
1806 if (pattern
.index_of_char ('(') < 0) {
1807 // shortcut for "(.+)/replacement"
1811 string replacement
= "\\1"; // replace the whole name with the match by default
1812 var split
= pattern
.split ("/");
1813 if (split
.length
> 1) {
1815 replacement
= split
[1];
1817 var regex
= new
Regex (pattern
, RegexCompileFlags
.ANCHORED
, RegexMatchFlags
.ANCHORED
);
1818 name
= regex
.replace (name
, -1, 0, replacement
);
1824 if (name
!= null && name
.has_suffix ("Enum")) {
1825 name
= name
.substring (0, name
.length
- "Enum".length
);
1832 string?
element_get_type_id () {
1833 var type_id
= metadata
.get_string (ArgumentType
.TYPE_ID
);
1834 if (type_id
!= null) {
1838 type_id
= reader
.get_attribute ("glib:get-type");
1839 if (type_id
!= null) {
1845 void set_array_ccode (Symbol sym
, ParameterInfo info
) {
1846 sym
.set_attribute_double ("CCode", "array_length_pos", info
.vala_idx
);
1847 if (sym is Parameter
) {
1848 sym
.set_attribute_string ("CCode", "array_length_cname", info
.param
.name
);
1850 var type_name
= info
.param
.variable_type
.to_qualified_string ();
1851 if (type_name
!= "int") {
1852 var st
= root
.lookup (type_name
);
1854 if (sym is Method
) {
1855 var m
= (Method
) sym
;
1856 m
.set_attribute_string ("CCode", "array_length_type", st
.get_cname ());
1858 var param
= (Parameter
) sym
;
1859 param
.set_attribute_string ("CCode", "array_length_type", st
.get_cname ());
1865 void set_type_id_ccode (Symbol sym
) {
1866 if (sym
.has_attribute_argument ("CCode", "has_type_id")
1867 || sym
.has_attribute_argument ("CCode", "type_id"))
1870 var type_id
= element_get_type_id ();
1871 if (type_id
== null) {
1872 sym
.set_attribute_bool ("CCode", "has_type_id", false);
1874 sym
.set_attribute_string ("CCode", "type_id", type_id
);
1878 void parse_repository () {
1879 start_element ("repository");
1880 if (reader
.get_attribute ("version") != GIR_VERSION
) {
1881 Report
.error (get_current_src (), "unsupported GIR version %s (supported: %s)".printf (reader
.get_attribute ("version"), GIR_VERSION
));
1885 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
1886 if (reader
.name
== "namespace") {
1888 } else if (reader
.name
== "include") {
1890 } else if (reader
.name
== "package") {
1891 var pkg
= parse_package ();
1892 this
.current_source_file
.package_name
= pkg
;
1893 if (context
.has_package (pkg
)) {
1894 // package already provided elsewhere, stop parsing this GIR
1895 // if it was not passed explicitly
1896 if (!this
.current_source_file
.explicit
) {
1900 context
.add_package (pkg
);
1902 } else if (reader
.name
== "c:include") {
1906 Report
.error (get_current_src (), "unknown child element `%s' in `repository'".printf (reader
.name
));
1910 end_element ("repository");
1913 void parse_include () {
1914 start_element ("include");
1915 var pkg
= reader
.get_attribute ("name");
1916 var version
= reader
.get_attribute ("version");
1917 if (version
!= null) {
1918 pkg
= "%s-%s".printf (pkg
, version
);
1920 // add the package to the queue
1921 context
.add_external_package (pkg
);
1923 end_element ("include");
1926 string parse_package () {
1927 start_element ("package");
1928 var pkg
= reader
.get_attribute ("name");
1930 end_element ("package");
1934 void parse_c_include () {
1935 start_element ("c:include");
1936 cheader_filenames
+= reader
.get_attribute ("name");
1938 end_element ("c:include");
1941 void skip_element () {
1946 if (current_token
== MarkupTokenType
.START_ELEMENT
) {
1948 } else if (current_token
== MarkupTokenType
.END_ELEMENT
) {
1950 } else if (current_token
== MarkupTokenType
.EOF
) {
1951 Report
.error (get_current_src (), "unexpected end of file");
1958 Node?
resolve_node (Node parent_scope
, UnresolvedSymbol unresolved_sym
, bool create_namespace
= false) {
1959 if (unresolved_sym
.inner
== null) {
1960 var scope
= parent_scope
;
1961 while (scope
!= null) {
1962 var node
= scope
.lookup (unresolved_sym
.name
, create_namespace
, unresolved_sym
.source_reference
);
1966 scope
= scope
.parent
;
1969 var inner
= resolve_node (parent_scope
, unresolved_sym
.inner
, create_namespace
);
1970 if (inner
!= null) {
1971 return inner
.lookup (unresolved_sym
.name
, create_namespace
, unresolved_sym
.source_reference
);
1977 Symbol?
resolve_symbol (Node parent_scope
, UnresolvedSymbol unresolved_sym
) {
1978 var node
= resolve_node (parent_scope
, unresolved_sym
);
1985 void push_node (string name
, bool merge
) {
1986 var parent
= current
;
1987 if (metadata
.has_argument (ArgumentType
.PARENT
)) {
1988 var target
= parse_symbol_from_string (metadata
.get_string (ArgumentType
.PARENT
), metadata
.get_source_reference (ArgumentType
.PARENT
));
1989 parent
= resolve_node (root
, target
, true);
1992 var node
= parent
.lookup (name
);
1993 if (node
== null || (node
.symbol
!= null && !merge
)) {
1994 node
= new
Node (name
);
1995 node
.new_symbol
= true;
1996 parent
.add_member (node
);
1998 Node
.new_namespaces
.remove (node
);
2000 node
.element_type
= reader
.name
;
2001 node
.girdata
= reader
.get_attributes ();
2002 node
.metadata
= metadata
;
2003 node
.source_reference
= get_current_src ();
2005 var gir_name
= node
.get_gir_name ();
2006 if (parent
!= current
|| gir_name
!= name
) {
2007 set_symbol_mapping (new
UnresolvedSymbol (null, gir_name
), node
.get_unresolved_symbol ());
2010 tree_stack
.add (current
);
2015 old_current
= current
;
2016 current
= tree_stack
[tree_stack
.size
- 1];
2017 tree_stack
.remove_at (tree_stack
.size
- 1);
2020 void parse_namespace () {
2021 start_element ("namespace");
2023 string? cprefix
= reader
.get_attribute ("c:identifier-prefixes");
2024 if (cprefix
!= null) {
2025 int idx
= cprefix
.index_of (",");
2027 cprefix
= cprefix
.substring (0, idx
);
2031 string? lower_case_cprefix
= reader
.get_attribute ("c:symbol-prefixes");
2032 string vala_namespace
= cprefix
;
2033 string gir_namespace
= reader
.get_attribute ("name");
2034 string gir_version
= reader
.get_attribute ("version");
2036 if (lower_case_cprefix
!= null) {
2037 int idx
= lower_case_cprefix
.index_of (",");
2039 lower_case_cprefix
= lower_case_cprefix
.substring (0, idx
);
2043 if (provided_namespaces
.contains ("%s-%s".printf (gir_namespace
, gir_version
))) {
2048 // load metadata, first look into metadata directories then in the same directory of the .gir.
2049 string? metadata_filename
= context
.get_metadata_path (current_source_file
.filename
);
2050 if (metadata_filename
!= null && FileUtils
.test (metadata_filename
, FileTest
.EXISTS
)) {
2051 var metadata_parser
= new
MetadataParser ();
2052 var metadata_file
= new
SourceFile (context
, current_source_file
.file_type
, metadata_filename
);
2053 context
.add_source_file (metadata_file
);
2054 metadata
= metadata_parser
.parse_metadata (metadata_file
);
2055 metadata_roots
.add (metadata
);
2058 var ns_metadata
= metadata
.match_child (gir_namespace
);
2059 if (ns_metadata
.has_argument (ArgumentType
.NAME
)) {
2060 vala_namespace
= ns_metadata
.get_string (ArgumentType
.NAME
);
2062 if (vala_namespace
== null) {
2063 vala_namespace
= gir_namespace
;
2066 current_source_file
.gir_namespace
= gir_namespace
;
2067 current_source_file
.gir_version
= gir_version
;
2070 push_node (vala_namespace
, true);
2071 if (current
.new_symbol
) {
2072 ns
= new
Namespace (vala_namespace
, current
.source_reference
);
2073 current
.symbol
= ns
;
2075 ns
= (Namespace
) current
.symbol
;
2076 ns
.attributes
= null;
2077 ns
.source_reference
= current
.source_reference
;
2080 current
.metadata
= ns_metadata
;
2082 if (ns_metadata
.has_argument (ArgumentType
.CPREFIX
)) {
2083 cprefix
= ns_metadata
.get_string (ArgumentType
.CPREFIX
);
2086 if (ns_metadata
.has_argument (ArgumentType
.LOWER_CASE_CPREFIX
)) {
2087 lower_case_cprefix
= ns_metadata
.get_string (ArgumentType
.LOWER_CASE_CPREFIX
);
2088 } else if (lower_case_cprefix
!= null) {
2089 lower_case_cprefix
+= "_";
2092 ns
.set_attribute_string ("CCode", "gir_namespace", gir_namespace
);
2093 ns
.set_attribute_string ("CCode", "gir_version", gir_version
);
2095 if (cprefix
!= null) {
2096 ns
.set_attribute_string ("CCode", "cprefix", cprefix
);
2097 if (lower_case_cprefix
== null) {
2098 ns
.set_attribute_string ("CCode", "lower_case_cprefix", Symbol
.camel_case_to_lower_case (cprefix
) + "_");
2102 if (lower_case_cprefix
!= null) {
2103 ns
.set_attribute_string ("CCode", "lower_case_cprefix", lower_case_cprefix
);
2106 if (cheader_filenames
!= null) {
2107 ns
.set_attribute_string ("CCode", "cheader_filename", string.joinv (",", cheader_filenames
));
2111 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2112 if (!push_metadata ()) {
2117 if (reader
.name
== "alias") {
2119 } else if (reader
.name
== "enumeration") {
2120 if (metadata
.has_argument (ArgumentType
.ERRORDOMAIN
)) {
2121 if (metadata
.get_bool (ArgumentType
.ERRORDOMAIN
)) {
2122 parse_error_domain ();
2124 parse_enumeration ();
2127 if ((reader
.get_attribute ("glib:error-quark") != null) || (reader
.get_attribute ("glib:error-domain") != null)) {
2128 parse_error_domain ();
2130 parse_enumeration ();
2133 } else if (reader
.name
== "bitfield") {
2135 } else if (reader
.name
== "function") {
2136 parse_method ("function");
2137 } else if (reader
.name
== "callback") {
2139 } else if (reader
.name
== "record") {
2140 if (metadata
.has_argument (ArgumentType
.STRUCT
)) {
2141 if (metadata
.get_bool (ArgumentType
.STRUCT
)) {
2144 parse_boxed ("record");
2146 } else if (element_get_type_id () != null) {
2147 parse_boxed ("record");
2148 } else if (!reader
.get_attribute ("name").has_suffix ("Private")) {
2149 if (reader
.get_attribute ("glib:is-gtype-struct-for") == null && reader
.get_attribute ("disguised") == "1") {
2150 parse_boxed ("record");
2157 } else if (reader
.name
== "class") {
2159 } else if (reader
.name
== "interface") {
2161 } else if (reader
.name
== "glib:boxed") {
2162 parse_boxed ("glib:boxed");
2163 } else if (reader
.name
== "union") {
2164 if (element_get_type_id () != null && !metadata
.get_bool (ArgumentType
.STRUCT
)) {
2165 parse_boxed ("union");
2169 } else if (reader
.name
== "constant") {
2173 Report
.error (get_current_src (), "unknown child element `%s' in `namespace'".printf (reader
.name
));
2180 end_element ("namespace");
2183 void parse_alias () {
2184 start_element ("alias");
2185 push_node (element_get_name (), true);
2186 // not enough information, symbol will be created while processing the tree
2190 if (current
.comment
== null) {
2191 current
.comment
= parse_symbol_doc ();
2193 parse_symbol_doc ();
2196 bool no_array_length
= false;
2197 bool array_null_terminated
= false;
2198 current
.base_type
= element_get_type (parse_type (null, null, true), true, ref no_array_length
, ref array_null_terminated
);
2200 if (metadata
.has_argument (ArgumentType
.BASE_TYPE
)) {
2201 current
.base_type
= parse_type_from_string (metadata
.get_string (ArgumentType
.BASE_TYPE
), true, metadata
.get_source_reference (ArgumentType
.BASE_TYPE
));
2205 end_element ("alias");
2208 private void calculate_common_prefix (ref string? common_prefix
, string cname
) {
2209 if (common_prefix
== null) {
2210 common_prefix
= cname
;
2211 while (common_prefix
.length
> 0 && !common_prefix
.has_suffix ("_")) {
2212 // FIXME: could easily be made faster
2213 common_prefix
= common_prefix
.substring (0, common_prefix
.length
- 1);
2216 while (!cname
.has_prefix (common_prefix
)) {
2217 common_prefix
= common_prefix
.substring (0, common_prefix
.length
- 1);
2220 while (common_prefix
.length
> 0 && (!common_prefix
.has_suffix ("_") ||
2221 (cname
.get_char (common_prefix
.length
).isdigit ()) && (cname
.length
- common_prefix
.length
) <= 1)) {
2222 // enum values may not consist solely of digits
2223 common_prefix
= common_prefix
.substring (0, common_prefix
.length
- 1);
2227 GirComment?
parse_symbol_doc () {
2228 GirComment? comment
= null;
2230 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2231 unowned
string reader_name
= reader
.name
;
2233 if (reader_name
== "doc") {
2234 start_element ("doc");
2238 if (current_token
== MarkupTokenType
.TEXT
) {
2239 comment
= new
GirComment (reader
.content
, current
.source_reference
);
2243 end_element ("doc");
2244 } else if (reader_name
== "doc-version" || reader_name
== "doc-deprecated" || reader_name
== "doc-stability") {
2254 Comment?
parse_doc () {
2255 Comment? comment
= null;
2257 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2258 unowned
string reader_name
= reader
.name
;
2260 if (reader_name
== "doc") {
2261 start_element ("doc");
2265 if (current_token
== MarkupTokenType
.TEXT
) {
2266 comment
= new
Comment (reader
.content
, current
.source_reference
);
2270 end_element ("doc");
2271 } else if (reader_name
== "doc-version" || reader_name
== "doc-deprecated" || reader_name
== "doc-stability") {
2281 void parse_enumeration (string element_name
= "enumeration", bool error_domain
= false) {
2282 start_element (element_name
);
2283 push_node (element_get_name (), true);
2286 if (current
.new_symbol
) {
2288 sym
= new
ErrorDomain (current
.name
, current
.source_reference
);
2290 var en
= new
Enum (current
.name
, current
.source_reference
);
2291 if (element_name
== "bitfield") {
2292 en
.set_attribute ("Flags", true);
2296 current
.symbol
= sym
;
2298 sym
= current
.symbol
;
2302 set_type_id_ccode (sym
);
2304 sym
.external
= true;
2305 sym
.access
= SymbolAccessibility
.PUBLIC
;
2307 string common_prefix
= null;
2308 bool has_member
= false;
2312 sym
.comment
= parse_symbol_doc ();
2314 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2315 if (!push_metadata ()) {
2320 if (reader
.name
== "member") {
2323 parse_error_member ();
2324 calculate_common_prefix (ref common_prefix
, old_current
.get_cname ());
2326 parse_enumeration_member ();
2327 calculate_common_prefix (ref common_prefix
, old_current
.get_cname ());
2329 } else if (reader
.name
== "function") {
2333 Report
.error (get_current_src (), "unknown child element `%s' in `%s'".printf (reader
.name
, element_name
));
2341 Report
.error (get_current_src (), "%s `%s' has no members".printf (element_name
, current
.name
));
2344 if (common_prefix
!= null) {
2345 sym
.set_attribute_string ("CCode", "cprefix", common_prefix
);
2349 end_element (element_name
);
2352 void parse_error_domain () {
2353 parse_enumeration ("enumeration", true);
2356 void parse_bitfield () {
2357 parse_enumeration ("bitfield");
2360 void parse_enumeration_member () {
2361 start_element ("member");
2362 push_node (element_get_name().ascii_up().replace ("-", "_"), false);
2364 var ev
= new
EnumValue (current
.name
, metadata
.get_expression (ArgumentType
.DEFAULT
), current
.source_reference
);
2365 current
.symbol
= ev
;
2368 ev
.comment
= parse_symbol_doc ();
2371 end_element ("member");
2374 void parse_error_member () {
2375 start_element ("member");
2376 push_node (element_get_name().ascii_up().replace ("-", "_"), false);
2379 string value
= reader
.get_attribute ("value");
2380 if (value
!= null) {
2381 ec
= new ErrorCode
.with_value (current
.name
, new
IntegerLiteral (value
));
2383 ec
= new
ErrorCode (current
.name
);
2385 current
.symbol
= ec
;
2388 ec
.comment
= parse_symbol_doc ();
2391 end_element ("member");
2394 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) {
2395 start_element ("return-value");
2397 string transfer
= reader
.get_attribute ("transfer-ownership");
2398 string nullable
= reader
.get_attribute ("nullable");
2399 string allow_none
= reader
.get_attribute ("allow-none");
2402 comment
= parse_doc ();
2404 var transfer_elements
= transfer
!= "container";
2405 var type
= parse_type (out ctype
, out array_length_idx
, transfer_elements
, out no_array_length
, out array_null_terminated
);
2406 if (transfer
== "full" || transfer
== "container") {
2407 type
.value_owned
= true;
2409 if (nullable
== "1" || allow_none
== "1") {
2410 type
.nullable
= true;
2412 type
= element_get_type (type
, true, ref no_array_length
, ref array_null_terminated
);
2414 // FIXME No support for fixed-size array as return-value
2415 var array_type
= type as ArrayType
;
2416 if (array_type
!= null && array_type
.fixed_length
) {
2417 array_type
.fixed_length
= false;
2418 array_type
.length
= null;
2421 end_element ("return-value");
2425 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) {
2428 array_length_idx
= -1;
2432 string element_type
= reader
.name
;
2433 if (current_token
!= MarkupTokenType
.START_ELEMENT
|| (element_type
!= "parameter" && element_type
!= "instance-parameter")) {
2434 Report
.error (get_current_src (), "expected start element of `parameter' or `instance-parameter'");
2436 start_element (element_type
);
2437 var name
= metadata
.get_string (ArgumentType
.NAME
);
2439 name
= reader
.get_attribute ("name");
2442 name
= default_name
;
2444 string direction
= null;
2445 if (metadata
.has_argument (ArgumentType
.OUT
)) {
2446 if (metadata
.get_bool (ArgumentType
.OUT
)) {
2449 } else if (metadata
.has_argument (ArgumentType
.REF
)) {
2450 if (metadata
.get_bool (ArgumentType
.REF
)) {
2451 direction
= "inout";
2454 direction
= reader
.get_attribute ("direction");
2456 string transfer
= reader
.get_attribute ("transfer-ownership");
2457 string nullable
= reader
.get_attribute ("nullable");
2458 string allow_none
= reader
.get_attribute ("allow-none");
2460 scope
= element_get_string ("scope", ArgumentType
.SCOPE
);
2462 string closure
= reader
.get_attribute ("closure");
2463 string destroy
= reader
.get_attribute ("destroy");
2464 if (closure
!= null && &closure_idx
!= null) {
2465 closure_idx
= int.parse (closure
);
2467 if (destroy
!= null && &destroy_idx
!= null) {
2468 destroy_idx
= int.parse (destroy
);
2470 if (metadata
.has_argument (ArgumentType
.CLOSURE
)) {
2471 closure_idx
= metadata
.get_integer (ArgumentType
.CLOSURE
);
2473 if (metadata
.has_argument (ArgumentType
.DESTROY
)) {
2474 destroy_idx
= metadata
.get_integer (ArgumentType
.DESTROY
);
2479 comment
= parse_doc ();
2481 if (reader
.name
== "varargs") {
2482 start_element ("varargs");
2484 param
= new Parameter
.with_ellipsis (get_current_src ());
2485 end_element ("varargs");
2488 bool no_array_length
;
2489 bool array_null_terminated
;
2490 var type
= parse_type (out ctype
, out array_length_idx
, transfer
!= "container", out no_array_length
, out array_null_terminated
);
2491 if (transfer
== "full" || transfer
== "container" || destroy
!= null) {
2492 type
.value_owned
= true;
2494 if (nullable
== "1" || (allow_none
== "1" && direction
!= "out")) {
2495 type
.nullable
= true;
2499 type
= element_get_type (type
, direction
== "out" || direction
== "inout", ref no_array_length
, ref array_null_terminated
, out changed
);
2501 // discard ctype, duplicated information
2505 param
= new
Parameter (name
, type
, get_current_src ());
2506 if (ctype
!= null) {
2507 param
.set_attribute_string ("CCode", "type", ctype
);
2509 if (direction
== "out") {
2510 param
.direction
= ParameterDirection
.OUT
;
2511 } else if (direction
== "inout") {
2512 param
.direction
= ParameterDirection
.REF
;
2514 if (type is ArrayType
) {
2515 if (metadata
.has_argument (ArgumentType
.ARRAY_LENGTH_IDX
)) {
2516 array_length_idx
= metadata
.get_integer (ArgumentType
.ARRAY_LENGTH_IDX
);
2518 if (no_array_length
|| array_null_terminated
) {
2519 param
.set_attribute_bool ("CCode", "array_length", !no_array_length
);
2521 if (array_null_terminated
) {
2522 param
.set_attribute_bool ("CCode", "array_null_terminated", array_null_terminated
);
2526 param
.initializer
= metadata
.get_expression (ArgumentType
.DEFAULT
);
2528 // empty tuple used for parameters without initializer
2529 if (param
.initializer is Tuple
) {
2530 param
.initializer
= null;
2533 end_element (element_type
);
2537 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) {
2538 bool is_array
= false;
2539 string type_name
= reader
.get_attribute ("name");
2542 var fixed_length
= -1;
2543 array_length_idx
= -1;
2544 no_array_length
= true;
2545 array_null_terminated
= true;
2547 if (reader
.name
== "array") {
2549 start_element ("array");
2551 var src
= get_current_src ();
2553 if (type_name
== null) {
2554 if (reader
.get_attribute ("length") != null) {
2555 array_length_idx
= int.parse (reader
.get_attribute ("length"));
2556 no_array_length
= false;
2557 array_null_terminated
= false;
2559 if (reader
.get_attribute ("fixed-size") != null) {
2560 fixed_length
= int.parse (reader
.get_attribute ("fixed-size"));
2561 array_null_terminated
= false;
2563 if (reader
.get_attribute ("c:type") == "GStrv") {
2564 no_array_length
= true;
2565 array_null_terminated
= true;
2567 if (reader
.get_attribute ("zero-terminated") != null) {
2568 array_null_terminated
= int.parse (reader
.get_attribute ("zero-terminated")) != 0;
2571 var element_type
= parse_type ();
2572 element_type
.value_owned
= transfer_elements
;
2573 end_element ("array");
2575 var array_type
= new
ArrayType (element_type
, 1, src
);
2576 if (fixed_length
> 0) {
2577 array_type
.fixed_length
= true;
2578 array_type
.length
= new
IntegerLiteral (fixed_length
.to_string ());
2582 } else if (reader
.name
== "callback"){
2584 return new
DelegateType ((Delegate
) old_current
.symbol
);
2586 start_element ("type");
2589 ctype
= reader
.get_attribute("c:type");
2593 if (type_name
== "GLib.PtrArray"
2594 && current_token
== MarkupTokenType
.START_ELEMENT
) {
2595 type_name
= "GLib.GenericArray";
2598 if (type_name
== null) {
2602 DataType type
= parse_type_from_gir_name (type_name
, out no_array_length
, out array_null_terminated
, ctype
);
2604 // type arguments / element types
2605 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2606 if (type_name
== "GLib.ByteArray") {
2610 var element_type
= parse_type ();
2611 element_type
.value_owned
= transfer_elements
;
2612 type
.add_type_argument (element_type
);
2613 unresolved_type_arguments
.add (element_type
);
2616 end_element (is_array ?
"array" : "type");
2620 DataType
parse_type_from_gir_name (string type_name
, out bool no_array_length
= null, out bool array_null_terminated
= null, string? ctype
= null) {
2621 no_array_length
= false;
2622 array_null_terminated
= false;
2624 DataType? type
= null;
2625 if (type_name
== "none") {
2626 type
= new
VoidType (get_current_src ());
2627 } else if (type_name
== "gpointer") {
2628 type
= new
PointerType (new
VoidType (get_current_src ()), get_current_src ());
2629 } else if (type_name
== "GObject.Strv") {
2630 var element_type
= new UnresolvedType
.from_symbol (new
UnresolvedSymbol (null, "string"));
2631 element_type
.value_owned
= true;
2632 type
= new
ArrayType (element_type
, 1, get_current_src ());
2633 no_array_length
= true;
2634 array_null_terminated
= true;
2636 bool known_type
= true;
2637 if (type_name
== "utf8") {
2638 type_name
= "string";
2639 } else if (type_name
== "gboolean") {
2640 type
= new
BooleanType ((Struct
) context
.root
.scope
.lookup ("bool"));
2641 } else if (type_name
== "gchar") {
2643 } else if (type_name
== "gshort") {
2644 type_name
= "short";
2645 } else if (type_name
== "gushort") {
2646 type_name
= "ushort";
2647 } else if (type_name
== "gint") {
2649 } else if (type_name
== "guint") {
2651 } else if (type_name
== "glong") {
2652 if (ctype
!= null && ctype
.has_prefix ("gssize")) {
2653 type_name
= "ssize_t";
2654 } else if (ctype
!= null && ctype
.has_prefix ("gintptr")) {
2655 type_name
= "intptr";
2659 } else if (type_name
== "gulong") {
2660 if (ctype
!= null && ctype
.has_prefix ("gsize")) {
2661 type_name
= "size_t";
2662 } else if (ctype
!= null && ctype
.has_prefix ("guintptr")) {
2663 type_name
= "uintptr";
2665 type_name
= "ulong";
2667 } else if (type_name
== "gint8") {
2669 } else if (type_name
== "guint8") {
2670 type_name
= "uint8";
2671 } else if (type_name
== "gint16") {
2672 type_name
= "int16";
2673 } else if (type_name
== "guint16") {
2674 type_name
= "uint16";
2675 } else if (type_name
== "gint32") {
2676 type_name
= "int32";
2677 } else if (type_name
== "guint32") {
2678 type_name
= "uint32";
2679 } else if (type_name
== "gint64") {
2680 type_name
= "int64";
2681 } else if (type_name
== "guint64") {
2682 type_name
= "uint64";
2683 } else if (type_name
== "gfloat") {
2684 type_name
= "float";
2685 } else if (type_name
== "gdouble") {
2686 type_name
= "double";
2687 } else if (type_name
== "filename") {
2688 type_name
= "string";
2689 } else if (type_name
== "GLib.offset") {
2690 type_name
= "int64";
2691 } else if (type_name
== "gsize") {
2692 type_name
= "size_t";
2693 } else if (type_name
== "gssize") {
2694 type_name
= "ssize_t";
2695 } else if (type_name
== "guintptr") {
2696 type_name
= "uintptr";
2697 } else if (type_name
== "gintptr") {
2698 type_name
= "intptr";
2699 } else if (type_name
== "GType") {
2700 type_name
= "GLib.Type";
2701 } else if (type_name
== "GLib.String") {
2702 type_name
= "GLib.StringBuilder";
2703 } else if (type_name
== "GObject.Class") {
2704 type_name
= "GLib.ObjectClass";
2705 } else if (type_name
== "gunichar") {
2706 type_name
= "unichar";
2707 } else if (type_name
== "GLib.Data") {
2708 type_name
= "GLib.Datalist";
2709 } else if (type_name
== "Atk.ImplementorIface") {
2710 type_name
= "Atk.Implementor";
2716 var sym
= parse_symbol_from_string (type_name
, get_current_src ());
2717 type
= new UnresolvedType
.from_symbol (sym
, get_current_src ());
2719 unresolved_gir_symbols
.add (sym
);
2727 void parse_record () {
2728 start_element ("record");
2729 push_node (element_get_name (), true);
2732 if (current
.new_symbol
) {
2733 st
= new
Struct (element_get_name (), current
.source_reference
);
2734 current
.symbol
= st
;
2736 st
= (Struct
) current
.symbol
;
2739 set_type_id_ccode (st
);
2742 st
.access
= SymbolAccessibility
.PUBLIC
;
2744 var gtype_struct_for
= reader
.get_attribute ("glib:is-gtype-struct-for");
2745 if (gtype_struct_for
!= null) {
2746 current
.gtype_struct_for
= parse_symbol_from_string (gtype_struct_for
, current
.source_reference
);
2747 unresolved_gir_symbols
.add (current
.gtype_struct_for
);
2750 bool first_field
= true;
2753 st
.comment
= parse_symbol_doc ();
2755 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2756 if (!push_metadata ()) {
2757 if (first_field
&& reader
.name
== "field") {
2758 first_field
= false;
2764 if (reader
.name
== "field") {
2765 if (reader
.get_attribute ("name") != "priv" && !(first_field
&& gtype_struct_for
!= null)) {
2770 first_field
= false;
2771 } else if (reader
.name
== "constructor") {
2772 parse_constructor ();
2773 } else if (reader
.name
== "method") {
2774 parse_method ("method");
2775 } else if (reader
.name
== "function") {
2777 } else if (reader
.name
== "union") {
2781 Report
.error (get_current_src (), "unknown child element `%s' in `record'".printf (reader
.name
));
2789 end_element ("record");
2792 void parse_class () {
2793 start_element ("class");
2794 push_node (element_get_name (), true);
2797 var parent
= reader
.get_attribute ("parent");
2798 if (current
.new_symbol
) {
2799 cl
= new
Class (current
.name
, current
.source_reference
);
2800 cl
.is_abstract
= metadata
.get_bool (ArgumentType
.ABSTRACT
, reader
.get_attribute ("abstract") == "1");
2802 if (parent
!= null) {
2803 cl
.add_base_type (parse_type_from_gir_name (parent
));
2805 current
.symbol
= cl
;
2807 cl
= (Class
) current
.symbol
;
2810 set_type_id_ccode (cl
);
2812 cl
.access
= SymbolAccessibility
.PUBLIC
;
2817 cl
.comment
= parse_symbol_doc ();
2819 var first_field
= true;
2820 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2821 if (!push_metadata ()) {
2822 if (first_field
&& reader
.name
== "field") {
2823 first_field
= false;
2829 if (reader
.name
== "implements") {
2830 start_element ("implements");
2831 cl
.add_base_type (parse_type_from_gir_name (reader
.get_attribute ("name")));
2833 end_element ("implements");
2834 } else if (reader
.name
== "constant") {
2836 } else if (reader
.name
== "field") {
2837 if (first_field
&& parent
!= null) {
2838 // first field is guaranteed to be the parent instance
2841 if (reader
.get_attribute ("name") != "priv") {
2847 first_field
= false;
2848 } else if (reader
.name
== "property") {
2850 } else if (reader
.name
== "constructor") {
2851 parse_constructor ();
2852 } else if (reader
.name
== "function") {
2853 parse_method ("function");
2854 } else if (reader
.name
== "method") {
2855 parse_method ("method");
2856 } else if (reader
.name
== "virtual-method") {
2857 parse_method ("virtual-method");
2858 } else if (reader
.name
== "union") {
2860 } else if (reader
.name
== "glib:signal") {
2864 Report
.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader
.name
));
2872 end_element ("class");
2875 void parse_interface () {
2876 start_element ("interface");
2877 push_node (element_get_name (), true);
2880 if (current
.new_symbol
) {
2881 iface
= new
Interface (current
.name
, current
.source_reference
);
2882 current
.symbol
= iface
;
2884 iface
= (Interface
) current
.symbol
;
2887 set_type_id_ccode (iface
);
2889 iface
.access
= SymbolAccessibility
.PUBLIC
;
2890 iface
.external
= true;
2895 iface
.comment
= parse_symbol_doc ();
2897 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
2898 if (!push_metadata ()) {
2903 if (reader
.name
== "prerequisite") {
2904 start_element ("prerequisite");
2905 iface
.add_prerequisite (parse_type_from_gir_name (reader
.get_attribute ("name")));
2907 end_element ("prerequisite");
2908 } else if (reader
.name
== "field") {
2910 } else if (reader
.name
== "property") {
2912 } else if (reader
.name
== "virtual-method") {
2913 parse_method ("virtual-method");
2914 } else if (reader
.name
== "function") {
2915 parse_method ("function");
2916 } else if (reader
.name
== "method") {
2917 parse_method ("method");
2918 } else if (reader
.name
== "glib:signal") {
2922 Report
.error (get_current_src (), "unknown child element `%s' in `interface'".printf (reader
.name
));
2930 end_element ("interface");
2933 void parse_field () {
2934 start_element ("field");
2935 push_node (element_get_name (), false);
2937 string nullable
= reader
.get_attribute ("nullable");
2938 string allow_none
= reader
.get_attribute ("allow-none");
2941 var comment
= parse_symbol_doc ();
2943 bool no_array_length
;
2944 bool array_null_terminated
;
2945 int array_length_idx
;
2946 var type
= parse_type (null, out array_length_idx
, true, out no_array_length
, out array_null_terminated
);
2947 type
= element_get_type (type
, true, ref no_array_length
, ref array_null_terminated
);
2949 string name
= current
.name
;
2950 string cname
= current
.girdata
["name"];
2952 var field
= new
Field (name
, type
, null, current
.source_reference
);
2953 field
.access
= SymbolAccessibility
.PUBLIC
;
2954 field
.comment
= comment
;
2955 if (name
!= cname
) {
2956 field
.set_attribute_string ("CCode", "cname", cname
);
2958 if (type is ArrayType
) {
2959 if (!no_array_length
&& array_length_idx
> -1) {
2960 current
.array_length_idx
= array_length_idx
;
2962 if (no_array_length
|| array_null_terminated
) {
2963 field
.set_attribute_bool ("CCode", "array_length", !no_array_length
);
2965 if (array_null_terminated
) {
2966 field
.set_attribute_bool ("CCode", "array_null_terminated", true);
2969 if (nullable
== "1" || allow_none
== "1") {
2970 type
.nullable
= true;
2972 current
.symbol
= field
;
2975 end_element ("field");
2978 Property
parse_property () {
2979 start_element ("property");
2980 push_node (element_get_name().replace ("-", "_"), false);
2981 bool is_abstract
= metadata
.get_bool (ArgumentType
.ABSTRACT
, current
.parent
.symbol is Interface
);
2982 string transfer
= reader
.get_attribute ("transfer-ownership");
2986 var comment
= parse_symbol_doc ();
2988 bool no_array_length
;
2989 bool array_null_terminated
;
2990 var type
= parse_type (null, null, transfer
!= "container", out no_array_length
, out array_null_terminated
);
2991 type
= element_get_type (type
, true, ref no_array_length
, ref array_null_terminated
);
2992 var prop
= new
Property (current
.name
, type
, null, null, current
.source_reference
);
2993 prop
.comment
= comment
;
2994 prop
.access
= SymbolAccessibility
.PUBLIC
;
2995 prop
.external
= true;
2996 prop
.is_abstract
= is_abstract
;
2997 if (no_array_length
|| array_null_terminated
) {
2998 prop
.set_attribute_bool ("CCode", "array_length", !no_array_length
);
3000 if (array_null_terminated
) {
3001 prop
.set_attribute_bool ("CCode", "array_null_terminated", true);
3003 current
.symbol
= prop
;
3006 end_element ("property");
3010 void parse_callback () {
3011 parse_function ("callback");
3014 void parse_constructor () {
3015 parse_function ("constructor");
3018 class ParameterInfo
{
3019 public ParameterInfo (Parameter param
, int array_length_idx
, int closure_idx
, int destroy_idx
, bool is_async
= false) {
3021 this
.array_length_idx
= array_length_idx
;
3022 this
.closure_idx
= closure_idx
;
3023 this
.destroy_idx
= destroy_idx
;
3024 this
.vala_idx
= 0.0F
;
3026 this
.is_async
= is_async
;
3029 public Parameter param
;
3030 public float vala_idx
;
3031 public int array_length_idx
;
3032 public int closure_idx
;
3033 public int destroy_idx
;
3035 public bool is_async
;
3038 void parse_function (string element_name
) {
3039 start_element (element_name
);
3040 push_node (element_get_name (reader
.get_attribute ("invoker")).replace ("-", "_"), false);
3043 if (metadata
.has_argument (ArgumentType
.SYMBOL_TYPE
)) {
3044 symbol_type
= metadata
.get_string (ArgumentType
.SYMBOL_TYPE
);
3046 symbol_type
= element_name
;
3049 string name
= current
.name
;
3050 string throws_string
= reader
.get_attribute ("throws");
3051 string invoker
= reader
.get_attribute ("invoker");
3055 var comment
= parse_symbol_doc ();
3057 DataType return_type
;
3058 string return_ctype
= null;
3059 int return_array_length_idx
= -1;
3060 bool return_no_array_length
= false;
3061 bool return_array_null_terminated
= false;
3062 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "return-value") {
3063 Comment? return_comment
;
3064 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
);
3065 if (return_comment
!= null) {
3066 if (comment
== null) {
3067 comment
= new
GirComment (null, current
.source_reference
);
3069 comment
.return_content
= return_comment
;
3072 return_type
= new
VoidType ();
3077 if (symbol_type
== "callback") {
3078 s
= new
Delegate (name
, return_type
, current
.source_reference
);
3079 ((Delegate
) s
).has_target
= false;
3080 } else if (symbol_type
== "constructor") {
3081 if (name
== "new") {
3083 } else if (name
.has_prefix ("new_")) {
3084 name
= name
.substring ("new_".length
);
3086 var m
= new
CreationMethod (null, name
, current
.source_reference
);
3087 m
.has_construct_function
= false;
3089 if (name
!= null && !current
.name
.has_prefix ("new_")) {
3090 m
.set_attribute_string ("CCode", "cname", current
.girdata
["c:identifier"]);
3093 string parent_ctype
= null;
3094 if (current
.parent
.symbol is Class
) {
3095 parent_ctype
= current
.parent
.get_cname ();
3097 if (return_ctype
!= null && (parent_ctype
== null || return_ctype
!= parent_ctype
+ "*")) {
3098 m
.set_attribute_string ("CCode", "type", return_ctype
);
3101 } else if (symbol_type
== "glib:signal") {
3102 s
= new
Signal (name
, return_type
, current
.source_reference
);
3104 s
= new
Method (name
, return_type
, current
.source_reference
);
3107 s
.access
= SymbolAccessibility
.PUBLIC
;
3108 s
.comment
= comment
;
3112 if (current
.girdata
["name"] != name
.replace ("_", "-")) {
3113 s
.set_attribute_string ("CCode", "cname", current
.girdata
["name"]);
3119 if (symbol_type
== "virtual-method" || symbol_type
== "callback") {
3120 if (current
.parent
.symbol is Interface
) {
3121 m
.is_abstract
= true;
3123 m
.is_virtual
= true;
3125 if (invoker
== null && !metadata
.has_argument (ArgumentType
.VFUNC_NAME
)) {
3126 s
.set_attribute ("NoWrapper", true, s
.source_reference
);
3127 } if (current
.girdata
["name"] != name
) {
3128 m
.set_attribute_string ("CCode", "vfunc_name", current
.girdata
["name"]);
3130 } else if (symbol_type
== "function") {
3131 m
.binding
= MemberBinding
.STATIC
;
3133 if (metadata
.has_argument (ArgumentType
.FLOATING
)) {
3134 m
.returns_floating_reference
= metadata
.get_bool (ArgumentType
.FLOATING
);
3135 m
.return_type
.value_owned
= true;
3139 if (s is Method
&& !(s is CreationMethod
)) {
3140 var method
= (Method
) s
;
3141 if (metadata
.has_argument (ArgumentType
.VIRTUAL
)) {
3142 method
.is_virtual
= metadata
.get_bool (ArgumentType
.VIRTUAL
);
3143 method
.is_abstract
= false;
3144 } else if (metadata
.has_argument (ArgumentType
.ABSTRACT
)) {
3145 method
.is_abstract
= metadata
.get_bool (ArgumentType
.ABSTRACT
);
3146 method
.is_virtual
= false;
3148 if (metadata
.has_argument (ArgumentType
.VFUNC_NAME
)) {
3149 method
.set_attribute_string ("CCode", "vfunc_name", metadata
.get_string (ArgumentType
.VFUNC_NAME
));
3150 method
.is_virtual
= true;
3152 if (metadata
.has_argument (ArgumentType
.FINISH_VFUNC_NAME
)) {
3153 method
.set_attribute_string ("CCode", "finish_vfunc_name", metadata
.get_string (ArgumentType
.FINISH_VFUNC_NAME
));
3154 method
.is_virtual
= true;
3158 if (!(metadata
.get_expression (ArgumentType
.THROWS
) is NullLiteral
)) {
3159 if (metadata
.has_argument (ArgumentType
.THROWS
)) {
3160 var error_types
= metadata
.get_string(ArgumentType
.THROWS
).split(",");
3161 foreach (var error_type
in error_types
) {
3162 s
.add_error_type (parse_type_from_string (error_type
, true, metadata
.get_source_reference (ArgumentType
.THROWS
)));
3164 } else if (throws_string
== "1") {
3165 s
.add_error_type (new
ErrorType (null, null));
3171 m
.set_attribute ("PrintfFormat", metadata
.get_bool (ArgumentType
.PRINTF_FORMAT
));
3172 if (metadata
.has_argument (ArgumentType
.SENTINEL
)) {
3173 m
.set_attribute_string ("CCode", "sentinel", metadata
.get_string (ArgumentType
.SENTINEL
));
3177 if (return_type is ArrayType
&& metadata
.has_argument (ArgumentType
.ARRAY_LENGTH_IDX
)) {
3178 return_array_length_idx
= metadata
.get_integer (ArgumentType
.ARRAY_LENGTH_IDX
);
3180 if (return_no_array_length
|| return_array_null_terminated
) {
3181 s
.set_attribute_bool ("CCode", "array_length", !return_no_array_length
);
3183 if (return_array_null_terminated
) {
3184 s
.set_attribute_bool ("CCode", "array_null_terminated", true);
3187 current
.return_array_length_idx
= return_array_length_idx
;
3191 if (metadata
.has_argument (ArgumentType
.FINISH_NAME
)) {
3192 s
.set_attribute_string ("CCode", "finish_name", metadata
.get_string (ArgumentType
.FINISH_NAME
));
3194 if (metadata
.has_argument (ArgumentType
.FINISH_INSTANCE
)) {
3195 s
.set_attribute_bool ("CCode", "finish_instance", metadata
.get_bool (ArgumentType
.FINISH_INSTANCE
));
3198 int instance_idx
= -2;
3199 if (element_name
== "function" && symbol_type
== "method") {
3200 if (metadata
.has_argument (ArgumentType
.INSTANCE_IDX
)) {
3201 instance_idx
= metadata
.get_integer (ArgumentType
.INSTANCE_IDX
);
3202 if (instance_idx
!= 0) {
3203 s
.set_attribute_double ("CCode", "instance_pos", instance_idx
+ 0.5);
3206 Report
.error (get_current_src (), "instance_idx required when converting function to method");
3210 var parameters
= new ArrayList
<ParameterInfo
> ();
3211 current
.array_length_parameters
= new ArrayList
<int> ();
3212 current
.closure_parameters
= new ArrayList
<int> ();
3213 current
.destroy_parameters
= new ArrayList
<int> ();
3214 if (current_token
== MarkupTokenType
.START_ELEMENT
&& reader
.name
== "parameters") {
3215 start_element ("parameters");
3218 var current_parameter_idx
= -1;
3219 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
3220 current_parameter_idx
++;
3222 if (reader
.name
== "instance-parameter" &&
3223 !(symbol_type
== "function" || symbol_type
== "constructor")) {
3228 if (instance_idx
> -2 && instance_idx
== current_parameter_idx
) {
3233 if (!push_metadata ()) {
3238 int array_length_idx
, closure_idx
, destroy_idx
;
3240 string default_param_name
= null;
3241 Comment? param_comment
;
3242 default_param_name
= "arg%d".printf (parameters
.size
);
3243 var param
= parse_parameter (out array_length_idx
, out closure_idx
, out destroy_idx
, out scope
, out param_comment
, default_param_name
);
3244 if (array_length_idx
!= -1) {
3245 if (instance_idx
> -2 && instance_idx
< array_length_idx
) {
3248 current
.array_length_parameters
.add (array_length_idx
);
3250 if (closure_idx
!= -1) {
3251 if (instance_idx
> -2 && instance_idx
< closure_idx
) {
3254 if (current
.closure_parameters
.index_of (current_parameter_idx
) < 0) {
3255 current
.closure_parameters
.add (closure_idx
);
3258 if (destroy_idx
!= -1) {
3259 if (instance_idx
> -2 && instance_idx
< destroy_idx
) {
3262 if (current
.destroy_parameters
.index_of (current_parameter_idx
) < 0) {
3263 current
.destroy_parameters
.add (destroy_idx
);
3266 if (param_comment
!= null) {
3267 if (comment
== null) {
3268 comment
= new
GirComment (null, s
.source_reference
);
3269 s
.comment
= comment
;
3272 comment
.add_content_for_parameter ((param
.ellipsis
)?
"..." : param
.name
, param_comment
);
3275 var info
= new
ParameterInfo (param
, array_length_idx
, closure_idx
, destroy_idx
, scope
== "async");
3277 if (s is Method
&& scope
== "async") {
3278 var unresolved_type
= param
.variable_type as UnresolvedType
;
3279 if (unresolved_type
!= null && unresolved_type
.unresolved_symbol
.name
== "AsyncReadyCallback") {
3280 // GAsync-style method
3281 ((Method
) s
).coroutine
= true;
3286 parameters
.add (info
);
3289 end_element ("parameters");
3291 current
.parameters
= parameters
;
3293 for (int param_n
= parameters
.size
- 1 ; param_n
>= 0 ; param_n
--) {
3294 ParameterInfo pi
= parameters
[param_n
];
3295 if (!pi
.param
.ellipsis
&& pi
.param
.initializer
== null) {
3296 string type_string
= pi
.param
.variable_type
.to_string ();
3297 if (type_string
== "Gio.Cancellable?") {
3298 pi
.param
.initializer
= new Vala
.NullLiteral ();
3306 end_element (element_name
);
3309 void parse_method (string element_name
) {
3310 parse_function (element_name
);
3313 void parse_signal () {
3314 parse_function ("glib:signal");
3317 void parse_boxed (string element_name
) {
3318 start_element (element_name
);
3319 string name
= reader
.get_attribute ("name");
3321 name
= reader
.get_attribute ("glib:name");
3323 push_node (element_get_name (name
), true);
3326 bool require_copy_free
= false;
3327 if (current
.new_symbol
) {
3328 cl
= new
Class (current
.name
, current
.source_reference
);
3329 cl
.is_compact
= true;
3330 current
.symbol
= cl
;
3332 cl
= (Class
) current
.symbol
;
3335 set_type_id_ccode (cl
);
3336 require_copy_free
= cl
.has_attribute_argument ("CCode", "type_id");
3338 cl
.access
= SymbolAccessibility
.PUBLIC
;
3341 if (metadata
.has_argument (ArgumentType
.BASE_TYPE
)) {
3342 cl
.add_base_type (parse_type_from_string (metadata
.get_string (ArgumentType
.BASE_TYPE
), true, metadata
.get_source_reference (ArgumentType
.BASE_TYPE
)));
3347 cl
.comment
= parse_symbol_doc ();
3349 Node? ref_method
= null;
3350 Node? unref_method
= null;
3352 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
3353 if (!push_metadata ()) {
3358 if (reader
.name
== "field") {
3360 } else if (reader
.name
== "constructor") {
3361 parse_constructor ();
3362 } else if (reader
.name
== "method") {
3363 parse_method ("method");
3364 var cname
= old_current
.get_cname ();
3365 if (cname
.has_suffix ("_ref") && (ref_method
== null || old_current
.name
== "ref")) {
3366 ref_method
= old_current
;
3367 } else if (cname
.has_suffix ("_unref") && (unref_method
== null || old_current
.name
== "unref")) {
3368 unref_method
= old_current
;
3370 } else if (reader
.name
== "function") {
3372 } else if (reader
.name
== "union") {
3376 Report
.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader
.name
));
3383 // Add ccode-attributes for ref/unref methodes if available
3384 // otherwise fallback to default g_boxed_copy/free
3385 if (cl
.has_attribute_argument ("CCode", "ref_function") || cl
.has_attribute_argument ("CCode", "unref_function")
3386 || cl
.has_attribute_argument ("CCode", "copy_function") || cl
.has_attribute_argument ("CCode", "free_function")) {
3388 } else if (ref_method
!= null && unref_method
!= null) {
3389 cl
.set_attribute_string ("CCode", "ref_function", ref_method
.get_cname ());
3390 cl
.set_attribute_string ("CCode", "unref_function", unref_method
.get_cname ());
3391 } else if (require_copy_free
) {
3392 cl
.set_attribute_string ("CCode", "copy_function", "g_boxed_copy");
3393 cl
.set_attribute_string ("CCode", "free_function", "g_boxed_free");
3397 end_element (element_name
);
3400 void parse_union () {
3401 start_element ("union");
3403 string? element_name
= element_get_name ();
3404 if (element_name
== null) {
3407 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
3408 if (!push_metadata ()) {
3413 if (reader
.name
== "field") {
3417 Report
.error (get_current_src (), "unknown child element `%s' in `transparent union'".printf (reader
.name
));
3424 end_element ("union");
3428 push_node (element_name
, true);
3431 if (current
.new_symbol
) {
3432 st
= new
Struct (reader
.get_attribute ("name"), current
.source_reference
);
3433 current
.symbol
= st
;
3435 st
= (Struct
) current
.symbol
;
3437 st
.access
= SymbolAccessibility
.PUBLIC
;
3442 st
.comment
= parse_symbol_doc ();
3444 while (current_token
== MarkupTokenType
.START_ELEMENT
) {
3445 if (!push_metadata ()) {
3450 if (reader
.name
== "field") {
3452 } else if (reader
.name
== "constructor") {
3453 parse_constructor ();
3454 } else if (reader
.name
== "method") {
3455 parse_method ("method");
3456 } else if (reader
.name
== "function") {
3458 } else if (reader
.name
== "record") {
3462 Report
.error (get_current_src (), "unknown child element `%s' in `union'".printf (reader
.name
));
3470 end_element ("union");
3473 void parse_constant () {
3474 start_element ("constant");
3475 push_node (element_get_name (), false);
3479 var comment
= parse_symbol_doc ();
3481 var type
= parse_type ();
3482 var c
= new
Constant (current
.name
, type
, null, current
.source_reference
);
3484 c
.access
= SymbolAccessibility
.PUBLIC
;
3485 c
.comment
= comment
;
3489 end_element ("constant");
3493 void report_unused_metadata (Metadata metadata
) {
3494 if (metadata
== Metadata
.empty
) {
3498 if (metadata
.args
.size
== 0 && metadata
.children
.size
== 0) {
3499 Report
.warning (metadata
.source_reference
, "empty metadata");
3503 foreach (var arg_type
in metadata
.args
.get_keys ()) {
3504 var arg
= metadata
.args
[arg_type
];
3506 // if metadata is used and argument is not, then it's a unexpected argument
3507 Report
.warning (arg
.source_reference
, "argument never used");
3511 foreach (var child
in metadata
.children
) {
3513 Report
.warning (child
.source_reference
, "metadata never used");
3515 report_unused_metadata (child
);
3522 void resolve_gir_symbols () {
3523 // gir has simple namespaces, we won't get deeper than 2 levels here, except reparenting
3524 foreach (var map_from
in unresolved_gir_symbols
) {
3525 while (map_from
!= null) {
3526 var map_to
= unresolved_symbols_map
[map_from
];
3527 if (map_to
!= null) {
3528 // remap the original symbol to match the target
3529 map_from
.inner
= null;
3530 map_from
.name
= map_to
.name
;
3531 if (map_to is UnresolvedSymbol
) {
3532 var umap_to
= (UnresolvedSymbol
) map_to
;
3533 while (umap_to
.inner
!= null) {
3534 umap_to
= umap_to
.inner
;
3535 map_from
.inner
= new
UnresolvedSymbol (null, umap_to
.name
);
3536 map_from
= map_from
.inner
;
3539 while (map_to
.parent_symbol
!= null && map_to
.parent_symbol
!= context
.root
) {
3540 map_to
= map_to
.parent_symbol
;
3541 map_from
.inner
= new
UnresolvedSymbol (null, map_to
.name
);
3542 map_from
= map_from
.inner
;
3547 map_from
= map_from
.inner
;
3552 void create_new_namespaces () {
3553 foreach (var node
in Node
.new_namespaces
) {
3554 if (node
.symbol
== null) {
3555 node
.symbol
= new
Namespace (node
.name
, node
.source_reference
);
3560 void resolve_type_arguments () {
3561 // box structs in type arguments
3562 foreach (var element_type
in unresolved_type_arguments
) {
3563 TypeSymbol sym
= null;
3564 if (element_type is UnresolvedType
) {
3565 sym
= (TypeSymbol
) resolve_symbol (root
, ((UnresolvedType
) element_type
).unresolved_symbol
);
3566 } else if (element_type
.data_type
!= null) {
3567 sym
= element_type
.data_type
;
3569 var st
= sym as Struct
;
3570 if (st
!= null && !st
.is_integer_type () && !st
.is_floating_type ()) {
3571 element_type
.nullable
= true;
3576 void process_interface (Node iface_node
) {
3577 /* Temporarily workaround G-I bug not adding GLib.Object prerequisite:
3578 ensure we have at least one instantiable prerequisite */
3579 Interface iface
= (Interface
) iface_node
.symbol
;
3580 bool has_instantiable_prereq
= false;
3581 foreach (DataType prereq
in iface
.get_prerequisites ()) {
3583 if (prereq is UnresolvedType
) {
3584 var unresolved_symbol
= ((UnresolvedType
) prereq
).unresolved_symbol
;
3585 sym
= resolve_symbol (iface_node
.parent
, unresolved_symbol
);
3587 sym
= prereq
.data_type
;
3590 has_instantiable_prereq
= true;
3595 if (!has_instantiable_prereq
) {
3596 iface
.add_prerequisite (new
ObjectType ((ObjectTypeSymbol
) glib_ns
.scope
.lookup ("Object")));
3600 void process_alias (Node alias
) {
3601 /* this is unfortunate because <alias> tag has no type information, thus we have
3602 to guess it from the base type */
3603 DataType base_type
= null;
3604 Symbol type_sym
= null;
3605 Node base_node
= null;
3606 bool simple_type
= false;
3607 if (alias
.base_type is UnresolvedType
) {
3608 base_type
= alias
.base_type
;
3609 base_node
= resolve_node (alias
.parent
, ((UnresolvedType
) base_type
).unresolved_symbol
);
3610 if (base_node
!= null) {
3611 type_sym
= base_node
.symbol
;
3613 } else if (alias
.base_type is PointerType
&& ((PointerType
) alias
.base_type
).base_type is VoidType
) {
3614 // gpointer, if it's a struct make it a simpletype
3617 base_type
= alias
.base_type
;
3618 type_sym
= base_type
.data_type
;
3619 if (type_sym
!= null) {
3620 base_node
= resolve_node (alias
.parent
, parse_symbol_from_string (type_sym
.get_full_name (), alias
.source_reference
));
3624 if (type_sym is Struct
&& ((Struct
) type_sym
).is_simple_type ()) {
3628 if (base_type
== null || type_sym
== null || type_sym is Struct
) {
3629 var st
= new
Struct (alias
.name
, alias
.source_reference
);
3630 st
.access
= SymbolAccessibility
.PUBLIC
;
3631 if (base_type
!= null) {
3632 // threat target="none" as a new struct
3633 st
.base_type
= base_type
;
3635 st
.comment
= alias
.comment
;
3637 st
.set_simple_type (simple_type
);
3639 } else if (type_sym is Class
) {
3640 var cl
= new
Class (alias
.name
, alias
.source_reference
);
3641 cl
.access
= SymbolAccessibility
.PUBLIC
;
3642 if (base_type
!= null) {
3643 cl
.add_base_type (base_type
);
3645 cl
.comment
= alias
.comment
;
3647 cl
.is_compact
= ((Class
) type_sym
).is_compact
;
3649 } else if (type_sym is Interface
) {
3650 // this is not a correct alias, but what can we do otherwise?
3651 var iface
= new
Interface (alias
.name
, alias
.source_reference
);
3652 iface
.access
= SymbolAccessibility
.PUBLIC
;
3653 if (base_type
!= null) {
3654 iface
.add_prerequisite (base_type
);
3656 iface
.comment
= alias
.comment
;
3657 iface
.external
= true;
3658 alias
.symbol
= iface
;
3659 } else if (type_sym is Delegate
) {
3660 var orig
= (Delegate
) type_sym
;
3661 if (base_node
!= null) {
3662 base_node
.process (this
);
3663 orig
= (Delegate
) base_node
.symbol
;
3666 var deleg
= new
Delegate (alias
.name
, orig
.return_type
.copy (), alias
.source_reference
);
3667 deleg
.access
= orig
.access
;
3669 foreach (var param
in orig
.get_parameters ()) {
3670 deleg
.add_parameter (param
.copy ());
3673 foreach (var error_type
in orig
.get_error_types ()) {
3674 deleg
.add_error_type (error_type
.copy ());
3677 foreach (var attribute
in orig
.attributes
) {
3678 deleg
.attributes
.append (attribute
);
3681 deleg
.external
= true;
3683 alias
.symbol
= deleg
;
3686 // inherit atributes, like type_id
3687 if (type_sym is Class
|| (type_sym is Struct
&& !simple_type
)) {
3688 if (type_sym
.has_attribute_argument ("CCode", "has_type_id")) {
3689 alias
.symbol
.set_attribute_bool ("CCode", "has_type_id", type_sym
.get_attribute_bool ("CCode", "has_type_id"));
3690 } else if (type_sym
.has_attribute_argument ("CCode", "type_id")) {
3691 alias
.symbol
.set_attribute_string ("CCode", "type_id", type_sym
.get_attribute_string ("CCode", "type_id"));
3696 void process_callable (Node node
) {
3697 if (node
.element_type
== "alias" && node
.symbol is Delegate
) {
3698 // processed in parse_alias
3702 var s
= node
.symbol
;
3703 List
<ParameterInfo
> parameters
= node
.parameters
;
3705 DataType return_type
= null;
3706 if (s is Callable
) {
3707 return_type
= ((Callable
) s
).return_type
;
3710 if (return_type is ArrayType
&& node
.return_array_length_idx
>= 0) {
3711 if (node
.return_array_length_idx
>= parameters
.size
) {
3712 Report
.error (return_type
.source_reference
, "invalid array length index");
3714 parameters
[node
.return_array_length_idx
].keep
= false;
3715 node
.array_length_parameters
.add (node
.return_array_length_idx
);
3717 } else if (return_type is VoidType
&& parameters
.size
> 0) {
3718 int n_out_parameters
= 0;
3719 foreach (var info
in parameters
) {
3720 if (info
.param
.direction
== ParameterDirection
.OUT
) {
3725 if (n_out_parameters
== 1) {
3726 ParameterInfo last_param
= parameters
[parameters
.size
-1];
3727 if (last_param
.param
.direction
== ParameterDirection
.OUT
) {
3728 // use last out real-non-null-struct parameter as return type
3729 if (last_param
.param
.variable_type is UnresolvedType
) {
3730 var st
= resolve_symbol (node
.parent
, ((UnresolvedType
) last_param
.param
.variable_type
).unresolved_symbol
) as Struct
;
3731 if (st
!= null && !st
.is_simple_type () && !last_param
.param
.variable_type
.nullable
) {
3732 if (!node
.metadata
.get_bool (ArgumentType
.RETURN_VOID
, false)) {
3733 last_param
.keep
= false;
3734 return_type
= last_param
.param
.variable_type
.copy ();
3741 if (return_type is UnresolvedType
&& !return_type
.nullable
) {
3742 var st
= resolve_symbol (node
.parent
, ((UnresolvedType
) return_type
).unresolved_symbol
) as Struct
;
3744 bool is_simple_type
= false;
3745 Struct? base_st
= st
;
3747 while (base_st
!= null) {
3748 if (base_st
.is_simple_type ()) {
3749 is_simple_type
= true;
3753 if (base_st
.base_type is UnresolvedType
) {
3754 base_st
= resolve_symbol (node
.parent
, ((UnresolvedType
) base_st
.base_type
).unresolved_symbol
) as Struct
;
3756 base_st
= base_st
.base_struct
;
3760 if (!is_simple_type
) {
3761 return_type
.nullable
= true;
3767 // Do not mark out-parameters as nullable if they are simple-types,
3768 // since it would result in a boxed-type in vala
3769 foreach (ParameterInfo info
in parameters
) {
3770 var type
= info
.param
.variable_type
;
3771 if (info
.param
.direction
== ParameterDirection
.OUT
&& type
.nullable
) {
3773 if (type is UnresolvedType
) {
3774 st
= resolve_symbol (node
.parent
, ((UnresolvedType
) type
).unresolved_symbol
) as Struct
;
3775 } else if (type is ValueType
) {
3776 st
= type
.data_type as Struct
;
3778 if (st
!= null && st
.is_simple_type ()) {
3779 type
.nullable
= false;
3784 if (parameters
.size
> 1) {
3785 ParameterInfo last_param
= parameters
[parameters
.size
-1];
3786 if (last_param
.param
.ellipsis
) {
3787 var first_vararg_param
= parameters
[parameters
.size
-2];
3788 if (first_vararg_param
.param
.name
.has_prefix ("first_")) {
3789 first_vararg_param
.keep
= false;
3797 foreach (ParameterInfo info
in parameters
) {
3798 if (s is Delegate
&& info
.closure_idx
== i
) {
3799 var d
= (Delegate
) s
;
3800 d
.has_target
= true;
3801 d
.set_attribute_double ("CCode", "instance_pos", j
- 0.1);
3803 } else if (info
.keep
3804 && !node
.array_length_parameters
.contains (i
)
3805 && !node
.closure_parameters
.contains (i
)
3806 && !node
.destroy_parameters
.contains (i
)) {
3807 info
.vala_idx
= (float) j
;
3810 /* interpolate for vala_idx between this and last*/
3811 float last_idx
= 0.0F
;
3813 last_idx
= parameters
[last
].vala_idx
;
3815 for (int k
=last
+1; k
< i
; k
++) {
3816 parameters
[k
].vala_idx
= last_idx
+ (((j
- last_idx
) / (i
-last
)) * (k
-last
));
3822 // make sure that vala_idx is always set
3823 // the above if branch does not set vala_idx for
3824 // hidden parameters at the end of the parameter list
3825 info
.vala_idx
= (j
- 1) + (i
- last
) * 0.1F
;
3830 foreach (ParameterInfo info
in parameters
) {
3835 /* add_parameter sets carray_length_parameter_position and cdelegate_target_parameter_position
3837 if (s is Callable
) {
3838 ((Callable
) s
).add_parameter (info
.param
);
3841 if (info
.array_length_idx
!= -1) {
3842 if ((info
.array_length_idx
) >= parameters
.size
) {
3843 Report
.error (info
.param
.source_reference
, "invalid array_length index");
3846 set_array_ccode (info
.param
, parameters
[info
.array_length_idx
]);
3849 if (info
.closure_idx
!= -1) {
3850 if ((info
.closure_idx
) >= parameters
.size
) {
3851 Report
.error (info
.param
.source_reference
, "invalid closure index");
3854 if ("%g".printf (parameters
[info
.closure_idx
].vala_idx
) != "%g".printf (info
.vala_idx
+ 0.1)) {
3855 info
.param
.set_attribute_double ("CCode", "delegate_target_pos", parameters
[info
.closure_idx
].vala_idx
);
3858 if (info
.destroy_idx
!= -1) {
3859 if (info
.destroy_idx
>= parameters
.size
) {
3860 Report
.error (info
.param
.source_reference
, "invalid destroy index");
3863 if ("%g".printf (parameters
[info
.destroy_idx
].vala_idx
) != "%g".printf (info
.vala_idx
+ 0.2)) {
3864 info
.param
.set_attribute_double ("CCode", "destroy_notify_pos", parameters
[info
.destroy_idx
].vala_idx
);
3868 if (info
.is_async
) {
3869 var resolved_type
= info
.param
.variable_type
;
3870 if (resolved_type is UnresolvedType
) {
3871 var resolved_symbol
= resolve_symbol (node
.parent
, ((UnresolvedType
) resolved_type
).unresolved_symbol
);
3872 if (resolved_symbol is Delegate
) {
3873 resolved_type
= new
DelegateType ((Delegate
) resolved_symbol
);
3877 if (resolved_type is DelegateType
) {
3878 var d
= ((DelegateType
) resolved_type
).delegate_symbol
;
3879 if (!(d
.name
== "DestroyNotify" && d
.parent_symbol
.name
== "GLib")) {
3880 info
.param
.set_attribute_string ("CCode", "scope", "async");
3881 info
.param
.variable_type
.value_owned
= (info
.closure_idx
!= -1 && info
.destroy_idx
!= -1);
3885 var resolved_type
= info
.param
.variable_type
;
3886 if (resolved_type is DelegateType
) {
3887 info
.param
.variable_type
.value_owned
= (info
.closure_idx
!= -1 && info
.destroy_idx
!= -1);
3892 if (return_type is ArrayType
&& node
.return_array_length_idx
>= 0) {
3893 set_array_ccode (s
, parameters
[node
.return_array_length_idx
]);
3896 if (s is Callable
) {
3897 ((Callable
) s
).return_type
= return_type
;
3901 void find_parent (string cname
, Node current
, ref Node best
, ref int match
) {
3902 var old_best
= best
;
3903 if (current
.symbol is Namespace
) {
3904 foreach (var child
in current
.members
) {
3905 // symbol is null only for aliases that aren't yet processed
3906 if ((child
.symbol
== null || is_container (child
.symbol
)) && cname
.has_prefix (child
.get_lower_case_cprefix ())) {
3907 find_parent (cname
, child
, ref best
, ref match
);
3911 if (best
!= old_best
) {
3916 var current_match
= current
.get_lower_case_cprefix().length
;
3917 if (current_match
> match
) {
3918 match
= current_match
;
3923 bool same_gir (Symbol gir_component
, Symbol sym
) {
3924 var gir_name
= gir_component
.source_reference
.file
.gir_namespace
;
3925 var gir_version
= gir_component
.source_reference
.file
.gir_version
;
3926 return "%s-%s".printf (gir_name
, gir_version
) in sym
.source_reference
.file
.filename
;
3929 void process_namespace_method (Node ns
, Node node
) {
3930 /* transform static methods into instance methods if possible.
3931 In most of cases this is a .gir fault we are going to fix */
3933 var ns_cprefix
= ns
.get_lower_case_cprefix ();
3934 var method
= (Method
) node
.symbol
;
3935 var cname
= node
.get_cname ();
3937 Parameter first_param
= null;
3938 if (method
.get_parameters ().size
> 0) {
3939 first_param
= method
.get_parameters()[0];
3941 if (first_param
!= null && first_param
.variable_type is UnresolvedType
) {
3942 // check if it's a missed instance method (often happens for structs)
3943 var sym
= ((UnresolvedType
) first_param
.variable_type
).unresolved_symbol
;
3944 var parent
= resolve_node (ns
, sym
);
3945 if (parent
!= null && same_gir (method
, parent
.symbol
) && parent
.parent
== ns
&& is_container (parent
.symbol
) && cname
.has_prefix (parent
.get_lower_case_cprefix ())) {
3947 var new_name
= method
.name
.substring (parent
.get_lower_case_cprefix().length
- ns_cprefix
.length
);
3948 if (parent
.lookup (new_name
) == null) {
3949 ns
.remove_member (node
);
3950 node
.name
= new_name
;
3951 method
.name
= new_name
;
3952 method
.get_parameters().remove_at (0);
3953 method
.binding
= MemberBinding
.INSTANCE
;
3954 parent
.add_member (node
);
3962 find_parent (cname
, ns
, ref parent
, ref match
);
3963 var new_name
= method
.name
.substring (parent
.get_lower_case_cprefix().length
- ns_cprefix
.length
);
3964 if (same_gir (method
, parent
.symbol
) && parent
.lookup (new_name
) == null) {
3965 ns
.remove_member (node
);
3966 node
.name
= new_name
;
3967 method
.name
= new_name
;
3968 parent
.add_member (node
);
3972 void process_virtual_method_field (Node node
, Delegate d
, UnresolvedSymbol gtype_struct_for
) {
3973 var gtype_node
= resolve_node (node
.parent
, gtype_struct_for
);
3974 if (gtype_node
== null || !(gtype_node
.symbol is ObjectTypeSymbol
)) {
3975 Report
.error (gtype_struct_for
.source_reference
, "Unknown symbol `%s' for virtual method field `%s'".printf (gtype_struct_for
.to_string (), node
.to_string ()));
3977 var nodes
= gtype_node
.lookup_all (d
.name
);
3978 if (nodes
== null) {
3981 foreach (var n
in nodes
) {
3986 foreach (var n
in nodes
) {
3991 if (sym is Signal
) {
3992 var sig
= (Signal
) sym
;
3993 sig
.is_virtual
= true;
3994 assume_parameter_names (sig
, d
, true);
3995 } else if (sym is Property
) {
3996 var prop
= (Property
) sym
;
3997 prop
.is_virtual
= true;
4002 void process_async_method (Node node
) {
4003 var m
= (Method
) node
.symbol
;
4004 string finish_method_base
;
4005 if (m
.name
== null) {
4006 assert (m is CreationMethod
);
4007 finish_method_base
= "new";
4008 } else if (m
.name
.has_suffix ("_async")) {
4009 finish_method_base
= m
.name
.substring (0, m
.name
.length
- "_async".length
);
4011 finish_method_base
= m
.name
;
4013 var finish_method_node
= node
.parent
.lookup (finish_method_base
+ "_finish");
4015 // check if the method is using non-standard finish method name
4016 if (finish_method_node
== null) {
4017 var method_cname
= node
.get_finish_cname ();
4018 foreach (var n
in node
.parent
.members
) {
4019 if (n
.symbol is Method
&& n
.get_cname () == method_cname
) {
4020 finish_method_node
= n
;
4028 if (finish_method_node
!= null && finish_method_node
.symbol is Method
) {
4029 finish_method_node
.process (this
);
4030 var finish_method
= (Method
) finish_method_node
.symbol
;
4031 if (finish_method is CreationMethod
) {
4032 method
= new
CreationMethod (((CreationMethod
) finish_method
).class_name
, null, m
.source_reference
);
4033 method
.access
= m
.access
;
4034 method
.binding
= m
.binding
;
4035 method
.external
= true;
4036 method
.coroutine
= true;
4037 method
.has_construct_function
= finish_method
.has_construct_function
;
4039 // cannot use List.copy()
4040 // as it returns a list of unowned elements
4041 foreach (Attribute a
in m
.attributes
) {
4042 method
.attributes
.append (a
);
4045 method
.set_attribute_string ("CCode", "cname", node
.get_cname ());
4046 if (finish_method_base
== "new") {
4048 } else if (finish_method_base
.has_prefix ("new_")) {
4049 method
.name
= m
.name
.substring ("new_".length
);
4051 foreach (var param
in m
.get_parameters ()) {
4052 method
.add_parameter (param
);
4054 node
.symbol
= method
;
4056 method
.return_type
= finish_method
.return_type
.copy ();
4057 var a
= finish_method
.get_attribute ("CCode");
4058 if (a
!= null && a
.has_argument ("array_length")) {
4059 method
.set_attribute_bool ("CCode", "array_length", a
.get_bool ("array_length"));
4061 if (a
!= null && a
.has_argument ("array_null_terminated")) {
4062 method
.set_attribute_bool ("CCode", "array_null_terminated", a
.get_bool ("array_null_terminated"));
4066 foreach (var param
in finish_method
.get_parameters ()) {
4067 if (param
.direction
== ParameterDirection
.OUT
) {
4068 var async_param
= param
.copy ();
4069 if (method
.scope
.lookup (param
.name
) != null) {
4070 // parameter name conflict
4071 async_param
.name
+= "_out";
4073 method
.add_parameter (async_param
);
4077 foreach (DataType error_type
in finish_method
.get_error_types ()) {
4078 method
.add_error_type (error_type
.copy ());
4080 finish_method_node
.processed
= true;
4081 finish_method_node
.merged
= true;
4085 /* Hash and equal functions */
4087 static uint unresolved_symbol_hash (UnresolvedSymbol? sym
) {
4088 var builder
= new
StringBuilder ();
4089 while (sym
!= null) {
4090 builder
.append (sym
.name
);
4093 return builder
.str
.hash ();
4096 static bool unresolved_symbol_equal (UnresolvedSymbol? sym1
, UnresolvedSymbol? sym2
) {
4097 while (sym1
!= sym2
) {
4098 if (sym1
== null || sym2
== null) {
4101 if (sym1
.name
!= sym2
.name
) {
4110 /* Helper methods */
4112 Node?
base_interface_property (Node prop_node
) {
4113 var cl
= prop_node
.parent
.symbol as Class
;
4118 foreach (DataType type
in cl
.get_base_types ()) {
4119 if (!(type is UnresolvedType
)) {
4123 var base_node
= resolve_node (prop_node
.parent
, ((UnresolvedType
) type
).unresolved_symbol
);
4124 if (base_node
!= null && base_node
.symbol is Interface
) {
4125 var base_prop_node
= base_node
.lookup (prop_node
.name
);
4126 if (base_prop_node
!= null && base_prop_node
.symbol is Property
) {
4127 var base_property
= (Property
) base_prop_node
.symbol
;
4128 if (base_property
.is_abstract
|| base_property
.is_virtual
) {
4130 return base_prop_node
;