Line data Source code
1 : /* valagirparser.vala
2 : *
3 : * Copyright (C) 2008-2012 Jürg Billeter
4 : * Copyright (C) 2011-2014 Luca Bruno
5 : *
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.
10 :
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.
15 :
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
19 : *
20 : * Author:
21 : * Jürg Billeter <j@bitron.ch>
22 : * Luca Bruno <lucabru@src.gnome.org>
23 : */
24 :
25 : using GLib;
26 :
27 : /**
28 : * Code visitor parsing all GIR source files.
29 : *
30 : * Pipeline:
31 : * 1) Parse metadata
32 : * 2) Parse GIR with metadata, track unresolved GIR symbols, create Vala symbols
33 : * 3) Reconciliate the tree by mapping tracked symbols
34 : * 4) Process the tree
35 : */
36 7690 : public class Vala.GirParser : CodeVisitor {
37 : /*
38 : * Metadata parser
39 : */
40 :
41 : enum ArgumentType {
42 : SKIP,
43 : HIDDEN,
44 : NEW,
45 : TYPE,
46 : TYPE_ARGUMENTS,
47 : TYPE_PARAMETERS,
48 : CHEADER_FILENAME,
49 : NAME,
50 : OWNED,
51 : UNOWNED,
52 : PARENT,
53 : IMPLEMENTS,
54 : PREREQUISITES,
55 : NULLABLE,
56 : DEPRECATED,
57 : REPLACEMENT,
58 : DEPRECATED_SINCE,
59 : SINCE,
60 : ARRAY,
61 : ARRAY_LENGTH_IDX,
62 : ARRAY_NULL_TERMINATED,
63 : DEFAULT,
64 : OUT,
65 : REF,
66 : VFUNC_NAME,
67 : VIRTUAL,
68 : ABSTRACT,
69 : COMPACT,
70 : SEALED,
71 : SCOPE,
72 : STRUCT,
73 : THROWS,
74 : PRINTF_FORMAT,
75 : ARRAY_LENGTH_FIELD,
76 : SENTINEL,
77 : CLOSURE,
78 : DESTROY,
79 : CPREFIX,
80 : LOWER_CASE_CPREFIX,
81 : LOWER_CASE_CSUFFIX,
82 : ERRORDOMAIN,
83 : DESTROYS_INSTANCE,
84 : BASE_TYPE,
85 : FINISH_NAME,
86 : FINISH_INSTANCE,
87 : SYMBOL_TYPE,
88 : INSTANCE_IDX,
89 : EXPERIMENTAL,
90 : FEATURE_TEST_MACRO,
91 : FLOATING,
92 : TYPE_ID,
93 : TYPE_GET_FUNCTION,
94 : COPY_FUNCTION,
95 : FREE_FUNCTION,
96 : REF_FUNCTION,
97 : REF_SINK_FUNCTION,
98 : UNREF_FUNCTION,
99 : RETURN_VOID,
100 : RETURNS_MODIFIED_POINTER,
101 : DELEGATE_TARGET_CNAME,
102 : DESTROY_NOTIFY_CNAME,
103 : FINISH_VFUNC_NAME,
104 : NO_ACCESSOR_METHOD,
105 : NO_WRAPPER,
106 : CNAME,
107 : DELEGATE_TARGET,
108 : CTYPE;
109 :
110 24 : public static ArgumentType? from_string (string name) {
111 24 : var enum_class = (EnumClass) typeof(ArgumentType).class_ref ();
112 24 : var nick = name.replace ("_", "-");
113 24 : unowned GLib.EnumValue? enum_value = enum_class.get_value_by_nick (nick);
114 24 : if (enum_value != null) {
115 24 : ArgumentType value = (ArgumentType) enum_value.value;
116 48 : return value;
117 : }
118 0 : return null;
119 : }
120 : }
121 :
122 167 : class Argument {
123 22 : public Expression expression;
124 22 : public SourceReference source_reference;
125 :
126 24 : public bool used = false;
127 :
128 48 : public Argument (Expression expression, SourceReference? source_reference = null) {
129 24 : this.expression = expression;
130 1661 : this.source_reference = source_reference;
131 : }
132 : }
133 :
134 1 : class MetadataSet : Metadata {
135 2 : public MetadataSet (string? selector = null) {
136 2 : base ("", selector);
137 : }
138 :
139 4 : public void add_sibling (Metadata metadata) {
140 4 : foreach (var child in metadata.children) {
141 0 : add_child (child);
142 : }
143 : // merge arguments and take precedence
144 12 : foreach (var key in metadata.args.get_keys ()) {
145 4 : args[key] = metadata.args[key];
146 : }
147 : }
148 : }
149 :
150 9928 : class Metadata {
151 : private static Metadata _empty = null;
152 : public static Metadata empty {
153 : get {
154 3387 : if (_empty == null) {
155 1538 : _empty = new Metadata ("");
156 : }
157 3387 : return _empty;
158 : }
159 : }
160 :
161 28 : public PatternSpec pattern_spec;
162 28 : public string? selector;
163 28 : public SourceReference source_reference;
164 :
165 1567 : public bool used = false;
166 1595 : public Vala.Map<ArgumentType,Argument> args = new HashMap<ArgumentType,Argument> ();
167 1595 : public ArrayList<Metadata> children = new ArrayList<Metadata> ();
168 :
169 3132 : public Metadata (string pattern, string? selector = null, SourceReference? source_reference = null) {
170 1567 : this.pattern_spec = new PatternSpec (pattern);
171 3134 : this.selector = selector;
172 1593 : this.source_reference = source_reference;
173 : }
174 :
175 26 : public void add_child (Metadata metadata) {
176 26 : children.add (metadata);
177 : }
178 :
179 1037 : public Metadata match_child (string name, string? selector = null) {
180 2074 : var result = Metadata.empty;
181 4121 : foreach (var metadata in children) {
182 1542 : if ((selector == null || metadata.selector == null || metadata.selector == selector) && metadata.pattern_spec.match_string (name)) {
183 54 : metadata.used = true;
184 56 : if (result == Metadata.empty) {
185 : // first match
186 52 : result = metadata;
187 : } else {
188 2 : var ms = result as MetadataSet;
189 0 : if (ms == null) {
190 : // second match
191 2 : ms = new MetadataSet (selector);
192 2 : ms.add_sibling (result);
193 : }
194 2 : ms.add_sibling (metadata);
195 4 : result = ms;
196 : }
197 : }
198 : }
199 : return result;
200 : }
201 :
202 24 : public void add_argument (ArgumentType key, Argument value) {
203 24 : args.set (key, value);
204 : }
205 :
206 19597 : public bool has_argument (ArgumentType key) {
207 19597 : return args.contains (key);
208 : }
209 :
210 4377 : public Expression? get_expression (ArgumentType arg) {
211 4377 : var val = args.get (arg);
212 4377 : if (val != null) {
213 56 : val.used = true;
214 112 : return val.expression;
215 : }
216 4377 : return null;
217 : }
218 :
219 1101 : public string? get_string (ArgumentType arg) {
220 1101 : var lit = get_expression (arg) as StringLiteral;
221 12 : if (lit != null) {
222 12 : return lit.eval ();
223 : }
224 1101 : return null;
225 : }
226 :
227 0 : public int get_integer (ArgumentType arg) {
228 0 : var unary = get_expression (arg) as UnaryExpression;
229 0 : if (unary != null && unary.operator == UnaryOperator.MINUS) {
230 0 : var lit = unary.inner as IntegerLiteral;
231 0 : if (lit != null) {
232 0 : return -int.parse (lit.value);
233 : }
234 : } else {
235 0 : var lit = get_expression (arg) as IntegerLiteral;
236 0 : if (lit != null) {
237 0 : return int.parse (lit.value);
238 : }
239 : }
240 :
241 0 : return 0;
242 : }
243 :
244 2558 : public bool get_bool (ArgumentType arg, bool default_value = false) {
245 2558 : var lit = get_expression (arg) as BooleanLiteral;
246 35 : if (lit != null) {
247 35 : return lit.value;
248 : }
249 2558 : return default_value;
250 : }
251 :
252 10 : public SourceReference? get_source_reference (ArgumentType arg) {
253 10 : var val = args.get (arg);
254 10 : if (val != null) {
255 10 : return val.source_reference;
256 : }
257 10 : return null;
258 : }
259 : }
260 :
261 4 : class MetadataParser {
262 : /**
263 : * Grammar:
264 : * metadata ::= [ rule [ '\n' relativerule ]* ]
265 : * rule ::= pattern ' ' [ args ]
266 : * relativerule ::= '.' rule
267 : * pattern ::= glob [ '#' selector ] [ '.' pattern ]
268 : */
269 2 : private Metadata tree = new Metadata ("");
270 1 : private Scanner scanner;
271 : private SourceLocation begin;
272 : private SourceLocation end;
273 : private SourceLocation old_end;
274 : private TokenType current;
275 1 : private Metadata parent_metadata;
276 :
277 1 : public MetadataParser () {
278 1 : tree.used = true;
279 : }
280 :
281 20 : SourceReference get_current_src () {
282 20 : return new SourceReference (scanner.source_file, begin, end);
283 : }
284 :
285 54 : SourceReference get_src (SourceLocation begin, SourceLocation? end = null) {
286 54 : var e = this.end;
287 54 : if (end != null) {
288 0 : e = end;
289 : }
290 54 : return new SourceReference (scanner.source_file, begin, e);
291 : }
292 :
293 1 : public Metadata parse_metadata (SourceFile metadata_file) {
294 1 : scanner = new Scanner (metadata_file);
295 1 : next ();
296 27 : while (current != TokenType.EOF) {
297 26 : if (!parse_rule ()) {
298 0 : return Metadata.empty;
299 : }
300 : }
301 1 : return tree;
302 : }
303 :
304 114 : TokenType next () {
305 114 : old_end = end;
306 114 : current = scanner.read_token (out begin, out end);
307 114 : return current;
308 : }
309 :
310 100 : bool has_space () {
311 100 : return old_end.pos != begin.pos;
312 : }
313 :
314 45 : bool has_newline () {
315 45 : return old_end.line != begin.line;
316 : }
317 :
318 61 : string get_string (SourceLocation? begin = null, SourceLocation? end = null) {
319 61 : var b = this.begin;
320 61 : var e = this.end;
321 61 : if (begin != null) {
322 52 : b = begin;
323 : }
324 61 : if (end != null) {
325 52 : e = end;
326 : }
327 61 : return ((string) b.pos).substring (0, (int) (e.pos - b.pos));
328 : }
329 :
330 52 : string? parse_identifier (bool is_glob) {
331 52 : var begin = this.begin;
332 :
333 52 : if (current == TokenType.DOT || current == TokenType.HASH) {
334 0 : if (is_glob) {
335 0 : Report.error (get_src (begin), "expected glob-style pattern");
336 : } else {
337 0 : Report.error (get_src (begin), "expected identifier");
338 : }
339 0 : return null;
340 : }
341 :
342 52 : if (is_glob) {
343 29 : while (current != TokenType.EOF && current != TokenType.DOT && current != TokenType.HASH) {
344 27 : next ();
345 27 : if (has_space ()) {
346 : break;
347 : }
348 : }
349 : } else {
350 26 : next ();
351 : }
352 :
353 52 : return get_string (begin, old_end);
354 : }
355 :
356 26 : string? parse_selector () {
357 26 : if (current != TokenType.HASH || has_space ()) {
358 24 : return null;
359 : }
360 2 : next ();
361 :
362 2 : return parse_identifier (false);
363 : }
364 :
365 26 : Metadata? parse_pattern () {
366 : Metadata metadata;
367 26 : bool is_relative = false;
368 26 : if (current == TokenType.IDENTIFIER || current == TokenType.STAR) {
369 : // absolute pattern
370 16 : parent_metadata = tree;
371 : } else {
372 : // relative pattern
373 18 : if (current != TokenType.DOT) {
374 0 : Report.error (get_current_src (), "expected pattern or `.', got `%s'", current.to_string ());
375 0 : return null;
376 : }
377 18 : next ();
378 18 : is_relative = true;
379 : }
380 :
381 26 : if (parent_metadata == null) {
382 0 : Report.error (get_current_src (), "cannot determinate parent metadata");
383 0 : return null;
384 : }
385 :
386 26 : SourceLocation begin = this.begin;
387 26 : var pattern = parse_identifier (true);
388 26 : if (pattern == null) {
389 0 : return null;
390 : }
391 26 : metadata = new Metadata (pattern, parse_selector (), get_src (begin));
392 26 : parent_metadata.add_child (metadata);
393 :
394 26 : while (current != TokenType.EOF && !has_space ()) {
395 0 : if (current != TokenType.DOT) {
396 0 : Report.error (get_current_src (), "expected `.' got `%s'", current.to_string ());
397 : break;
398 : }
399 0 : next ();
400 :
401 0 : begin = this.begin;
402 0 : pattern = parse_identifier (true);
403 0 : if (pattern == null) {
404 0 : return null;
405 : }
406 0 : var child = new Metadata (pattern, parse_selector (), get_src (begin, old_end));
407 0 : metadata.add_child (child);
408 0 : metadata = child;
409 : }
410 26 : if (!is_relative) {
411 16 : parent_metadata = metadata;
412 : }
413 :
414 26 : return metadata;
415 : }
416 :
417 20 : Expression? parse_expression () {
418 20 : var begin = this.begin;
419 20 : var src = get_current_src ();
420 20 : Expression expr = null;
421 20 : switch (current) {
422 : case TokenType.NULL:
423 0 : expr = new NullLiteral (src);
424 0 : break;
425 : case TokenType.TRUE:
426 0 : expr = new BooleanLiteral (true, src);
427 0 : break;
428 : case TokenType.FALSE:
429 11 : expr = new BooleanLiteral (false, src);
430 11 : break;
431 : case TokenType.MINUS:
432 0 : next ();
433 0 : var inner = parse_expression ();
434 0 : if (inner == null) {
435 0 : Report.error (src, "expected expression after `-', got `%s'", current.to_string ());
436 : } else {
437 0 : expr = new UnaryExpression (UnaryOperator.MINUS, inner, get_src (begin));
438 : }
439 0 : return expr;
440 : case TokenType.INTEGER_LITERAL:
441 0 : expr = new IntegerLiteral (get_string (), src);
442 0 : break;
443 : case TokenType.REAL_LITERAL:
444 0 : expr = new RealLiteral (get_string (), src);
445 0 : break;
446 : case TokenType.STRING_LITERAL:
447 9 : expr = new StringLiteral (get_string (), src);
448 9 : break;
449 : case TokenType.IDENTIFIER:
450 0 : expr = new MemberAccess (null, get_string (), src);
451 0 : while (next () == TokenType.DOT) {
452 0 : if (next () != TokenType.IDENTIFIER) {
453 0 : Report.error (get_current_src (), "expected identifier got `%s'", current.to_string ());
454 : break;
455 : }
456 0 : expr = new MemberAccess (expr, get_string (), get_current_src ());
457 : }
458 0 : return expr;
459 : case TokenType.OPEN_PARENS:
460 : // empty tuple => no expression
461 0 : if (next () != TokenType.CLOSE_PARENS) {
462 0 : Report.error (get_current_src (), "expected `)', got `%s'", current.to_string ());
463 : break;
464 : }
465 0 : expr = new Tuple (src);
466 0 : break;
467 : default:
468 0 : Report.error (src, "expected literal or symbol got %s", current.to_string ());
469 0 : break;
470 : }
471 20 : next ();
472 20 : return expr;
473 : }
474 :
475 22 : bool parse_args (Metadata metadata) {
476 66 : while (current != TokenType.EOF && has_space () && !has_newline ()) {
477 24 : SourceLocation begin = this.begin;
478 24 : var id = parse_identifier (false);
479 24 : if (id == null) {
480 0 : return false;
481 : }
482 24 : var arg_type = ArgumentType.from_string (id);
483 24 : if (arg_type == null) {
484 0 : Report.warning (get_src (begin, old_end), "unknown argument `%s'", id);
485 0 : continue;
486 : }
487 :
488 24 : if (current != TokenType.ASSIGN) {
489 : // threat as `true'
490 4 : metadata.add_argument (arg_type, new Argument (new BooleanLiteral (true, get_src (begin)), get_src (begin)));
491 4 : continue;
492 : }
493 20 : next ();
494 :
495 20 : Expression expr = parse_expression ();
496 20 : if (expr == null) {
497 0 : return false;
498 : }
499 20 : metadata.add_argument (arg_type, new Argument (expr, get_src (begin)));
500 : }
501 :
502 22 : return true;
503 : }
504 :
505 26 : bool parse_rule () {
506 26 : var old_end = end;
507 26 : var metadata = parse_pattern ();
508 26 : if (metadata == null) {
509 0 : return false;
510 : }
511 :
512 26 : if (current == TokenType.EOF || old_end.line != end.line) {
513 : // eof or new rule
514 4 : return true;
515 : }
516 22 : return parse_args (metadata);
517 : }
518 : }
519 :
520 : /*
521 : * GIR parser
522 : */
523 :
524 15038 : class Node {
525 1538 : public static ArrayList<Node> new_namespaces = new ArrayList<Node> ();
526 :
527 : public weak Node parent;
528 2097 : public string element_type;
529 2097 : public string name;
530 2097 : public Map<string,string> girdata = null;
531 4196 : public Metadata metadata = Metadata.empty;
532 2097 : public SourceReference source_reference = null;
533 4196 : public ArrayList<Node> members = new ArrayList<Node> (); // guarantees fields order
534 4196 : public HashMap<string, ArrayList<Node>> scope = new HashMap<string, ArrayList<Node>> (str_hash, str_equal);
535 :
536 2097 : public GirComment comment;
537 2097 : public Symbol symbol;
538 : public bool new_symbol;
539 : public bool merged;
540 : public bool processed;
541 :
542 : // function-specific
543 2099 : public int return_array_length_idx = -1;
544 2097 : public List<ParameterInfo> parameters;
545 2097 : public ArrayList<int> array_length_parameters;
546 2097 : public ArrayList<int> closure_parameters;
547 2097 : public ArrayList<int> destroy_parameters;
548 : // record-specific
549 2097 : public UnresolvedSymbol gtype_struct_for;
550 : // class-specific
551 2097 : public UnresolvedSymbol type_struct;
552 : // alias-specific
553 2097 : public DataType base_type;
554 : // struct-specific
555 2099 : public int array_length_idx = -1;
556 : // objecttypesymbol-specific
557 2097 : public List<DataType> inherited_types;
558 :
559 2099 : public bool deprecated = false;
560 2099 : public uint64 deprecated_version = 0;
561 2097 : public string? deprecated_since = null;
562 2097 : public string? deprecated_replacement = null;
563 :
564 4198 : public Node (string? name) {
565 4198 : this.name = name;
566 : }
567 :
568 1124 : public void add_member (Node node) {
569 562 : var nodes = scope[node.name];
570 562 : if (nodes == null) {
571 534 : nodes = new ArrayList<Node> ();
572 534 : scope[node.name] = nodes;
573 : }
574 562 : nodes.add (node);
575 562 : members.add (node);
576 562 : node.parent = this;
577 : }
578 :
579 2 : public void remove_member (Node node) {
580 1 : var nodes = scope[node.name];
581 1 : nodes.remove (node);
582 1 : if (nodes.size == 0) {
583 1 : scope.remove (node.name);
584 : }
585 1 : members.remove (node);
586 1 : node.parent = null;
587 : }
588 :
589 1494 : public Node? lookup (string name, bool create_namespace = false, SourceReference? source_reference = null) {
590 1494 : var nodes = scope[name];
591 1494 : Node node = null;
592 1494 : if (nodes != null) {
593 357 : node = nodes[0];
594 : }
595 1553 : if (node == null) {
596 1137 : Symbol sym = null;
597 1137 : if (symbol != null) {
598 1101 : sym = symbol.scope.lookup (name);
599 : }
600 1137 : if (sym != null || create_namespace) {
601 60 : node = new Node (name);
602 119 : node.symbol = sym;
603 60 : node.new_symbol = node.symbol == null;
604 113 : node.source_reference = source_reference;
605 60 : add_member (node);
606 :
607 60 : if (sym == null) {
608 1 : new_namespaces.add (node);
609 : }
610 : }
611 : }
612 1494 : return node;
613 : }
614 :
615 336 : public ArrayList<Node>? lookup_all (string name) {
616 336 : return scope[name];
617 : }
618 :
619 141 : public UnresolvedSymbol get_unresolved_symbol () {
620 141 : if (parent.name == null) {
621 47 : return new UnresolvedSymbol (null, name);
622 : } else {
623 94 : return new UnresolvedSymbol (parent.get_unresolved_symbol (), name);
624 : }
625 : }
626 :
627 0 : public string get_full_name () {
628 0 : if (parent == null) {
629 0 : return name;
630 : }
631 :
632 0 : if (name == null) {
633 : return parent.get_full_name ();
634 : }
635 :
636 0 : if (parent.get_full_name () == null) {
637 0 : return name;
638 : }
639 :
640 0 : return "%s.%s".printf (parent.get_full_name (), name);
641 : }
642 :
643 501 : public string get_default_gir_name () {
644 501 : GLib.StringBuilder default_name = new GLib.StringBuilder ();
645 :
646 1298 : for (unowned Node? node = this ; node != null ; node = node.parent) {
647 1298 : if (node.symbol is Namespace) {
648 502 : if (node.symbol.has_attribute_argument ("CCode", "gir_namespace")) {
649 : break;
650 : }
651 : }
652 :
653 797 : default_name.prepend (node.name);
654 : }
655 :
656 1002 : return default_name.str;
657 : }
658 :
659 1002 : public string get_gir_name () {
660 1002 : var gir_name = girdata["name"];
661 1002 : if (gir_name == null) {
662 0 : gir_name = girdata["glib:name"];
663 : }
664 : return gir_name;
665 : }
666 :
667 2735 : public string get_lower_case_cprefix () {
668 2735 : if (name == null) {
669 46 : return "";
670 : }
671 :
672 2689 : var prefix = symbol.get_attribute_string ("CCode", "lower_case_cprefix");
673 2689 : if (prefix == null && (symbol is ObjectTypeSymbol || symbol is Struct)) {
674 1100 : if (metadata.has_argument (ArgumentType.LOWER_CASE_CPREFIX)) {
675 0 : prefix = metadata.get_string (ArgumentType.LOWER_CASE_CPREFIX);
676 1100 : } else if (metadata.has_argument (ArgumentType.CPREFIX)) {
677 0 : prefix = metadata.get_string (ArgumentType.CPREFIX);
678 : } else {
679 1100 : prefix = symbol.get_attribute_string ("CCode", "cprefix");
680 : }
681 : }
682 :
683 2689 : if (prefix == null && girdata != null && (girdata.contains ("c:symbol-prefix") || girdata.contains("c:symbol-prefixes"))) {
684 : /* Use the prefix in the gir. We look up prefixes up to the root.
685 : If some node does not have girdata, we ignore it as i might be
686 : a namespace created due to reparenting. */
687 : unowned Node cur = this;
688 2632 : do {
689 1974 : if (cur.girdata != null) {
690 1316 : var p = cur.girdata["c:symbol-prefix"];
691 1316 : if (p == null) {
692 658 : p = cur.girdata["c:symbol-prefixes"];
693 658 : if (p != null) {
694 658 : var idx = p.index_of (",");
695 658 : if (idx >= 0) {
696 0 : p = p.substring (0, idx);
697 : }
698 : }
699 : }
700 :
701 2632 : if (p != null) {
702 1316 : prefix = "%s_%s".printf (p, prefix ?? "");
703 : }
704 : }
705 :
706 1974 : cur = cur.parent;
707 1974 : } while (cur != null);
708 : }
709 :
710 2689 : if (prefix == null) {
711 1035 : prefix = get_default_lower_case_cprefix ();
712 : }
713 2735 : return prefix;
714 : }
715 :
716 1536 : public string get_default_lower_case_cprefix () {
717 1536 : return "%s%s_".printf (parent.get_lower_case_cprefix (), get_lower_case_csuffix ());
718 : }
719 :
720 2040 : public string get_lower_case_csuffix () {
721 2040 : var suffix = symbol.get_attribute_string ("CCode", "lower_case_csuffix");
722 2040 : if (metadata.has_argument (ArgumentType.LOWER_CASE_CSUFFIX)) {
723 0 : suffix = metadata.get_string (ArgumentType.LOWER_CASE_CSUFFIX);
724 : }
725 :
726 : // we can't rely on gir suffix if metadata changed the name
727 2040 : if (suffix == null && girdata != null && girdata["c:symbol-prefix"] != null && !metadata.has_argument (ArgumentType.NAME)) {
728 57 : suffix = girdata["c:symbol-prefix"];
729 : }
730 2040 : if (suffix == null) {
731 1983 : suffix = get_default_lower_case_csuffix ();
732 : }
733 : return suffix;
734 : }
735 :
736 2484 : public string get_default_lower_case_csuffix () {
737 2484 : var csuffix = Symbol.camel_case_to_lower_case (name);
738 :
739 : // FIXME Code duplication with CCodeAttribute.get_default_lower_case_suffix()
740 : // remove underscores in some cases to avoid conflicts of type macros
741 2484 : if (csuffix.has_prefix ("type_")) {
742 23 : csuffix = "type" + csuffix.substring ("type_".length);
743 2461 : } else if (csuffix.has_prefix ("is_")) {
744 0 : csuffix = "is" + csuffix.substring ("is_".length);
745 : }
746 2484 : if (csuffix.has_suffix ("_class")) {
747 317 : csuffix = csuffix.substring (0, csuffix.length - "_class".length) + "class";
748 : }
749 : return csuffix;
750 : }
751 :
752 316 : public string get_cprefix () {
753 316 : if (name == null) {
754 92 : return "";
755 : }
756 : string prefix;
757 224 : if (metadata.has_argument (ArgumentType.CPREFIX)) {
758 0 : prefix = metadata.get_string (ArgumentType.CPREFIX);
759 : } else {
760 224 : prefix = symbol.get_attribute_string ("CCode", "cprefix");
761 : }
762 224 : if (prefix == null && girdata != null && girdata["c:identifier-prefixes"] != null) {
763 0 : prefix = girdata["c:identifier-prefixes"];
764 0 : int idx = prefix.index_of (",");
765 0 : if (idx != -1) {
766 0 : prefix = prefix.substring (0, idx);
767 : }
768 : }
769 224 : if (prefix == null) {
770 79 : if (symbol is Enum || symbol is ErrorDomain) {
771 0 : prefix = "%s%s".printf (parent.get_lower_case_cprefix ().ascii_up (), name);
772 : } else {
773 79 : prefix = get_cname ();
774 : }
775 : }
776 316 : return prefix;
777 : }
778 :
779 840 : public string get_cname () {
780 840 : if (name == null) {
781 0 : return "";
782 : }
783 : string cname;
784 840 : if (metadata.has_argument (ArgumentType.CNAME)) {
785 0 : cname = metadata.get_string (ArgumentType.CNAME);
786 : } else {
787 840 : cname = symbol.get_attribute_string ("CCode", "cname");
788 : }
789 840 : if (girdata != null) {
790 830 : if (cname == null) {
791 813 : cname = girdata["c:identifier"];
792 : }
793 813 : if (cname == null) {
794 517 : cname = girdata["c:type"];
795 : }
796 517 : if (cname == null) {
797 206 : cname = girdata["glib:type-name"];
798 : }
799 : }
800 216 : if (cname == null) {
801 206 : cname = get_default_cname ();
802 : }
803 840 : return cname;
804 : }
805 :
806 707 : public string get_default_cname () {
807 707 : if (name == null) {
808 0 : return "";
809 : }
810 707 : if (symbol is Field) {
811 161 : if (((Field) symbol).binding == MemberBinding.STATIC) {
812 0 : return parent.get_lower_case_cprefix () + name;
813 : } else {
814 322 : return name;
815 : }
816 546 : } else if (symbol is Method) {
817 230 : return "%s%s".printf (parent.get_lower_case_cprefix (), name);
818 : } else {
819 316 : return "%s%s".printf (parent.get_cprefix (), name);
820 : }
821 : }
822 :
823 0 : public string get_finish_cname () {
824 0 : var finish_cname = symbol.get_attribute_string ("CCode", "finish_name");
825 0 : if (finish_cname == null) {
826 0 : finish_cname = get_cname ();
827 0 : if (finish_cname.has_suffix ("_async")) {
828 0 : finish_cname = finish_cname.substring (0, finish_cname.length - "_async".length);
829 : }
830 0 : finish_cname = "%s_finish".printf (finish_cname);
831 : }
832 : return finish_cname;
833 : }
834 :
835 343 : public string get_cheader_filename () {
836 343 : if (metadata.has_argument (ArgumentType.CHEADER_FILENAME)) {
837 0 : return metadata.get_string (ArgumentType.CHEADER_FILENAME);
838 : }
839 343 : var cheader_filename = symbol.get_attribute_string ("CCode", "cheader_filename");
840 343 : if (cheader_filename != null) {
841 343 : return cheader_filename;
842 : }
843 148 : if (parent.name != null) {
844 148 : return parent.get_cheader_filename ();
845 0 : } else if (symbol.source_reference != null) {
846 0 : return symbol.source_reference.file.get_cinclude_filename ();
847 : }
848 0 : return "";
849 : }
850 :
851 1 : private static uint64 parse_version_string (string version) {
852 1 : int64 res = 0;
853 1 : int shift = 16;
854 1 : string[] tokens = version.split (".", 3);
855 :
856 4 : foreach (unowned string token in tokens) {
857 : int64 t;
858 :
859 3 : if (!int64.try_parse (token, out t))
860 0 : return 0;
861 3 : if (t > 0xffff)
862 0 : return 0;
863 :
864 3 : res |= (t << shift);
865 3 : shift -= 8;
866 : }
867 :
868 1 : return res;
869 : }
870 :
871 52 : static void move_class_methods (Node target, Node? source) {
872 52 : if (source == null) {
873 : return;
874 : }
875 :
876 : var i = 0;
877 89 : while (i < source.members.size) {
878 45 : var node = source.members[i];
879 45 : if (node.symbol is Method) {
880 1 : source.remove_member (node);
881 1 : target.add_member (node);
882 :
883 1 : ((Method) node.symbol).binding = MemberBinding.CLASS;
884 : } else {
885 44 : i++;
886 : }
887 : }
888 : }
889 :
890 2123 : public void process (GirParser parser) {
891 2123 : if (processed) {
892 : return;
893 : }
894 :
895 2041 : if (symbol is Namespace && parent == parser.root) {
896 : // first process aliases since they have no assigned symbol
897 195 : foreach (var node in members) {
898 149 : if (node.element_type == "alias") {
899 5 : parser.process_alias (node);
900 : }
901 : }
902 :
903 : // auto reparent namespace methods, allowing node removals
904 195 : for (int i=0; i < members.size; i++) {
905 149 : var node = members[i];
906 149 : if (node.symbol is Method && node.new_symbol) {
907 36 : parser.process_namespace_method (this, node);
908 36 : if (i < members.size && members[i] != node) {
909 : // node removed in the middle
910 0 : i--;
911 : }
912 : }
913 : }
914 : }
915 :
916 2072 : if (symbol is Class && girdata != null) {
917 31 : if (type_struct != null) {
918 26 : move_class_methods (this, parser.resolve_node (parent, type_struct));
919 : }
920 31 : var class_struct = girdata["glib:type-struct"];
921 31 : if (class_struct != null) {
922 26 : move_class_methods (this, parser.resolve_node (parent, parser.parse_symbol_from_string (class_struct, source_reference)));
923 : }
924 : }
925 :
926 : // process children
927 3047 : foreach (var node in members) {
928 503 : node.process (parser);
929 : }
930 :
931 2542 : if (girdata != null) {
932 : // GIR node processing
933 693 : if (symbol is Method) {
934 192 : var m = (Method) symbol;
935 192 : parser.process_callable (this);
936 :
937 192 : var colliding = parent.lookup_all (name);
938 435 : foreach (var node in colliding) {
939 243 : var sym = node.symbol;
940 243 : if (sym is Field) {
941 0 : if (m.return_type.compatible (((Field) sym).variable_type) && m.get_parameters ().size == 0) {
942 : // assume method is getter
943 0 : merged = true;
944 : } else {
945 0 : Report.warning (symbol.source_reference, "Field `%s' conflicts with method of the same name", get_full_name ());
946 : }
947 246 : } else if (sym is Signal) {
948 3 : node.process (parser);
949 3 : var sig = (Signal) sym;
950 3 : if (m.is_virtual || m.is_abstract) {
951 2 : sig.is_virtual = true;
952 : } else {
953 1 : sig.set_attribute ("HasEmitter", true);
954 : }
955 3 : parser.assume_parameter_names (sig, m, false);
956 3 : if (m.get_parameters().size != sig.get_parameters().size) {
957 0 : Report.warning (symbol.source_reference, "Signal `%s' conflicts with method of the same name", get_full_name ());
958 : }
959 3 : merged = true;
960 240 : } else if (sym is Method && !(sym is CreationMethod) && node != this) {
961 48 : if (m.is_virtual || m.is_abstract) {
962 24 : bool different_invoker = false;
963 24 : var no_wrapper = m.has_attribute ("NoWrapper");
964 24 : if (no_wrapper) {
965 : /* no invoker but this method has the same name,
966 : most probably the invoker has a different name
967 : and g-ir-scanner missed it */
968 0 : var invoker = parser.find_invoker (this);
969 0 : if (invoker != null) {
970 0 : m.set_attribute_string ("CCode", "vfunc_name", m.name);
971 0 : m.name = invoker.symbol.name;
972 0 : m.set_attribute ("NoWrapper", false);
973 0 : invoker.merged = true;
974 0 : different_invoker = true;
975 : }
976 : }
977 0 : if (!different_invoker) {
978 24 : if (no_wrapper) {
979 0 : Report.warning (symbol.source_reference, "Virtual method `%s' conflicts with method of the same name", get_full_name ());
980 : }
981 24 : node.merged = true;
982 : }
983 24 : } else if (m.is_class_member ()) {
984 0 : Report.warning (symbol.source_reference, "Class method `%s' conflicts with method of the same name", get_full_name ());
985 0 : node.merged = true;
986 : }
987 : }
988 : }
989 192 : if (!(m is CreationMethod)) {
990 164 : if (metadata.has_argument (ArgumentType.DESTROYS_INSTANCE)) {
991 0 : m.set_attribute ("DestroysInstance", metadata.get_bool (ArgumentType.DESTROYS_INSTANCE));
992 : }
993 164 : if (metadata.has_argument (ArgumentType.RETURNS_MODIFIED_POINTER)) {
994 0 : m.set_attribute ("ReturnsModifiedPointer", metadata.get_bool (ArgumentType.RETURNS_MODIFIED_POINTER));
995 : }
996 : // merge custom vfunc
997 164 : if (metadata.has_argument (ArgumentType.VFUNC_NAME)) {
998 0 : var vfunc = parent.lookup (metadata.get_string (ArgumentType.VFUNC_NAME));
999 0 : if (vfunc != null && vfunc != this) {
1000 0 : vfunc.processed = true;
1001 0 : vfunc.merged = true;
1002 : }
1003 : }
1004 : }
1005 192 : if (metadata.has_argument (ArgumentType.DELEGATE_TARGET)) {
1006 0 : m.set_attribute_bool ("CCode", "delegate_target", metadata.get_bool (ArgumentType.DELEGATE_TARGET));
1007 : }
1008 192 : if (m.coroutine) {
1009 14 : parser.process_async_method (this);
1010 : }
1011 325 : } else if (symbol is Property) {
1012 16 : var colliding = parent.lookup_all (name);
1013 32 : foreach (var node in colliding) {
1014 16 : if (node.symbol is Signal) {
1015 : // properties take precedence
1016 0 : node.processed = true;
1017 0 : node.merged = true;
1018 0 : Report.warning (symbol.source_reference, "Signal `%s' conflicts with property of the same name", get_full_name ());
1019 16 : } else if (node.symbol is Method) {
1020 : // getter in C, but not in Vala
1021 0 : node.merged = true;
1022 : }
1023 : }
1024 :
1025 16 : var prop = (Property) symbol;
1026 :
1027 : // add accessors, can't do this before gir symbol resolution
1028 16 : var readable = girdata["readable"];
1029 16 : var writable = girdata["writable"];
1030 16 : var construct_ = girdata["construct"];
1031 16 : var construct_only = girdata["construct-only"];
1032 16 : if (readable != "0") {
1033 13 : prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, null);
1034 : }
1035 16 : if (writable == "1" || construct_only == "1") {
1036 16 : prop.set_accessor = new PropertyAccessor (false, (construct_only != "1") && (writable == "1"), (construct_only == "1") || (construct_ == "1"), prop.property_type.copy (), null, null);
1037 : }
1038 :
1039 : // there is no information about the internal ownership so assume `owned` as default
1040 16 : prop.property_type.value_owned = true;
1041 :
1042 : // find virtual/abstract accessors to handle abstract properties properly
1043 :
1044 16 : Node getter = null;
1045 16 : var getters = parent.lookup_all ("get_%s".printf (name));
1046 16 : if (getters != null) {
1047 20 : foreach (var g in getters) {
1048 7 : if ((getter == null || !g.merged) && g.get_cname () == "%sget_%s".printf (parent.get_lower_case_cprefix (), name)) {
1049 12 : getter = g;
1050 : }
1051 : }
1052 : }
1053 :
1054 16 : Node setter = null;
1055 16 : var setters = parent.lookup_all ("set_%s".printf (name));
1056 16 : if (setters != null) {
1057 23 : foreach (var s in setters) {
1058 8 : if ((setter == null || !s.merged) && s.get_cname () == "%sset_%s".printf (parent.get_lower_case_cprefix (), name)) {
1059 14 : setter = s;
1060 : }
1061 : }
1062 : }
1063 :
1064 16 : prop.set_attribute ("NoAccessorMethod", (readable == "0" && construct_only == "1"));
1065 29 : if (prop.get_accessor != null) {
1066 13 : var m = getter != null ? getter.symbol as Method : null;
1067 : // ensure getter vfunc if the property is abstract
1068 13 : if (m != null) {
1069 5 : getter.process (parser);
1070 5 : if (m.return_type is VoidType || m.get_parameters().size != 0 || m.tree_can_fail) {
1071 1 : prop.set_attribute ("NoAccessorMethod", true);
1072 : } else {
1073 4 : if (getter.name == name) {
1074 0 : foreach (var node in colliding) {
1075 0 : if (node.symbol is Method) {
1076 0 : node.merged = true;
1077 : }
1078 : }
1079 : }
1080 :
1081 4 : prop.get_accessor.value_type.value_owned = m.return_type.value_owned;
1082 :
1083 4 : if (!m.is_abstract && !m.is_virtual && prop.is_abstract) {
1084 0 : prop.set_attribute ("ConcreteAccessor", true);
1085 : }
1086 : }
1087 : } else {
1088 8 : prop.set_attribute ("NoAccessorMethod", true);
1089 : }
1090 : }
1091 :
1092 21 : if (!prop.has_attribute ("NoAccessorMethod") && prop.set_accessor != null && prop.set_accessor.writable) {
1093 5 : var m = setter != null ? setter.symbol as Method : null;
1094 : // ensure setter vfunc if the property is abstract
1095 5 : if (m != null) {
1096 5 : setter.process (parser);
1097 5 : if (!(m.return_type is VoidType || m.return_type is BooleanType) || m.get_parameters ().size != 1 || m.tree_can_fail) {
1098 1 : prop.set_attribute ("NoAccessorMethod", true);
1099 1 : prop.set_attribute ("ConcreteAccessor", false);
1100 : } else {
1101 4 : prop.set_accessor.value_type.value_owned = m.get_parameters()[0].variable_type.value_owned;
1102 4 : if (prop.has_attribute ("ConcreteAccessor") && !m.is_abstract && !m.is_virtual && prop.is_abstract) {
1103 0 : prop.set_attribute ("ConcreteAccessor", true);
1104 0 : prop.set_attribute ("NoAccessorMethod", false);
1105 : }
1106 : }
1107 : } else {
1108 0 : prop.set_attribute ("NoAccessorMethod", true);
1109 0 : prop.set_attribute ("ConcreteAccessor", false);
1110 : }
1111 : }
1112 :
1113 16 : if (prop.has_attribute ("NoAccessorMethod")) {
1114 13 : if (!prop.overrides && parent.symbol is Class) {
1115 : // bug 742012
1116 : // find base interface property with ConcreteAccessor and this overriding property with NoAccessorMethod
1117 11 : var base_prop_node = parser.base_interface_property (this);
1118 12 : if (base_prop_node != null) {
1119 1 : base_prop_node.process (parser);
1120 :
1121 1 : var base_property = (Property) base_prop_node.symbol;
1122 1 : if (base_property.has_attribute ("ConcreteAccessor")) {
1123 0 : prop.set_attribute ("NoAccessorMethod", false);
1124 0 : if (prop.get_accessor != null) {
1125 0 : prop.get_accessor.value_type.value_owned = base_property.get_accessor.value_type.value_owned;
1126 : }
1127 0 : if (prop.set_accessor != null) {
1128 0 : prop.set_accessor.value_type.value_owned = base_property.set_accessor.value_type.value_owned;
1129 : }
1130 :
1131 : }
1132 : }
1133 : }
1134 : }
1135 :
1136 16 : if (metadata.has_argument (ArgumentType.NO_ACCESSOR_METHOD)) {
1137 0 : prop.set_attribute ("NoAccessorMethod", metadata.get_bool (ArgumentType.NO_ACCESSOR_METHOD));
1138 : }
1139 :
1140 16 : if (prop.has_attribute ("NoAccessorMethod")) {
1141 : // gobject defaults
1142 12 : if (prop.get_accessor != null) {
1143 10 : prop.get_accessor.value_type.value_owned = true;
1144 : }
1145 12 : if (prop.set_accessor != null) {
1146 12 : prop.set_accessor.value_type.value_owned = false;
1147 : }
1148 : }
1149 355 : } else if (symbol is Field) {
1150 62 : var field = (Field) symbol;
1151 62 : var colliding = parent.lookup_all (name);
1152 62 : if (colliding.size > 1) {
1153 : // whatelse has precedence over the field
1154 0 : merged = true;
1155 : }
1156 :
1157 62 : if (metadata.has_argument (ArgumentType.DELEGATE_TARGET)) {
1158 0 : field.set_attribute_bool ("CCode", "delegate_target", metadata.get_bool (ArgumentType.DELEGATE_TARGET));
1159 : }
1160 62 : if (metadata.has_argument (ArgumentType.DELEGATE_TARGET_CNAME)) {
1161 0 : field.set_attribute_string ("CCode", "delegate_target_cname", metadata.get_string (ArgumentType.DELEGATE_TARGET_CNAME));
1162 : }
1163 62 : if (metadata.has_argument (ArgumentType.DESTROY_NOTIFY_CNAME)) {
1164 0 : field.set_attribute_string ("CCode", "destroy_notify_cname", metadata.get_string (ArgumentType.DESTROY_NOTIFY_CNAME));
1165 : }
1166 :
1167 96 : if (field.variable_type is DelegateType && parent.gtype_struct_for != null) {
1168 : // virtual method field
1169 34 : var d = ((DelegateType) field.variable_type).delegate_symbol;
1170 34 : parser.process_virtual_method_field (this, d, parent.gtype_struct_for);
1171 34 : merged = true;
1172 29 : } else if (field.variable_type is DelegateType) {
1173 : // anonymous delegate
1174 1 : var d = ((DelegateType) field.variable_type).delegate_symbol;
1175 1 : if (this.lookup (d.name).parent == this) {
1176 1 : d.set_attribute_bool ("CCode", "has_typedef", false);
1177 1 : if (d.has_target && !metadata.has_argument (ArgumentType.DELEGATE_TARGET)) {
1178 0 : field.set_attribute_bool ("CCode", "delegate_target", false);
1179 : }
1180 1 : d.name = "%s%sFunc".printf (parent.symbol.name, Symbol.lower_case_to_camel_case (d.name));
1181 1 : get_parent_namespace (this).add_delegate (d);
1182 : }
1183 30 : } else if (field.variable_type is ArrayType) {
1184 : Node array_length;
1185 3 : if (metadata.has_argument (ArgumentType.ARRAY_LENGTH_FIELD)) {
1186 0 : array_length = parent.lookup (metadata.get_string (ArgumentType.ARRAY_LENGTH_FIELD));
1187 3 : } else if (array_length_idx > -1 && parent.members.size > array_length_idx) {
1188 0 : array_length = parent.members[array_length_idx];
1189 : } else {
1190 3 : array_length = parent.lookup ("n_%s".printf (field.name));
1191 3 : if (array_length == null) {
1192 3 : array_length = parent.lookup ("num_%s".printf (field.name));
1193 3 : if (array_length == null) {
1194 3 : array_length = parent.lookup ("%s_length".printf (field.name));
1195 3 : if (array_length == null) {
1196 3 : array_length = parent.lookup ("%s_length1".printf (field.name));
1197 : }
1198 : }
1199 : }
1200 : }
1201 4 : if (array_length != null && array_length.symbol is Field) {
1202 1 : var length_field = (Field) array_length.symbol;
1203 : // array has length
1204 1 : field.set_attribute_string ("CCode", "array_length_cname", length_field.name);
1205 1 : var length_type = length_field.variable_type.to_qualified_string ();
1206 1 : if (length_type != "int") {
1207 0 : var st = parser.root.lookup (length_type);
1208 0 : if (st != null) {
1209 0 : field.set_attribute_string ("CCode", "array_length_type", st.get_cname ());
1210 : }
1211 : }
1212 1 : field.remove_attribute_argument ("CCode", "array_length");
1213 1 : field.remove_attribute_argument ("CCode", "array_null_terminated");
1214 : }
1215 : }
1216 231 : } else if (symbol is Signal || symbol is Delegate) {
1217 50 : parser.process_callable (this);
1218 181 : } else if (symbol is Class) {
1219 31 : parser.process_class (this);
1220 150 : } else if (symbol is Interface) {
1221 7 : parser.process_interface (this);
1222 143 : } else if (symbol is Struct) {
1223 38 : if (parent.symbol is ObjectTypeSymbol || parent.symbol is Struct) {
1224 : // nested struct
1225 0 : foreach (var fn in members) {
1226 0 : var f = fn.symbol as Field;
1227 0 : if (f != null) {
1228 0 : if (f.binding == MemberBinding.INSTANCE) {
1229 0 : f.set_attribute_string ("CCode", "cname", "%s.%s".printf (name, fn.get_cname ()));
1230 : }
1231 0 : f.name = "%s_%s".printf (symbol.name, f.name);
1232 0 : fn.name = f.name;
1233 0 : parent.add_member (fn);
1234 : }
1235 : }
1236 0 : merged = true;
1237 : } else {
1238 : // record for a gtype
1239 67 : if (gtype_struct_for != null) {
1240 31 : var obj = parser.resolve_node (parent, gtype_struct_for);
1241 31 : if (obj != null && obj.symbol is Interface && "%sIface".printf (obj.get_cname ()) != get_cname ()) {
1242 : // set the interface struct name
1243 1 : obj.symbol.set_attribute_string ("CCode", "type_cname", get_cname ());
1244 30 : } else if (obj != null && obj.symbol is Class && "%sClass".printf (obj.get_cname ()) != get_cname ()) {
1245 : // set the class struct name
1246 1 : obj.symbol.set_attribute_string ("CCode", "type_cname", get_cname ());
1247 : }
1248 31 : merged = true;
1249 : }
1250 : }
1251 : }
1252 :
1253 : // deprecated
1254 501 : if (metadata.has_argument (ArgumentType.REPLACEMENT)) {
1255 0 : deprecated = true;
1256 0 : deprecated_replacement = metadata.get_string (ArgumentType.REPLACEMENT);
1257 : }
1258 501 : if (metadata.has_argument (ArgumentType.DEPRECATED_SINCE)) {
1259 0 : deprecated = true;
1260 0 : deprecated_since = metadata.get_string (ArgumentType.DEPRECATED_SINCE);
1261 501 : } else if (girdata["deprecated-version"] != null) {
1262 1 : deprecated = true;
1263 1 : deprecated_since = girdata.get ("deprecated-version");
1264 : }
1265 501 : if (metadata.has_argument (ArgumentType.DEPRECATED)) {
1266 0 : deprecated = metadata.get_bool (ArgumentType.DEPRECATED, true);
1267 0 : if (!deprecated) {
1268 0 : deprecated_since = null;
1269 0 : deprecated_replacement = null;
1270 : }
1271 501 : } else if (girdata["deprecated"] != null) {
1272 1 : deprecated = true;
1273 : }
1274 501 : if (deprecated_since != null) {
1275 1 : deprecated_version = parse_version_string (deprecated_since);
1276 : }
1277 :
1278 : // experimental
1279 501 : if (metadata.has_argument (ArgumentType.EXPERIMENTAL)) {
1280 0 : symbol.set_attribute_bool ("Version", "experimental", metadata.get_bool (ArgumentType.EXPERIMENTAL));
1281 : }
1282 :
1283 : // since
1284 501 : if (metadata.has_argument (ArgumentType.SINCE)) {
1285 0 : symbol.version.since = metadata.get_string (ArgumentType.SINCE);
1286 501 : } else if (symbol is Namespace == false && girdata["version"] != null) {
1287 1 : symbol.version.since = girdata.get ("version");
1288 : }
1289 :
1290 501 : if (parent.symbol is Namespace) {
1291 : // always write cheader filename for namespace children
1292 195 : symbol.set_attribute_string ("CCode", "cheader_filename", get_cheader_filename ());
1293 306 : } else if (metadata.has_argument (ArgumentType.CHEADER_FILENAME)) {
1294 0 : symbol.set_attribute_string ("CCode", "cheader_filename", metadata.get_string (ArgumentType.CHEADER_FILENAME));
1295 : }
1296 501 : if (get_cname () != get_default_cname ()) {
1297 82 : symbol.set_attribute_string ("CCode", "cname", get_cname ());
1298 : }
1299 :
1300 501 : if (metadata.has_argument (ArgumentType.FEATURE_TEST_MACRO)) {
1301 0 : symbol.set_attribute_string ("CCode", "feature_test_macro", metadata.get_string (ArgumentType.FEATURE_TEST_MACRO));
1302 : }
1303 :
1304 : // lower_case_cprefix
1305 501 : if (get_lower_case_cprefix () != get_default_lower_case_cprefix ()) {
1306 0 : symbol.set_attribute_string ("CCode", "lower_case_cprefix", get_lower_case_cprefix ());
1307 : }
1308 : // lower_case_csuffix
1309 501 : if (get_lower_case_csuffix () != get_default_lower_case_csuffix ()) {
1310 3 : symbol.set_attribute_string ("CCode", "lower_case_csuffix", get_lower_case_csuffix ());
1311 : }
1312 :
1313 : // set gir name if the symbol has been renamed
1314 501 : string gir_name = get_gir_name ();
1315 501 : string default_gir_name = get_default_gir_name ();
1316 501 : if (is_container (symbol) && !(symbol is Namespace) && (name != gir_name || gir_name != default_gir_name)) {
1317 0 : symbol.set_attribute_string ("GIR", "name", gir_name);
1318 : }
1319 : }
1320 :
1321 2073 : if (!(new_symbol && merged) && is_container (symbol)) {
1322 2118 : foreach (var node in members) {
1323 472 : if (this.deprecated_version > 0 && node.deprecated_version > 0) {
1324 0 : if (this.deprecated_version <= node.deprecated_version) {
1325 0 : node.deprecated = false;
1326 0 : node.deprecated_since = null;
1327 0 : node.deprecated_replacement = null;
1328 : }
1329 : }
1330 472 : if (node.deprecated) {
1331 1 : node.symbol.version.deprecated = true;
1332 : }
1333 472 : if (node.deprecated_since != null) {
1334 1 : node.symbol.version.deprecated_since = node.deprecated_since;
1335 : }
1336 472 : if (node.deprecated_replacement != null) {
1337 0 : node.symbol.version.replacement = node.deprecated_replacement;
1338 : }
1339 :
1340 472 : if (node.new_symbol && !node.merged && !metadata.get_bool (ArgumentType.HIDDEN)) {
1341 367 : if (symbol.name == null || node.lookup (symbol.name) == null) {
1342 367 : add_symbol_to_container (symbol, node.symbol);
1343 : }
1344 : }
1345 : }
1346 :
1347 1646 : var cl = symbol as Class;
1348 1690 : if (cl != null && !cl.is_compact && cl.default_construction_method == null) {
1349 : // always provide constructor in generated bindings
1350 : // to indicate that implicit Object () chainup is allowed
1351 12 : var cm = new CreationMethod (null, null, cl.source_reference);
1352 12 : cm.has_construct_function = false;
1353 12 : cm.access = SymbolAccessibility.PROTECTED;
1354 12 : cl.add_method (cm);
1355 : }
1356 : }
1357 :
1358 2041 : processed = true;
1359 : }
1360 :
1361 0 : public string to_string () {
1362 0 : if (parent.name == null) {
1363 0 : return name;
1364 : } else {
1365 0 : return "%s.%s".printf (parent.to_string (), name);
1366 : }
1367 : }
1368 : }
1369 :
1370 : static GLib.Regex type_from_string_regex;
1371 :
1372 1538 : MarkupReader reader;
1373 :
1374 1538 : CodeContext context;
1375 :
1376 1538 : SourceFile current_source_file;
1377 1538 : Node root;
1378 3076 : ArrayList<Metadata> metadata_roots = new ArrayList<Metadata> ();
1379 :
1380 : SourceLocation begin;
1381 : SourceLocation end;
1382 : MarkupTokenType current_token;
1383 :
1384 1538 : string[] cheader_filenames;
1385 :
1386 1538 : ArrayList<Metadata> metadata_stack;
1387 1538 : Metadata metadata;
1388 1538 : ArrayList<Node> tree_stack;
1389 1538 : Node current;
1390 1538 : Node old_current;
1391 :
1392 3076 : Set<string> provided_namespaces = new HashSet<string> (str_hash, str_equal);
1393 3076 : HashMap<UnresolvedSymbol,Symbol> unresolved_symbols_map = new HashMap<UnresolvedSymbol,Symbol> (unresolved_symbol_hash, unresolved_symbol_equal);
1394 3076 : ArrayList<UnresolvedSymbol> unresolved_gir_symbols = new ArrayList<UnresolvedSymbol> ();
1395 3076 : HashMap<UnresolvedType,Node> unresolved_type_arguments = new HashMap<UnresolvedType,Node> ();
1396 3076 : ArrayList<Interface> ifaces_needing_object_prereq = new ArrayList<Interface> ();
1397 :
1398 : /**
1399 : * Parses all .gir source files in the specified code
1400 : * context and builds a code tree.
1401 : *
1402 : * @param context a code context
1403 : */
1404 3067 : public void parse (CodeContext context) {
1405 1538 : this.context = context;
1406 :
1407 1538 : root = new Node (null);
1408 74830 : root.symbol = context.root;
1409 1538 : tree_stack = new ArrayList<Node> ();
1410 3718 : current = root;
1411 :
1412 1538 : map_vala_to_gir ();
1413 :
1414 1538 : context.accept (this);
1415 :
1416 1538 : resolve_gir_symbols ();
1417 1538 : create_new_namespaces ();
1418 1538 : resolve_type_arguments ();
1419 :
1420 1538 : root.process (this);
1421 :
1422 : /* Temporarily workaround G-I bug not adding GLib.Object prerequisite:
1423 : ensure we have at least one instantiable prerequisite */
1424 1538 : var glib_ns = context.root.scope.lookup ("GLib") as Namespace;
1425 4596 : if (glib_ns != null) {
1426 1529 : var object_type = (Class) glib_ns.scope.lookup ("Object");
1427 1537 : foreach (var iface in ifaces_needing_object_prereq) {
1428 4 : iface.add_prerequisite (new ObjectType (object_type));
1429 : }
1430 : }
1431 :
1432 1540 : foreach (var metadata in metadata_roots) {
1433 1 : report_unused_metadata (metadata);
1434 : }
1435 :
1436 1538 : this.context = null;
1437 : }
1438 :
1439 1538 : void map_vala_to_gir () {
1440 13196 : foreach (var source_file in context.get_source_files ()) {
1441 6761 : string gir_namespace = source_file.gir_namespace;
1442 6761 : string gir_version = source_file.gir_version;
1443 6761 : Namespace ns = null;
1444 6761 : if (gir_namespace == null) {
1445 4927939 : foreach (var node in source_file.get_nodes ()) {
1446 2465486 : if (node is Namespace) {
1447 68508 : ns = (Namespace) node;
1448 68508 : gir_namespace = ns.get_attribute_string ("CCode", "gir_namespace");
1449 68508 : if (gir_namespace != null) {
1450 4897 : gir_version = ns.get_attribute_string ("CCode", "gir_version");
1451 4897 : break;
1452 : }
1453 : }
1454 : }
1455 : }
1456 6761 : if (gir_namespace == null) {
1457 1864 : continue;
1458 : }
1459 :
1460 4897 : provided_namespaces.add ("%s-%s".printf (gir_namespace, gir_version));
1461 :
1462 4897 : var gir_symbol = new UnresolvedSymbol (null, gir_namespace);
1463 4897 : if (gir_namespace != ns.name) {
1464 3219 : set_symbol_mapping (gir_symbol, ns);
1465 : }
1466 :
1467 4846631 : foreach (var node in source_file.get_nodes ()) {
1468 2482482 : if (node.has_attribute_argument ("GIR", "name")) {
1469 61615 : var map_from = new UnresolvedSymbol (gir_symbol, node.get_attribute_string ("GIR", "name"));
1470 61615 : set_symbol_mapping (map_from, (Symbol) node);
1471 : }
1472 : }
1473 : }
1474 : }
1475 :
1476 6886 : public override void visit_source_file (SourceFile source_file) {
1477 6886 : if (source_file.filename.has_suffix (".gir")) {
1478 170 : parse_file (source_file);
1479 : }
1480 : }
1481 :
1482 170 : public void parse_file (SourceFile source_file) {
1483 170 : var has_global_context = (context != null);
1484 170 : if (!has_global_context) {
1485 0 : context = source_file.context;
1486 : }
1487 :
1488 170 : metadata_stack = new ArrayList<Metadata> ();
1489 4847 : metadata = Metadata.empty;
1490 170 : cheader_filenames = null;
1491 :
1492 170 : this.current_source_file = source_file;
1493 170 : reader = new MarkupReader (source_file.filename);
1494 :
1495 : // xml prolog
1496 680 : do {
1497 510 : next ();
1498 510 : if (current_token == MarkupTokenType.EOF) {
1499 0 : Report.error (get_current_src (), "unexpected end of file");
1500 0 : return;
1501 : }
1502 510 : } while (current_token != MarkupTokenType.START_ELEMENT && reader.name != "repository");
1503 :
1504 170 : parse_repository ();
1505 :
1506 170 : reader = null;
1507 170 : this.current_source_file = null;
1508 170 : if (!has_global_context) {
1509 0 : context = null;
1510 : }
1511 : }
1512 :
1513 6746 : void next () {
1514 6746 : current_token = reader.read_token (out begin, out end);
1515 : }
1516 :
1517 2807 : void start_element (string name) {
1518 2807 : if (current_token != MarkupTokenType.START_ELEMENT || reader.name != name) {
1519 : // error
1520 0 : Report.error (get_current_src (), "expected start element of `%s'", name);
1521 : }
1522 : }
1523 :
1524 2683 : void end_element (string name) {
1525 2683 : while (current_token != MarkupTokenType.END_ELEMENT || reader.name != name) {
1526 0 : Report.warning (get_current_src (), "expected end element of `%s'", name);
1527 0 : skip_element ();
1528 : }
1529 2683 : next ();
1530 : }
1531 :
1532 1958 : SourceReference get_current_src () {
1533 1958 : return new SourceReference (this.current_source_file, begin, end);
1534 : }
1535 :
1536 458 : SourceReference get_src (SourceLocation begin, SourceLocation? end = null) {
1537 458 : var e = this.end;
1538 458 : if (end != null) {
1539 0 : e = end;
1540 : }
1541 458 : return new SourceReference (this.current_source_file, begin, e);
1542 : }
1543 :
1544 : const string GIR_VERSION = "1.2";
1545 :
1546 367 : static void add_symbol_to_container (Symbol container, Symbol sym) {
1547 367 : if (sym.name == "") {
1548 1 : Report.warning (sym.source_reference, "node with empty name");
1549 1 : return;
1550 366 : } else if (sym.name != null) {
1551 346 : Symbol? old_sym = container.scope.lookup (sym.name);
1552 346 : if (old_sym != null) {
1553 1 : Report.warning (sym.source_reference, "`%s' already contains a definition for `%s'", container.name, sym.name);
1554 1 : Report.notice (old_sym.source_reference, "previous definition of `%s' was here", old_sym.name);
1555 1 : return;
1556 : }
1557 : }
1558 :
1559 365 : if (container is Class) {
1560 131 : unowned Class cl = (Class) container;
1561 :
1562 131 : if (sym is Class) {
1563 0 : cl.add_class ((Class) sym);
1564 131 : } else if (sym is Constant) {
1565 0 : cl.add_constant ((Constant) sym);
1566 131 : } else if (sym is Enum) {
1567 0 : cl.add_enum ((Enum) sym);
1568 131 : } else if (sym is Field) {
1569 17 : cl.add_field ((Field) sym);
1570 114 : } else if (sym is Method) {
1571 96 : cl.add_method ((Method) sym);
1572 18 : } else if (sym is Property) {
1573 14 : cl.add_property ((Property) sym);
1574 4 : } else if (sym is Signal) {
1575 4 : cl.add_signal ((Signal) sym);
1576 0 : } else if (sym is Struct) {
1577 0 : cl.add_struct ((Struct) sym);
1578 : }
1579 234 : } else if (container is Enum) {
1580 21 : unowned Enum en = (Enum) container;
1581 :
1582 21 : if (sym is EnumValue) {
1583 21 : en.add_value ((EnumValue) sym);
1584 0 : } else if (sym is Constant) {
1585 0 : en.add_constant ((Constant) sym);
1586 0 : } else if (sym is Method) {
1587 0 : en.add_method ((Method) sym);
1588 : }
1589 213 : } else if (container is Interface) {
1590 16 : unowned Interface iface = (Interface) container;
1591 :
1592 16 : if (sym is Class) {
1593 0 : iface.add_class ((Class) sym);
1594 16 : } else if (sym is Constant) {
1595 0 : iface.add_constant ((Constant) sym);
1596 16 : } else if (sym is Enum) {
1597 0 : iface.add_enum ((Enum) sym);
1598 16 : } else if (sym is Field) {
1599 0 : iface.add_field ((Field) sym);
1600 16 : } else if (sym is Method) {
1601 13 : iface.add_method ((Method) sym);
1602 3 : } else if (sym is Property) {
1603 2 : iface.add_property ((Property) sym);
1604 1 : } else if (sym is Signal) {
1605 1 : iface.add_signal ((Signal) sym);
1606 0 : } else if (sym is Struct) {
1607 0 : iface.add_struct ((Struct) sym);
1608 : }
1609 197 : } else if (container is Namespace) {
1610 164 : unowned Namespace ns = (Namespace) container;
1611 :
1612 164 : if (sym is Namespace) {
1613 47 : ns.add_namespace ((Namespace) sym);
1614 117 : } else if (sym is Class) {
1615 31 : ns.add_class ((Class) sym);
1616 86 : } else if (sym is Constant) {
1617 11 : ns.add_constant ((Constant) sym);
1618 75 : } else if (sym is Delegate) {
1619 10 : ns.add_delegate ((Delegate) sym);
1620 65 : } else if (sym is Enum) {
1621 10 : ns.add_enum ((Enum) sym);
1622 55 : } else if (sym is ErrorDomain) {
1623 5 : ns.add_error_domain ((ErrorDomain) sym);
1624 50 : } else if (sym is Field) {
1625 0 : unowned Field field = (Field) sym;
1626 0 : if (field.binding == MemberBinding.INSTANCE) {
1627 0 : field.binding = MemberBinding.STATIC;
1628 : }
1629 0 : ns.add_field (field);
1630 50 : } else if (sym is Interface) {
1631 7 : ns.add_interface ((Interface) sym);
1632 43 : } else if (sym is Method) {
1633 36 : unowned Method method = (Method) sym;
1634 36 : if (method.binding == MemberBinding.INSTANCE) {
1635 0 : method.binding = MemberBinding.STATIC;
1636 : }
1637 36 : ns.add_method (method);
1638 7 : } else if (sym is Struct) {
1639 7 : ns.add_struct ((Struct) sym);
1640 : }
1641 33 : } else if (container is Struct) {
1642 22 : unowned Struct st = (Struct) container;
1643 :
1644 22 : if (sym is Constant) {
1645 0 : st.add_constant ((Constant) sym);
1646 22 : } else if (sym is Field) {
1647 11 : st.add_field ((Field) sym);
1648 11 : } else if (sym is Method) {
1649 11 : st.add_method ((Method) sym);
1650 0 : } else if (sym is Property) {
1651 0 : st.add_property ((Property) sym);
1652 : }
1653 11 : } else if (container is ErrorDomain) {
1654 11 : unowned ErrorDomain ed = (ErrorDomain) container;
1655 :
1656 11 : if (sym is ErrorCode) {
1657 11 : ed.add_code ((ErrorCode) sym);
1658 0 : } else if (sym is Method) {
1659 0 : ed.add_method ((Method) sym);
1660 : }
1661 : } else {
1662 0 : Report.error (sym.source_reference, "impossible to add `%s' to container `%s'", sym.name, container.name);
1663 : }
1664 : }
1665 :
1666 3042 : static bool is_container (Symbol sym) {
1667 3042 : return sym is ObjectTypeSymbol || sym is Struct || sym is Namespace || sym is ErrorDomain || sym is Enum;
1668 : }
1669 :
1670 1 : static unowned Namespace get_parent_namespace (Node node) {
1671 1 : unowned Node? n = node.parent;
1672 2 : while (n != null) {
1673 2 : if (n.symbol is Namespace) {
1674 1 : return (Namespace) n.symbol;
1675 : }
1676 1 : n = n.parent;
1677 : }
1678 0 : assert_not_reached ();
1679 : }
1680 :
1681 662 : UnresolvedSymbol? parse_symbol_from_string (string symbol_string, SourceReference? source_reference = null) {
1682 662 : UnresolvedSymbol? sym = null;
1683 2319 : foreach (unowned string s in symbol_string.split (".")) {
1684 995 : sym = new UnresolvedSymbol (sym, s, source_reference);
1685 : }
1686 662 : if (sym == null) {
1687 0 : Report.error (source_reference, "a symbol must be specified");
1688 : }
1689 : return sym;
1690 : }
1691 :
1692 64881 : void set_symbol_mapping (UnresolvedSymbol map_from, Symbol map_to) {
1693 : // last mapping is the most up-to-date
1694 64881 : if (map_from is UnresolvedSymbol) {
1695 64881 : unresolved_symbols_map[(UnresolvedSymbol) map_from] = map_to;
1696 : }
1697 : }
1698 :
1699 6 : void assume_parameter_names (Signal sig, Symbol sym, bool skip_first) {
1700 3 : var iter = ((Callable) sym).get_parameters ().iterator ();
1701 3 : bool first = true;
1702 7 : foreach (var param in sig.get_parameters ()) {
1703 2 : if (!iter.next ()) {
1704 : // unreachable for valid GIR
1705 0 : break;
1706 : }
1707 2 : if (skip_first && first) {
1708 0 : if (!iter.next ()) {
1709 : // unreachable for valid GIR
1710 0 : break;
1711 : }
1712 : first = false;
1713 : }
1714 2 : param.name = iter.get ().name;
1715 : }
1716 : }
1717 :
1718 0 : Node? find_invoker (Node node) {
1719 : /* most common use case is invoker has at least the given method prefix
1720 : and the same parameter names */
1721 0 : var m = (Method) node.symbol;
1722 0 : var prefix = "%s_".printf (m.name);
1723 0 : foreach (var n in node.parent.members) {
1724 0 : if (!n.name.has_prefix (prefix)) {
1725 0 : continue;
1726 : }
1727 0 : Method? invoker = n.symbol as Method;
1728 0 : if (invoker == null || (m.get_parameters().size != invoker.get_parameters().size)) {
1729 0 : continue;
1730 : }
1731 0 : var iter = invoker.get_parameters ().iterator ();
1732 0 : foreach (var param in m.get_parameters ()) {
1733 0 : assert (iter.next ());
1734 0 : if (param.name != iter.get().name) {
1735 0 : invoker = null;
1736 0 : break;
1737 : }
1738 : }
1739 0 : if (invoker != null) {
1740 0 : return n;
1741 : }
1742 : }
1743 :
1744 0 : return null;
1745 : }
1746 :
1747 991 : Metadata get_current_metadata () {
1748 991 : var selector = reader.name;
1749 991 : var child_name = reader.get_attribute ("name");
1750 991 : if (child_name == null) {
1751 1 : child_name = reader.get_attribute ("glib:name");
1752 : }
1753 : // Give a transparent union the generic name "union"
1754 991 : if (selector == "union" && child_name == null) {
1755 1 : child_name = "union";
1756 : }
1757 991 : if (child_name == null) {
1758 0 : return Metadata.empty;
1759 : }
1760 991 : selector = selector.replace ("-", "_");
1761 991 : child_name = child_name.replace ("-", "_");
1762 :
1763 991 : if (selector.has_prefix ("glib:")) {
1764 6 : selector = selector.substring ("glib:".length);
1765 : }
1766 :
1767 991 : return metadata.match_child (child_name, selector);
1768 : }
1769 :
1770 991 : bool push_metadata () {
1771 991 : var new_metadata = get_current_metadata ();
1772 : // skip ?
1773 991 : if (new_metadata.has_argument (ArgumentType.SKIP)) {
1774 8 : if (new_metadata.get_bool (ArgumentType.SKIP)) {
1775 2 : return false;
1776 : }
1777 983 : } else if (reader.get_attribute ("introspectable") == "0" || reader.get_attribute ("private") == "1") {
1778 68 : return false;
1779 : }
1780 :
1781 921 : metadata_stack.add (metadata);
1782 1842 : metadata = new_metadata;
1783 :
1784 921 : return true;
1785 : }
1786 :
1787 921 : void pop_metadata () {
1788 921 : metadata = metadata_stack.remove_at (metadata_stack.size - 1);
1789 : }
1790 :
1791 0 : bool parse_type_arguments_from_string (DataType parent_type, string type_arguments, SourceReference? source_reference = null) {
1792 0 : int type_arguments_length = (int) type_arguments.length;
1793 0 : GLib.StringBuilder current = new GLib.StringBuilder.sized (type_arguments_length);
1794 :
1795 0 : int depth = 0;
1796 0 : for (var c = 0 ; c < type_arguments_length ; c++) {
1797 0 : if (type_arguments[c] == '<' || type_arguments[c] == '[') {
1798 0 : depth++;
1799 0 : current.append_unichar (type_arguments[c]);
1800 0 : } else if (type_arguments[c] == '>' || type_arguments[c] == ']') {
1801 0 : depth--;
1802 0 : current.append_unichar (type_arguments[c]);
1803 0 : } else if (type_arguments[c] == ',') {
1804 0 : if (depth == 0) {
1805 0 : var dt = parse_type_from_string (current.str, true, source_reference);
1806 0 : if (dt == null) {
1807 0 : return false;
1808 : }
1809 0 : parent_type.add_type_argument (dt);
1810 0 : current.truncate ();
1811 : } else {
1812 0 : current.append_unichar (type_arguments[c]);
1813 : }
1814 : } else {
1815 0 : current.append_unichar (type_arguments[c]);
1816 : }
1817 : }
1818 :
1819 0 : var dt = parse_type_from_string (current.str, true, source_reference);
1820 0 : if (dt == null) {
1821 0 : return false;
1822 : }
1823 0 : parent_type.add_type_argument (dt);
1824 :
1825 0 : return true;
1826 : }
1827 :
1828 0 : List<DataType> parse_list_of_types_from_string (string type_list, SourceReference? source_reference = null) {
1829 0 : var types = new ArrayList<DataType> ();
1830 0 : var type_list_length = type_list.length;
1831 0 : GLib.StringBuilder current = new GLib.StringBuilder.sized (type_list_length);
1832 :
1833 0 : for (var c = 0 ; c < type_list_length ; c++) {
1834 0 : if (type_list[c] == ',') {
1835 0 : types.add (parse_type_from_string (current.str, true, source_reference));
1836 0 : current.truncate ();
1837 : } else {
1838 0 : current.append_unichar (type_list[c]);
1839 : }
1840 : }
1841 :
1842 0 : types.add (parse_type_from_string (current.str, true, source_reference));
1843 :
1844 0 : return types;
1845 : }
1846 :
1847 0 : bool parse_type_parameters_from_string (GenericSymbol type_symbol, string type_parameters, SourceReference? source_reference = null) {
1848 0 : var type_parameters_length = type_parameters.length;
1849 0 : GLib.StringBuilder current = new GLib.StringBuilder.sized (type_parameters_length);
1850 :
1851 0 : for (var c = 0 ; c < type_parameters_length ; c++) {
1852 0 : if (type_parameters[c] == ',') {
1853 0 : var p = new TypeParameter (current.str, source_reference);
1854 0 : type_symbol.add_type_parameter (p);
1855 0 : current.truncate ();
1856 : } else {
1857 0 : current.append_unichar (type_parameters[c]);
1858 : }
1859 : }
1860 :
1861 0 : var p = new TypeParameter (current.str, source_reference);
1862 0 : type_symbol.add_type_parameter (p);
1863 :
1864 0 : return true;
1865 : }
1866 :
1867 9 : DataType? parse_type_from_string (string type_string, bool owned_by_default, SourceReference? source_reference = null) {
1868 9 : if (type_from_string_regex == null) {
1869 0 : try {
1870 1 : type_from_string_regex = new GLib.Regex ("^(?:(owned|unowned|weak) +)?([0-9a-zA-Z_\\.]+)(?:<(.+)>)?(\\*+)?(\\[,*\\])?(\\?)?$", GLib.RegexCompileFlags.ANCHORED | GLib.RegexCompileFlags.DOLLAR_ENDONLY | GLib.RegexCompileFlags.OPTIMIZE);
1871 : } catch (GLib.RegexError e) {
1872 0 : GLib.error ("Unable to compile regex: %s", e.message);
1873 : }
1874 : }
1875 :
1876 : GLib.MatchInfo match;
1877 9 : if (!type_from_string_regex.match (type_string, 0, out match)) {
1878 0 : Report.error (source_reference, "unable to parse type");
1879 0 : return null;
1880 : }
1881 :
1882 9 : DataType? type = null;
1883 :
1884 9 : var ownership_data = match.fetch (1);
1885 9 : var type_name = match.fetch (2);
1886 9 : var type_arguments_data = match.fetch (3);
1887 9 : var pointers_data = match.fetch (4);
1888 9 : var array_data = match.fetch (5);
1889 9 : var nullable_data = match.fetch (6);
1890 :
1891 9 : var nullable = nullable_data != null && nullable_data.length > 0;
1892 :
1893 9 : if (ownership_data == null && type_name == "void") {
1894 0 : if (array_data == null && !nullable) {
1895 0 : type = new VoidType (source_reference);
1896 0 : if (pointers_data != null) {
1897 0 : for (int i=0; i < pointers_data.length; i++) {
1898 0 : type = new PointerType (type);
1899 : }
1900 : }
1901 0 : return type;
1902 : } else {
1903 0 : Report.error (source_reference, "invalid void type");
1904 0 : return null;
1905 : }
1906 : }
1907 :
1908 9 : bool value_owned = owned_by_default;
1909 :
1910 9 : if (ownership_data == "owned") {
1911 0 : if (owned_by_default) {
1912 0 : Report.error (source_reference, "unexpected `owned' keyword");
1913 : } else {
1914 : value_owned = true;
1915 : }
1916 9 : } else if (ownership_data == "unowned") {
1917 0 : if (owned_by_default) {
1918 : value_owned = false;
1919 : } else {
1920 0 : Report.error (source_reference, "unexpected `unowned' keyword");
1921 0 : return null;
1922 : }
1923 : }
1924 :
1925 9 : var sym = parse_symbol_from_string (type_name, source_reference);
1926 9 : if (sym == null) {
1927 0 : return null;
1928 : }
1929 9 : type = new UnresolvedType.from_symbol (sym, source_reference);
1930 :
1931 9 : if (type_arguments_data != null && type_arguments_data.length > 0) {
1932 0 : if (!parse_type_arguments_from_string (type, type_arguments_data, source_reference)) {
1933 0 : return null;
1934 : }
1935 : }
1936 :
1937 9 : if (pointers_data != null) {
1938 9 : for (int i=0; i < pointers_data.length; i++) {
1939 0 : type = new PointerType (type);
1940 : }
1941 : }
1942 :
1943 9 : if (array_data != null && array_data.length != 0) {
1944 0 : type.value_owned = true;
1945 0 : type = new ArrayType (type, (int) array_data.length - 1, source_reference);
1946 : }
1947 :
1948 9 : type.nullable = nullable;
1949 9 : type.value_owned = value_owned;
1950 9 : return type;
1951 : }
1952 :
1953 458 : string? element_get_string (string attribute_name, ArgumentType arg_type) {
1954 458 : if (metadata.has_argument (arg_type)) {
1955 0 : return metadata.get_string (arg_type);
1956 : } else {
1957 458 : return reader.get_attribute (attribute_name);
1958 : }
1959 : }
1960 :
1961 : /*
1962 : * The changed is a faster way to check whether the type has changed and it may affect the C declaration.
1963 : */
1964 790 : 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) {
1965 790 : changed = false;
1966 790 : var type = orig_type;
1967 :
1968 790 : if (metadata.has_argument (ArgumentType.TYPE)) {
1969 0 : type = parse_type_from_string (metadata.get_string (ArgumentType.TYPE), owned_by_default, metadata.get_source_reference (ArgumentType.TYPE));
1970 0 : changed = true;
1971 790 : } else if (!(type is VoidType)) {
1972 633 : if (metadata.has_argument (ArgumentType.TYPE_ARGUMENTS)) {
1973 0 : type.remove_all_type_arguments ();
1974 0 : parse_type_arguments_from_string (type, metadata.get_string (ArgumentType.TYPE_ARGUMENTS), metadata.get_source_reference (ArgumentType.TYPE_ARGUMENTS));
1975 : }
1976 :
1977 633 : if (!(type is ArrayType) && metadata.get_bool (ArgumentType.ARRAY)) {
1978 0 : type.value_owned = true;
1979 0 : type = new ArrayType (type, 1, type.source_reference);
1980 : changed = true;
1981 : }
1982 :
1983 633 : if (owned_by_default) {
1984 238 : type.value_owned = !metadata.get_bool (ArgumentType.UNOWNED, !type.value_owned);
1985 : } else {
1986 395 : type.value_owned = metadata.get_bool (ArgumentType.OWNED, type.value_owned);
1987 : }
1988 633 : type.nullable = metadata.get_bool (ArgumentType.NULLABLE, type.nullable);
1989 : }
1990 :
1991 790 : if (type is ArrayType) {
1992 39 : if (!(orig_type is ArrayType)) {
1993 0 : no_array_length = true;
1994 : }
1995 39 : array_null_terminated = metadata.get_bool (ArgumentType.ARRAY_NULL_TERMINATED, array_null_terminated);
1996 : }
1997 :
1998 790 : return type;
1999 : }
2000 :
2001 492 : string? element_get_name (string? gir_name = null) {
2002 492 : unowned string tag = reader.name;
2003 :
2004 492 : var name = gir_name;
2005 492 : if (name == null) {
2006 463 : name = reader.get_attribute ("name");
2007 : }
2008 492 : var pattern = metadata.get_string (ArgumentType.NAME);
2009 492 : if (pattern != null) {
2010 2 : if (pattern.index_of_char ('(') < 0) {
2011 : // shortcut for "(.+)/replacement"
2012 4 : name = pattern;
2013 : } else {
2014 0 : try {
2015 0 : string replacement = "\\1"; // replace the whole name with the match by default
2016 0 : var split = pattern.split ("/");
2017 0 : if (split.length > 1) {
2018 0 : pattern = split[0];
2019 0 : replacement = split[1];
2020 : }
2021 0 : var regex = new Regex (pattern, RegexCompileFlags.ANCHORED, RegexMatchFlags.ANCHORED);
2022 0 : name = regex.replace (name, -1, 0, replacement);
2023 : } catch (Error e) {
2024 0 : name = pattern;
2025 : }
2026 : }
2027 490 : } else if (tag == "enumeration") {
2028 : // FIXME Stripping "Enum"-suffix is required for error-domains
2029 : // Applied to all enumerations to preserve backwards compatibility
2030 11 : if (name != null && name.has_suffix ("Enum")) {
2031 0 : name = name.substring (0, name.length - "Enum".length);
2032 : }
2033 : }
2034 :
2035 492 : return name;
2036 : }
2037 :
2038 141 : string? element_get_type_id () {
2039 141 : var type_id = metadata.get_string (ArgumentType.TYPE_ID);
2040 141 : if (type_id != null) {
2041 : return type_id;
2042 : }
2043 :
2044 141 : type_id = reader.get_attribute ("glib:get-type");
2045 141 : if (type_id != null) {
2046 48 : type_id += " ()";
2047 : }
2048 : return type_id;
2049 : }
2050 :
2051 62 : void set_array_ccode (Symbol sym, ParameterInfo info) {
2052 31 : sym.set_attribute_double ("CCode", "array_length_pos", info.vala_idx);
2053 31 : if (sym is Parameter) {
2054 20 : sym.set_attribute_string ("CCode", "array_length_cname", info.param.name);
2055 : }
2056 31 : var type_name = info.param.variable_type.to_qualified_string ();
2057 41 : if (type_name != "int") {
2058 10 : var st = root.lookup (type_name);
2059 10 : if (st != null) {
2060 10 : if (sym is Callable || sym is Parameter) {
2061 10 : sym.set_attribute_string ("CCode", "array_length_type", st.get_cname ());
2062 : }
2063 : }
2064 : }
2065 : }
2066 :
2067 174 : void set_type_id_ccode (Symbol sym) {
2068 174 : if (sym.has_attribute_argument ("CCode", "has_type_id")
2069 87 : || sym.has_attribute_argument ("CCode", "type_id"))
2070 0 : return;
2071 :
2072 87 : var type_id = element_get_type_id ();
2073 87 : if (type_id == null) {
2074 42 : sym.set_attribute_bool ("CCode", "has_type_id", false);
2075 : } else {
2076 45 : sym.set_attribute_string ("CCode", "type_id", type_id);
2077 : }
2078 : }
2079 :
2080 170 : void parse_repository () {
2081 170 : start_element ("repository");
2082 170 : if (reader.get_attribute ("version") != GIR_VERSION) {
2083 0 : Report.error (get_current_src (), "unsupported GIR version %s (supported: %s)", reader.get_attribute ("version"), GIR_VERSION);
2084 0 : return;
2085 : }
2086 170 : next ();
2087 510 : while (current_token == MarkupTokenType.START_ELEMENT) {
2088 464 : if (reader.name == "namespace") {
2089 46 : parse_namespace ();
2090 418 : } else if (reader.name == "include") {
2091 202 : parse_include ();
2092 262 : } else if (reader.name == "package") {
2093 170 : var pkg = parse_package ();
2094 170 : this.current_source_file.package_name = pkg;
2095 170 : if (context.has_package (pkg)) {
2096 : // package already provided elsewhere, stop parsing this GIR
2097 : // if it was not passed explicitly
2098 124 : if (!this.current_source_file.from_commandline) {
2099 124 : return;
2100 : }
2101 : } else {
2102 46 : context.add_package (pkg);
2103 : }
2104 46 : } else if (reader.name == "c:include") {
2105 46 : parse_c_include ();
2106 : } else {
2107 : // error
2108 0 : Report.error (get_current_src (), "unknown child element `%s' in `repository'", reader.name);
2109 0 : skip_element ();
2110 : }
2111 : }
2112 46 : end_element ("repository");
2113 : }
2114 :
2115 404 : void parse_include () {
2116 202 : start_element ("include");
2117 202 : var pkg = reader.get_attribute ("name");
2118 202 : var version = reader.get_attribute ("version");
2119 202 : if (version != null) {
2120 202 : pkg = "%s-%s".printf (pkg, version);
2121 : }
2122 : // add the package to the queue
2123 202 : context.add_external_package (pkg);
2124 202 : next ();
2125 202 : end_element ("include");
2126 : }
2127 :
2128 170 : string parse_package () {
2129 170 : start_element ("package");
2130 170 : var pkg = reader.get_attribute ("name");
2131 170 : next ();
2132 170 : end_element ("package");
2133 170 : return pkg;
2134 : }
2135 :
2136 46 : void parse_c_include () {
2137 46 : start_element ("c:include");
2138 92 : cheader_filenames += reader.get_attribute ("name");
2139 46 : next ();
2140 46 : end_element ("c:include");
2141 : }
2142 :
2143 105 : void skip_element () {
2144 105 : next ();
2145 :
2146 105 : int level = 1;
2147 744 : while (level > 0) {
2148 639 : if (current_token == MarkupTokenType.START_ELEMENT) {
2149 267 : level++;
2150 372 : } else if (current_token == MarkupTokenType.END_ELEMENT) {
2151 372 : level--;
2152 0 : } else if (current_token == MarkupTokenType.EOF) {
2153 0 : Report.error (get_current_src (), "unexpected end of file");
2154 : break;
2155 : }
2156 639 : next ();
2157 : }
2158 : }
2159 :
2160 366 : Node? resolve_node (Node parent_scope, UnresolvedSymbol unresolved_sym, bool create_namespace = false) {
2161 366 : if (unresolved_sym.inner == null) {
2162 281 : var scope = parent_scope;
2163 553 : while (scope != null) {
2164 541 : var node = scope.lookup (unresolved_sym.name, create_namespace, unresolved_sym.source_reference);
2165 541 : if (node != null) {
2166 269 : return node;
2167 : }
2168 272 : scope = scope.parent;
2169 : }
2170 : } else {
2171 85 : var inner = resolve_node (parent_scope, unresolved_sym.inner, create_namespace);
2172 85 : if (inner != null) {
2173 85 : return inner.lookup (unresolved_sym.name, create_namespace, unresolved_sym.source_reference);
2174 : }
2175 : }
2176 366 : return null;
2177 : }
2178 :
2179 122 : Symbol? resolve_symbol (Node parent_scope, UnresolvedSymbol unresolved_sym) {
2180 122 : var node = resolve_node (parent_scope, unresolved_sym);
2181 122 : if (node != null) {
2182 120 : return node.symbol;
2183 : }
2184 122 : return null;
2185 : }
2186 :
2187 1002 : void push_node (string name, bool merge) {
2188 501 : var parent = current;
2189 502 : if (metadata.has_argument (ArgumentType.PARENT)) {
2190 1 : var target = parse_symbol_from_string (metadata.get_string (ArgumentType.PARENT), metadata.get_source_reference (ArgumentType.PARENT));
2191 1 : parent = resolve_node (root, target, true);
2192 : }
2193 :
2194 501 : var node = parent.lookup (name);
2195 501 : if (node == null || (node.symbol != null && !merge)) {
2196 501 : node = new Node (name);
2197 501 : node.new_symbol = true;
2198 501 : parent.add_member (node);
2199 : } else {
2200 0 : Node.new_namespaces.remove (node);
2201 : }
2202 1002 : node.element_type = reader.name;
2203 501 : node.girdata = reader.get_attributes ();
2204 1002 : node.metadata = metadata;
2205 501 : node.source_reference = get_current_src ();
2206 :
2207 501 : var gir_name = node.get_gir_name ();
2208 501 : if (parent != current || gir_name != name) {
2209 47 : set_symbol_mapping (new UnresolvedSymbol (null, gir_name), node.get_unresolved_symbol ());
2210 : }
2211 :
2212 501 : tree_stack.add (current);
2213 501 : current = node;
2214 : }
2215 :
2216 501 : void pop_node () {
2217 1002 : old_current = current;
2218 501 : current = tree_stack.remove_at (tree_stack.size - 1);
2219 : }
2220 :
2221 92 : void parse_namespace () {
2222 46 : start_element ("namespace");
2223 :
2224 46 : string? cprefix = reader.get_attribute ("c:identifier-prefixes");
2225 46 : if (cprefix != null) {
2226 46 : int idx = cprefix.index_of (",");
2227 46 : if (idx != -1) {
2228 0 : cprefix = cprefix.substring (0, idx);
2229 : }
2230 : }
2231 :
2232 46 : string? lower_case_cprefix = reader.get_attribute ("c:symbol-prefixes");
2233 46 : string vala_namespace = cprefix;
2234 46 : string gir_namespace = reader.get_attribute ("name");
2235 46 : string gir_version = reader.get_attribute ("version");
2236 :
2237 46 : if (lower_case_cprefix != null) {
2238 46 : int idx = lower_case_cprefix.index_of (",");
2239 46 : if (idx != -1) {
2240 0 : lower_case_cprefix = lower_case_cprefix.substring (0, idx);
2241 : }
2242 : }
2243 :
2244 46 : if (provided_namespaces.contains ("%s-%s".printf (gir_namespace, gir_version))) {
2245 0 : skip_element ();
2246 0 : return;
2247 : }
2248 :
2249 : // load metadata, first look into metadata directories then in the same directory of the .gir.
2250 46 : string? metadata_filename = context.get_metadata_path (current_source_file.filename);
2251 47 : if (metadata_filename != null && FileUtils.test (metadata_filename, FileTest.EXISTS)) {
2252 1 : var metadata_parser = new MetadataParser ();
2253 1 : var metadata_file = new SourceFile (context, current_source_file.file_type, metadata_filename);
2254 1 : context.add_source_file (metadata_file);
2255 1 : metadata = metadata_parser.parse_metadata (metadata_file);
2256 1 : metadata_roots.add (metadata);
2257 : }
2258 :
2259 46 : var ns_metadata = metadata.match_child (gir_namespace);
2260 46 : if (ns_metadata.has_argument (ArgumentType.NAME)) {
2261 0 : vala_namespace = ns_metadata.get_string (ArgumentType.NAME);
2262 : }
2263 46 : if (vala_namespace == null) {
2264 0 : vala_namespace = gir_namespace;
2265 : }
2266 :
2267 46 : current_source_file.gir_namespace = gir_namespace;
2268 46 : current_source_file.gir_version = gir_version;
2269 :
2270 : Namespace ns;
2271 46 : push_node (vala_namespace, true);
2272 46 : if (current.new_symbol) {
2273 46 : ns = new Namespace (vala_namespace, current.source_reference);
2274 92 : current.symbol = ns;
2275 : } else {
2276 0 : ns = (Namespace) current.symbol;
2277 0 : ns.attributes = null;
2278 0 : ns.source_reference = current.source_reference;
2279 : }
2280 :
2281 92 : current.metadata = ns_metadata;
2282 :
2283 46 : if (ns_metadata.has_argument (ArgumentType.CPREFIX)) {
2284 0 : cprefix = ns_metadata.get_string (ArgumentType.CPREFIX);
2285 : }
2286 :
2287 46 : if (ns_metadata.has_argument (ArgumentType.LOWER_CASE_CPREFIX)) {
2288 0 : lower_case_cprefix = ns_metadata.get_string (ArgumentType.LOWER_CASE_CPREFIX);
2289 46 : } else if (lower_case_cprefix != null) {
2290 46 : lower_case_cprefix += "_";
2291 : }
2292 :
2293 46 : ns.set_attribute_string ("CCode", "gir_namespace", gir_namespace);
2294 46 : ns.set_attribute_string ("CCode", "gir_version", gir_version);
2295 :
2296 46 : if (cprefix != null) {
2297 46 : ns.set_attribute_string ("CCode", "cprefix", cprefix);
2298 46 : if (lower_case_cprefix == null) {
2299 0 : ns.set_attribute_string ("CCode", "lower_case_cprefix", Symbol.camel_case_to_lower_case (cprefix) + "_");
2300 : }
2301 : }
2302 :
2303 46 : if (lower_case_cprefix != null) {
2304 46 : ns.set_attribute_string ("CCode", "lower_case_cprefix", lower_case_cprefix);
2305 : }
2306 :
2307 46 : if (cheader_filenames != null) {
2308 46 : ns.set_attribute_string ("CCode", "cheader_filename", string.joinv (",", cheader_filenames));
2309 : }
2310 :
2311 46 : next ();
2312 216 : while (current_token == MarkupTokenType.START_ELEMENT) {
2313 170 : if (!push_metadata ()) {
2314 6 : skip_element ();
2315 6 : continue;
2316 : }
2317 :
2318 164 : if (reader.name == "alias") {
2319 5 : parse_alias ();
2320 159 : } else if (reader.name == "enumeration") {
2321 11 : if (metadata.has_argument (ArgumentType.ERRORDOMAIN)) {
2322 0 : if (metadata.get_bool (ArgumentType.ERRORDOMAIN)) {
2323 0 : parse_error_domain ();
2324 : } else {
2325 0 : parse_enumeration ();
2326 : }
2327 : } else {
2328 11 : if (reader.has_attribute ("glib:error-quark") || reader.has_attribute ("glib:error-domain")) {
2329 5 : parse_error_domain ();
2330 : } else {
2331 6 : parse_enumeration ();
2332 : }
2333 : }
2334 148 : } else if (reader.name == "bitfield") {
2335 4 : parse_bitfield ();
2336 144 : } else if (reader.name == "function") {
2337 37 : parse_method ("function");
2338 107 : } else if (reader.name == "function-macro") {
2339 0 : skip_element ();
2340 107 : } else if (reader.name == "callback") {
2341 8 : parse_callback ();
2342 99 : } else if (reader.name == "record") {
2343 55 : if (metadata.has_argument (ArgumentType.STRUCT)) {
2344 2 : if (metadata.get_bool (ArgumentType.STRUCT)) {
2345 1 : parse_record ();
2346 : } else {
2347 1 : parse_boxed ("record");
2348 : }
2349 53 : } else if (element_get_type_id () != null) {
2350 3 : parse_boxed ("record");
2351 50 : } else if (!reader.get_attribute ("name").has_suffix ("Private")) {
2352 35 : if (!reader.has_attribute ("glib:is-gtype-struct-for") && reader.get_attribute ("disguised") == "1") {
2353 0 : parse_boxed ("record");
2354 : } else {
2355 35 : parse_record ();
2356 : }
2357 : } else {
2358 15 : skip_element ();
2359 : }
2360 44 : } else if (reader.name == "class") {
2361 26 : parse_class ();
2362 18 : } else if (reader.name == "interface") {
2363 6 : parse_interface ();
2364 12 : } else if (reader.name == "glib:boxed") {
2365 0 : parse_boxed ("glib:boxed");
2366 12 : } else if (reader.name == "union") {
2367 1 : if (element_get_type_id () != null && !metadata.get_bool (ArgumentType.STRUCT)) {
2368 0 : parse_boxed ("union");
2369 : } else {
2370 1 : parse_union ();
2371 : }
2372 11 : } else if (reader.name == "constant") {
2373 11 : parse_constant ();
2374 0 : } else if (reader.name == "docsection") {
2375 0 : skip_element ();
2376 : } else {
2377 : // error
2378 0 : Report.error (get_current_src (), "unknown child element `%s' in `namespace'", reader.name);
2379 0 : skip_element ();
2380 : }
2381 :
2382 164 : pop_metadata ();
2383 : }
2384 46 : pop_node ();
2385 46 : end_element ("namespace");
2386 : }
2387 :
2388 5 : void parse_alias () {
2389 5 : start_element ("alias");
2390 5 : push_node (element_get_name (), true);
2391 : // not enough information, symbol will be created while processing the tree
2392 :
2393 5 : next ();
2394 :
2395 5 : if (current.comment == null) {
2396 5 : current.comment = parse_symbol_doc ();
2397 : } else {
2398 0 : parse_symbol_doc ();
2399 : }
2400 :
2401 5 : bool no_array_length = false;
2402 5 : bool array_null_terminated = false;
2403 5 : current.base_type = element_get_type (parse_type (null, null, true), true, ref no_array_length, ref array_null_terminated);
2404 :
2405 5 : if (metadata.has_argument (ArgumentType.BASE_TYPE)) {
2406 0 : current.base_type = parse_type_from_string (metadata.get_string (ArgumentType.BASE_TYPE), true, metadata.get_source_reference (ArgumentType.BASE_TYPE));
2407 : }
2408 :
2409 5 : pop_node ();
2410 5 : end_element ("alias");
2411 : }
2412 :
2413 33 : private void calculate_common_prefix (ref string? common_prefix, string cname) {
2414 33 : if (common_prefix == null) {
2415 30 : common_prefix = cname;
2416 84 : while (common_prefix.length > 0 && !common_prefix.has_suffix ("_")) {
2417 : // FIXME: could easily be made faster
2418 69 : common_prefix = common_prefix.substring (0, common_prefix.length - 1);
2419 : }
2420 : } else {
2421 18 : while (!cname.has_prefix (common_prefix)) {
2422 0 : common_prefix = common_prefix.substring (0, common_prefix.length - 1);
2423 : }
2424 : }
2425 33 : while (common_prefix.length > 0 && (!common_prefix.has_suffix ("_") ||
2426 33 : (cname.get_char (common_prefix.length).isdigit ()) && (cname.length - common_prefix.length) <= 1)) {
2427 : // enum values may not consist solely of digits
2428 0 : common_prefix = common_prefix.substring (0, common_prefix.length - 1);
2429 : }
2430 : }
2431 :
2432 456 : GirComment? parse_symbol_doc () {
2433 : GirComment? comment = null;
2434 :
2435 456 : while (current_token == MarkupTokenType.START_ELEMENT) {
2436 416 : unowned string reader_name = reader.name;
2437 :
2438 416 : if (reader_name == "doc") {
2439 0 : start_element ("doc");
2440 0 : next ();
2441 :
2442 :
2443 0 : if (current_token == MarkupTokenType.TEXT) {
2444 0 : comment = new GirComment (reader.content, current.source_reference);
2445 0 : next ();
2446 : }
2447 :
2448 0 : end_element ("doc");
2449 416 : } else if (reader_name == "doc-version" || reader_name == "doc-deprecated" || reader_name == "doc-stability") {
2450 0 : skip_element ();
2451 416 : } else if (reader_name == "source-position") {
2452 0 : skip_element ();
2453 416 : } else if (reader_name == "attribute") {
2454 0 : skip_element ();
2455 : } else {
2456 : break;
2457 : }
2458 : }
2459 :
2460 : return comment;
2461 : }
2462 :
2463 698 : Comment? parse_doc () {
2464 : Comment? comment = null;
2465 :
2466 700 : while (current_token == MarkupTokenType.START_ELEMENT) {
2467 700 : unowned string reader_name = reader.name;
2468 :
2469 700 : if (reader_name == "doc") {
2470 2 : start_element ("doc");
2471 2 : next ();
2472 :
2473 :
2474 2 : if (current_token == MarkupTokenType.TEXT) {
2475 2 : comment = new Comment (reader.content, current.source_reference);
2476 2 : next ();
2477 : }
2478 :
2479 2 : end_element ("doc");
2480 698 : } else if (reader_name == "doc-version" || reader_name == "doc-deprecated" || reader_name == "doc-stability") {
2481 0 : skip_element ();
2482 698 : } else if (reader_name == "source-position") {
2483 0 : skip_element ();
2484 698 : } else if (reader_name == "attribute") {
2485 0 : skip_element ();
2486 : } else {
2487 : break;
2488 : }
2489 : }
2490 :
2491 : return comment;
2492 : }
2493 :
2494 30 : void parse_enumeration (string element_name = "enumeration", bool error_domain = false) {
2495 15 : start_element (element_name);
2496 15 : push_node (element_get_name (), true);
2497 :
2498 : Symbol sym;
2499 15 : if (current.new_symbol) {
2500 15 : if (error_domain) {
2501 5 : sym = new ErrorDomain (current.name, current.source_reference);
2502 : } else {
2503 10 : var en = new Enum (current.name, current.source_reference);
2504 10 : if (element_name == "bitfield") {
2505 4 : en.set_attribute ("Flags", true);
2506 : }
2507 20 : sym = en;
2508 : }
2509 30 : current.symbol = sym;
2510 : } else {
2511 0 : sym = current.symbol;
2512 : }
2513 :
2514 15 : set_type_id_ccode (sym);
2515 :
2516 15 : sym.access = SymbolAccessibility.PUBLIC;
2517 :
2518 15 : string? common_prefix = null;
2519 15 : bool explicit_prefix = false;
2520 15 : if (metadata.has_argument (ArgumentType.CPREFIX)) {
2521 0 : sym.set_attribute_string ("CCode", "cprefix", metadata.get_string (ArgumentType.CPREFIX));
2522 0 : explicit_prefix = true;
2523 : }
2524 15 : bool has_member = false;
2525 :
2526 15 : next ();
2527 :
2528 15 : sym.comment = parse_symbol_doc ();
2529 :
2530 48 : while (current_token == MarkupTokenType.START_ELEMENT) {
2531 33 : if (!push_metadata ()) {
2532 0 : skip_element ();
2533 0 : continue;
2534 : }
2535 :
2536 33 : if (reader.name == "member") {
2537 33 : has_member = true;
2538 33 : if (error_domain) {
2539 11 : parse_error_member ();
2540 : } else {
2541 22 : parse_enumeration_member ();
2542 : }
2543 33 : if (!explicit_prefix) {
2544 33 : calculate_common_prefix (ref common_prefix, old_current.get_cname ());
2545 : }
2546 0 : } else if (reader.name == "function") {
2547 0 : parse_method ("function");
2548 0 : } else if (reader.name == "function-macro") {
2549 0 : skip_element ();
2550 : } else {
2551 : // error
2552 0 : Report.error (get_current_src (), "unknown child element `%s' in `%s'", reader.name, element_name);
2553 0 : skip_element ();
2554 : }
2555 :
2556 33 : pop_metadata ();
2557 : }
2558 :
2559 15 : if (!has_member) {
2560 0 : Report.error (get_current_src (), "%s `%s' has no members", element_name, current.name);
2561 : }
2562 :
2563 15 : if (common_prefix != null) {
2564 15 : sym.set_attribute_string ("CCode", "cprefix", common_prefix);
2565 : }
2566 :
2567 15 : pop_node ();
2568 15 : end_element (element_name);
2569 : }
2570 :
2571 5 : void parse_error_domain () {
2572 5 : parse_enumeration ("enumeration", true);
2573 : }
2574 :
2575 4 : void parse_bitfield () {
2576 4 : parse_enumeration ("bitfield");
2577 : }
2578 :
2579 44 : void parse_enumeration_member () {
2580 22 : start_element ("member");
2581 22 : push_node (element_get_name().ascii_up().replace ("-", "_"), false);
2582 :
2583 22 : var ev = new EnumValue (current.name, metadata.get_expression (ArgumentType.DEFAULT), current.source_reference);
2584 44 : current.symbol = ev;
2585 22 : next ();
2586 :
2587 22 : ev.comment = parse_symbol_doc ();
2588 :
2589 22 : pop_node ();
2590 22 : end_element ("member");
2591 : }
2592 :
2593 22 : void parse_error_member () {
2594 11 : start_element ("member");
2595 11 : push_node (element_get_name().ascii_up().replace ("-", "_"), false);
2596 :
2597 : ErrorCode ec;
2598 11 : string value = reader.get_attribute ("value");
2599 11 : if (value != null) {
2600 11 : ec = new ErrorCode.with_value (current.name, new IntegerLiteral (value));
2601 : } else {
2602 0 : ec = new ErrorCode (current.name);
2603 : }
2604 22 : current.symbol = ec;
2605 11 : next ();
2606 :
2607 11 : ec.comment = parse_symbol_doc ();
2608 :
2609 11 : pop_node ();
2610 11 : end_element ("member");
2611 : }
2612 :
2613 240 : 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) {
2614 240 : start_element ("return-value");
2615 :
2616 240 : string transfer = reader.get_attribute ("transfer-ownership");
2617 240 : string nullable = reader.get_attribute ("nullable");
2618 240 : string allow_none = reader.get_attribute ("allow-none");
2619 240 : next ();
2620 :
2621 240 : comment = parse_doc ();
2622 :
2623 240 : var transfer_elements = transfer != "container";
2624 240 : var type = parse_type (out ctype, out array_length_idx, transfer_elements, out no_array_length, out array_null_terminated);
2625 240 : if (transfer == "full" || transfer == "container") {
2626 156 : type.value_owned = true;
2627 : }
2628 240 : if (nullable == "1" || allow_none == "1") {
2629 2 : type.nullable = true;
2630 : }
2631 240 : type = element_get_type (type, true, ref no_array_length, ref array_null_terminated);
2632 :
2633 240 : end_element ("return-value");
2634 240 : return type;
2635 : }
2636 :
2637 458 : Parameter parse_parameter (out bool caller_allocates, 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) {
2638 458 : var begin = this.begin;
2639 : Parameter param;
2640 :
2641 458 : array_length_idx = -1;
2642 458 : closure_idx = -1;
2643 458 : destroy_idx = -1;
2644 :
2645 458 : string element_type = reader.name;
2646 458 : if (current_token != MarkupTokenType.START_ELEMENT || (element_type != "parameter" && element_type != "instance-parameter")) {
2647 0 : Report.error (get_current_src (), "expected start element of `parameter' or `instance-parameter'");
2648 : }
2649 458 : start_element (element_type);
2650 458 : var name = metadata.get_string (ArgumentType.NAME);
2651 458 : if (name == null) {
2652 458 : name = reader.get_attribute ("name");
2653 : }
2654 458 : if (name == null) {
2655 0 : name = default_name;
2656 458 : } else if (name.contains ("-")) {
2657 0 : Report.warning (get_current_src (), "parameter name contains hyphen");
2658 0 : name = name.replace ("-", "_");
2659 : }
2660 458 : string direction = null;
2661 458 : if (metadata.has_argument (ArgumentType.OUT)) {
2662 0 : if (metadata.get_bool (ArgumentType.OUT)) {
2663 0 : direction = "out";
2664 : } // null otherwise
2665 458 : } else if (metadata.has_argument (ArgumentType.REF)) {
2666 0 : if (metadata.get_bool (ArgumentType.REF)) {
2667 0 : direction = "inout";
2668 : } // null otherwise
2669 : } else {
2670 458 : direction = reader.get_attribute ("direction");
2671 : }
2672 458 : string transfer = reader.get_attribute ("transfer-ownership");
2673 458 : string nullable = reader.get_attribute ("nullable");
2674 458 : string allow_none = reader.get_attribute ("allow-none");
2675 :
2676 458 : caller_allocates = reader.get_attribute ("caller-allocates") == "1";
2677 458 : scope = element_get_string ("scope", ArgumentType.SCOPE);
2678 :
2679 458 : string closure = reader.get_attribute ("closure");
2680 458 : string destroy = reader.get_attribute ("destroy");
2681 458 : if (closure != null && &closure_idx != null) {
2682 43 : closure_idx = int.parse (closure);
2683 : }
2684 458 : if (destroy != null && &destroy_idx != null) {
2685 16 : destroy_idx = int.parse (destroy);
2686 : }
2687 458 : if (metadata.has_argument (ArgumentType.CLOSURE)) {
2688 0 : closure_idx = metadata.get_integer (ArgumentType.CLOSURE);
2689 : }
2690 458 : if (metadata.has_argument (ArgumentType.DESTROY)) {
2691 0 : destroy_idx = metadata.get_integer (ArgumentType.DESTROY);
2692 : }
2693 :
2694 458 : next ();
2695 :
2696 458 : comment = parse_doc ();
2697 :
2698 914 : if (reader.name == "varargs") {
2699 2 : start_element ("varargs");
2700 2 : next ();
2701 2 : param = new Parameter.with_ellipsis (get_src (begin));
2702 2 : end_element ("varargs");
2703 : } else {
2704 : string ctype;
2705 : bool no_array_length;
2706 : bool array_null_terminated;
2707 456 : var type = parse_type (out ctype, out array_length_idx, transfer != "container", out no_array_length, out array_null_terminated);
2708 456 : if (transfer == "full" || transfer == "container" || destroy != null) {
2709 54 : type.value_owned = true;
2710 : }
2711 456 : if (nullable == "1" || (allow_none == "1" && direction != "out")) {
2712 72 : type.nullable = true;
2713 : }
2714 :
2715 : bool changed;
2716 456 : type = element_get_type (type, direction == "out" || direction == "inout", ref no_array_length, ref array_null_terminated, out changed);
2717 456 : if (!changed) {
2718 456 : if (metadata.has_argument (ArgumentType.CTYPE)) {
2719 0 : ctype = metadata.get_string (ArgumentType.CTYPE);
2720 : } else {
2721 : // discard ctype, duplicated information
2722 456 : ctype = null;
2723 : }
2724 : }
2725 :
2726 456 : param = new Parameter (name, type, get_src (begin));
2727 456 : if (ctype != null) {
2728 0 : param.set_attribute_string ("CCode", "type", ctype);
2729 : }
2730 456 : if (direction == "out") {
2731 53 : param.direction = ParameterDirection.OUT;
2732 403 : } else if (direction == "inout") {
2733 8 : param.direction = ParameterDirection.REF;
2734 : }
2735 456 : if (type is DelegateType && metadata.has_argument (ArgumentType.DELEGATE_TARGET)) {
2736 0 : param.set_attribute_bool ("CCode", "delegate_target", metadata.get_bool (ArgumentType.DELEGATE_TARGET));
2737 : }
2738 456 : if (type is ArrayType) {
2739 23 : if (metadata.has_argument (ArgumentType.ARRAY_LENGTH_IDX)) {
2740 0 : array_length_idx = metadata.get_integer (ArgumentType.ARRAY_LENGTH_IDX);
2741 : } else {
2742 23 : if (no_array_length || array_null_terminated) {
2743 3 : param.set_attribute_bool ("CCode", "array_length", !no_array_length);
2744 : }
2745 23 : if (array_null_terminated) {
2746 0 : param.set_attribute_bool ("CCode", "array_null_terminated", array_null_terminated);
2747 : }
2748 : }
2749 : }
2750 456 : param.initializer = metadata.get_expression (ArgumentType.DEFAULT);
2751 :
2752 : // empty tuple used for parameters without initializer
2753 456 : if (param.initializer is Tuple) {
2754 0 : param.initializer = null;
2755 : }
2756 : }
2757 458 : end_element (element_type);
2758 458 : return param;
2759 : }
2760 :
2761 840 : 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) {
2762 840 : bool is_array = false;
2763 840 : string type_name = reader.get_attribute ("name");
2764 840 : ctype = null;
2765 :
2766 840 : var fixed_length = -1;
2767 840 : array_length_idx = -1;
2768 840 : no_array_length = true;
2769 840 : array_null_terminated = true;
2770 :
2771 841 : if (reader.name == "array") {
2772 40 : is_array = true;
2773 40 : start_element ("array");
2774 :
2775 40 : var src = get_current_src ();
2776 :
2777 40 : if (type_name == null) {
2778 39 : if (reader.has_attribute ("length")) {
2779 31 : array_length_idx = int.parse (reader.get_attribute ("length"));
2780 31 : no_array_length = false;
2781 31 : array_null_terminated = false;
2782 : }
2783 39 : if (reader.has_attribute ("fixed-size")) {
2784 6 : fixed_length = int.parse (reader.get_attribute ("fixed-size"));
2785 6 : array_null_terminated = false;
2786 : }
2787 39 : if (reader.get_attribute ("c:type") == "GStrv") {
2788 0 : no_array_length = true;
2789 0 : array_null_terminated = true;
2790 : }
2791 39 : if (reader.has_attribute ("zero-terminated")) {
2792 8 : array_null_terminated = int.parse (reader.get_attribute ("zero-terminated")) != 0;
2793 : }
2794 39 : next ();
2795 39 : var element_type = parse_type ();
2796 39 : element_type.value_owned = transfer_elements;
2797 39 : end_element ("array");
2798 :
2799 39 : var array_type = new ArrayType (element_type, 1, src);
2800 39 : if (fixed_length > 0) {
2801 6 : array_type.fixed_length = true;
2802 6 : array_type.length = new IntegerLiteral (fixed_length.to_string ());
2803 : }
2804 39 : return array_type;
2805 : }
2806 800 : } else if (reader.name == "callback"){
2807 35 : parse_callback ();
2808 35 : return new DelegateType ((Delegate) old_current.symbol);
2809 : } else {
2810 765 : start_element ("type");
2811 : }
2812 :
2813 766 : if (metadata.has_argument (ArgumentType.CTYPE)) {
2814 0 : ctype = metadata.get_string (ArgumentType.CTYPE);
2815 : } else {
2816 766 : ctype = reader.get_attribute("c:type");
2817 : }
2818 :
2819 766 : next ();
2820 :
2821 766 : if (type_name == null) {
2822 0 : type_name = ctype;
2823 : }
2824 :
2825 : DataType type;
2826 766 : if (type_name != null) {
2827 766 : type = parse_type_from_gir_name (type_name, out no_array_length, out array_null_terminated, ctype);
2828 : } else {
2829 : // empty <type/>
2830 0 : no_array_length = false;
2831 0 : array_null_terminated = false;
2832 0 : type = new InvalidType ();
2833 0 : Report.error (get_current_src (), "empty type element");
2834 : }
2835 :
2836 : // type arguments / element types
2837 788 : while (current_token == MarkupTokenType.START_ELEMENT) {
2838 11 : if (type_name == "GLib.ByteArray") {
2839 0 : skip_element ();
2840 0 : continue;
2841 : }
2842 11 : var element_type = parse_type ();
2843 11 : element_type.value_owned = transfer_elements;
2844 11 : type.add_type_argument (element_type);
2845 :
2846 12 : if (element_type is UnresolvedType) {
2847 1 : Node parent = current ?? root;
2848 3 : while (parent != root && parent.parent != null && parent.parent != root) {
2849 2 : parent = parent.parent;
2850 : }
2851 1 : unresolved_type_arguments[(UnresolvedType) element_type] = parent;
2852 : }
2853 : }
2854 :
2855 766 : end_element (is_array ? "array" : "type");
2856 766 : return type;
2857 : }
2858 :
2859 794 : DataType parse_type_from_gir_name (string type_name, out bool no_array_length = null, out bool array_null_terminated = null, string? ctype = null) {
2860 794 : no_array_length = false;
2861 794 : array_null_terminated = false;
2862 :
2863 794 : DataType? type = null;
2864 794 : if (type_name == "none") {
2865 157 : type = new VoidType (get_current_src ());
2866 637 : } else if (type_name == "gpointer") {
2867 61 : type = new PointerType (new VoidType (get_current_src ()), get_current_src ());
2868 576 : } else if (type_name == "GObject.Strv") {
2869 0 : var element_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, "string"));
2870 0 : element_type.value_owned = true;
2871 0 : type = new ArrayType (element_type, 1, get_current_src ());
2872 0 : no_array_length = true;
2873 0 : array_null_terminated = true;
2874 : } else {
2875 576 : bool known_type = true;
2876 576 : if (type_name == "utf8") {
2877 40 : if (ctype == null || ctype.has_suffix ("*") || ctype == "gpointer" || ctype == "gconstpointer") {
2878 : type_name = "string";
2879 : } else {
2880 : //FIXME Work around a g-ir-scanner bug
2881 2 : type_name = "char";
2882 : }
2883 536 : } else if (type_name == "gboolean") {
2884 7 : type = new BooleanType ((Struct) context.root.scope.lookup ("bool"));
2885 529 : } else if (type_name == "gchar") {
2886 : type_name = "char";
2887 529 : } else if (type_name == "gshort") {
2888 : type_name = "short";
2889 529 : } else if (type_name == "gushort") {
2890 : type_name = "ushort";
2891 529 : } else if (type_name == "gint") {
2892 111 : if (ctype != null && ctype.has_prefix ("dev_t")) {
2893 : type_name = "dev_t";
2894 109 : } else if (ctype != null && ctype.has_prefix ("pid_t")) {
2895 : type_name = "pid_t";
2896 : } else {
2897 : type_name = "int";
2898 : }
2899 418 : } else if (type_name == "guint") {
2900 10 : if (ctype != null && ctype.has_prefix ("gid_t")) {
2901 : type_name = "gid_t";
2902 8 : } else if (ctype != null && ctype.has_prefix ("uid_t")) {
2903 : type_name = "uid_t";
2904 : } else {
2905 : type_name = "uint";
2906 : }
2907 408 : } else if (type_name == "glong") {
2908 2 : if (ctype != null && ctype.has_prefix ("gssize")) {
2909 : type_name = "ssize_t";
2910 2 : } else if (ctype != null && ctype.has_prefix ("gintptr")) {
2911 : type_name = "intptr";
2912 2 : } else if (ctype != null && ctype.has_prefix ("time_t")) {
2913 : type_name = "time_t";
2914 : } else {
2915 : type_name = "long";
2916 : }
2917 406 : } else if (type_name == "gulong") {
2918 3 : if (ctype != null && ctype.has_prefix ("gsize")) {
2919 : type_name = "size_t";
2920 0 : } else if (ctype != null && ctype.has_prefix ("guintptr")) {
2921 : type_name = "uintptr";
2922 : } else {
2923 : type_name = "ulong";
2924 : }
2925 403 : } else if (type_name == "gint8") {
2926 : type_name = "int8";
2927 379 : } else if (type_name == "guint8") {
2928 : type_name = "uint8";
2929 374 : } else if (type_name == "gint16") {
2930 : type_name = "int16";
2931 374 : } else if (type_name == "guint16") {
2932 : type_name = "uint16";
2933 374 : } else if (type_name == "gint32") {
2934 2 : if (ctype != null && ctype.has_prefix ("socklen_t")) {
2935 : type_name = "socklen_t";
2936 : } else {
2937 : type_name = "int32";
2938 : }
2939 372 : } else if (type_name == "guint32") {
2940 : type_name = "uint32";
2941 372 : } else if (type_name == "gint64") {
2942 : type_name = "int64";
2943 372 : } else if (type_name == "guint64") {
2944 : type_name = "uint64";
2945 372 : } else if (type_name == "gfloat") {
2946 : type_name = "float";
2947 371 : } else if (type_name == "gdouble") {
2948 : type_name = "double";
2949 370 : } else if (type_name == "filename") {
2950 : type_name = "string";
2951 370 : } else if (type_name == "GLib.offset") {
2952 : type_name = "int64";
2953 370 : } else if (type_name == "gsize") {
2954 7 : if (ctype != null && ctype.has_prefix ("off_t")) {
2955 : type_name = "off_t";
2956 : } else {
2957 : type_name = "size_t";
2958 : }
2959 363 : } else if (type_name == "gssize") {
2960 : type_name = "ssize_t";
2961 363 : } else if (type_name == "guintptr") {
2962 : type_name = "uintptr";
2963 363 : } else if (type_name == "gintptr") {
2964 : type_name = "intptr";
2965 363 : } else if (type_name == "GType") {
2966 : type_name = "GLib.Type";
2967 352 : } else if (type_name == "GObject.Class") {
2968 : type_name = "GLib.ObjectClass";
2969 352 : } else if (type_name == "gunichar") {
2970 : type_name = "unichar";
2971 352 : } else if (type_name == "Atk.ImplementorIface") {
2972 : type_name = "Atk.Implementor";
2973 : } else {
2974 352 : known_type = false;
2975 : }
2976 :
2977 1145 : if (type == null) {
2978 569 : var sym = parse_symbol_from_string (type_name, get_current_src ());
2979 569 : type = new UnresolvedType.from_symbol (sym, get_current_src ());
2980 569 : if (!known_type) {
2981 352 : unresolved_gir_symbols.add (sym);
2982 : }
2983 : }
2984 : }
2985 :
2986 794 : return type;
2987 : }
2988 :
2989 72 : void parse_record () {
2990 36 : start_element ("record");
2991 36 : push_node (element_get_name (), true);
2992 :
2993 : Struct st;
2994 36 : bool require_copy_free = false;
2995 36 : if (current.new_symbol) {
2996 36 : st = new Struct (element_get_name (), current.source_reference);
2997 72 : current.symbol = st;
2998 : } else {
2999 0 : st = (Struct) current.symbol;
3000 : }
3001 :
3002 36 : set_type_id_ccode (st);
3003 36 : require_copy_free = st.has_attribute_argument ("CCode", "type_id");
3004 :
3005 36 : st.access = SymbolAccessibility.PUBLIC;
3006 :
3007 36 : var gtype_struct_for = reader.get_attribute ("glib:is-gtype-struct-for");
3008 36 : if (gtype_struct_for != null) {
3009 31 : current.gtype_struct_for = parse_symbol_from_string (gtype_struct_for, current.source_reference);
3010 31 : unresolved_gir_symbols.add (current.gtype_struct_for);
3011 : }
3012 36 : if (metadata.has_argument (ArgumentType.TYPE_PARAMETERS)) {
3013 0 : parse_type_parameters_from_string (st, metadata.get_string (ArgumentType.TYPE_PARAMETERS), metadata.get_source_reference (ArgumentType.TYPE_PARAMETERS));
3014 : }
3015 :
3016 36 : bool first_field = true;
3017 36 : next ();
3018 :
3019 36 : st.comment = parse_symbol_doc ();
3020 :
3021 122 : while (current_token == MarkupTokenType.START_ELEMENT) {
3022 86 : if (!push_metadata ()) {
3023 24 : if (first_field && reader.name == "field") {
3024 24 : first_field = false;
3025 : }
3026 24 : skip_element ();
3027 24 : continue;
3028 : }
3029 :
3030 62 : if (reader.name == "field") {
3031 49 : if (reader.get_attribute ("name") != "priv" && !(first_field && gtype_struct_for != null)) {
3032 42 : parse_field ();
3033 : } else {
3034 7 : skip_element ();
3035 : }
3036 : first_field = false;
3037 13 : } else if (reader.name == "constructor") {
3038 1 : parse_constructor ();
3039 12 : } else if (reader.name == "method") {
3040 11 : parse_method ("method");
3041 1 : } else if (reader.name == "function") {
3042 0 : parse_method ("function");
3043 1 : } else if (reader.name == "function-macro") {
3044 0 : skip_element ();
3045 1 : } else if (reader.name == "union") {
3046 1 : parse_union ();
3047 : } else {
3048 : // error
3049 0 : Report.error (get_current_src (), "unknown child element `%s' in `record'", reader.name);
3050 0 : skip_element ();
3051 : }
3052 :
3053 62 : pop_metadata ();
3054 : }
3055 :
3056 : // Add default g_boxed_copy/free ccode-attributes
3057 36 : if (require_copy_free) {
3058 1 : st.set_attribute_string ("CCode", "copy_function", "g_boxed_copy");
3059 1 : st.set_attribute_string ("CCode", "free_function", "g_boxed_free");
3060 : }
3061 :
3062 36 : pop_node ();
3063 36 : end_element ("record");
3064 : }
3065 :
3066 52 : void parse_class () {
3067 26 : start_element ("class");
3068 26 : push_node (element_get_name (), true);
3069 :
3070 : Class cl;
3071 26 : var parent = reader.get_attribute ("parent");
3072 26 : if (current.new_symbol) {
3073 26 : cl = new Class (current.name, current.source_reference);
3074 26 : cl.is_abstract = metadata.get_bool (ArgumentType.ABSTRACT, reader.get_attribute ("abstract") == "1");
3075 26 : cl.is_sealed = metadata.get_bool (ArgumentType.SEALED, reader.get_attribute ("final") == "1");
3076 26 : if (metadata.has_argument (ArgumentType.TYPE_GET_FUNCTION)) {
3077 0 : cl.set_attribute_string ("CCode", "type_get_function", metadata.get_string (ArgumentType.TYPE_GET_FUNCTION));
3078 : }
3079 :
3080 26 : if (parent != null) {
3081 21 : cl.add_base_type (parse_type_from_gir_name (parent));
3082 : }
3083 26 : var type_struct = reader.get_attribute ("glib:type-struct");
3084 26 : if (type_struct != null) {
3085 26 : current.type_struct = parse_symbol_from_string (type_struct, current.source_reference);
3086 26 : unresolved_gir_symbols.add (current.type_struct);
3087 : }
3088 52 : current.symbol = cl;
3089 : } else {
3090 0 : cl = (Class) current.symbol;
3091 : }
3092 :
3093 26 : set_type_id_ccode (cl);
3094 :
3095 26 : cl.access = SymbolAccessibility.PUBLIC;
3096 :
3097 26 : if (metadata.has_argument (ArgumentType.REF_FUNCTION)) {
3098 0 : cl.set_attribute_string ("CCode", "ref_function", metadata.get_string (ArgumentType.REF_FUNCTION));
3099 26 : } else if (reader.has_attribute ("glib:ref-func")) {
3100 5 : cl.set_attribute_string ("CCode", "ref_function", reader.get_attribute ("glib:ref-func"));
3101 : }
3102 26 : if (metadata.has_argument (ArgumentType.REF_SINK_FUNCTION)) {
3103 0 : cl.set_attribute_string ("CCode", "ref_sink_function", metadata.get_string (ArgumentType.REF_SINK_FUNCTION));
3104 : }
3105 26 : if (metadata.has_argument (ArgumentType.UNREF_FUNCTION)) {
3106 0 : cl.set_attribute_string ("CCode", "unref_function", metadata.get_string (ArgumentType.UNREF_FUNCTION));
3107 26 : } else if (reader.has_attribute ("glib:unref-func")) {
3108 5 : cl.set_attribute_string ("CCode", "unref_function", reader.get_attribute ("glib:unref-func"));
3109 : }
3110 26 : if (metadata.has_argument (ArgumentType.TYPE_PARAMETERS)) {
3111 0 : parse_type_parameters_from_string (cl, metadata.get_string (ArgumentType.TYPE_PARAMETERS), metadata.get_source_reference (ArgumentType.TYPE_PARAMETERS));
3112 : }
3113 26 : if (metadata.has_argument (ArgumentType.IMPLEMENTS)) {
3114 0 : current.inherited_types = parse_list_of_types_from_string (metadata.get_string (ArgumentType.IMPLEMENTS), metadata.get_source_reference (ArgumentType.IMPLEMENTS));
3115 : }
3116 :
3117 26 : next ();
3118 :
3119 26 : cl.comment = parse_symbol_doc ();
3120 :
3121 : var first_field = true;
3122 222 : while (current_token == MarkupTokenType.START_ELEMENT) {
3123 196 : if (!push_metadata ()) {
3124 33 : if (first_field && reader.name == "field") {
3125 33 : first_field = false;
3126 : }
3127 33 : skip_element ();
3128 33 : continue;
3129 : }
3130 :
3131 163 : if (reader.name == "implements") {
3132 3 : start_element ("implements");
3133 3 : cl.add_base_type (parse_type_from_gir_name (reader.get_attribute ("name")));
3134 3 : next ();
3135 3 : end_element ("implements");
3136 160 : } else if (reader.name == "constant") {
3137 0 : parse_constant ();
3138 160 : } else if (reader.name == "field") {
3139 26 : if (first_field && parent != null) {
3140 : // first field is guaranteed to be the parent instance
3141 13 : skip_element ();
3142 : } else {
3143 13 : if (reader.get_attribute ("name") != "priv") {
3144 13 : parse_field ();
3145 : } else {
3146 0 : skip_element ();
3147 : }
3148 : }
3149 : first_field = false;
3150 134 : } else if (reader.name == "property") {
3151 14 : parse_property ();
3152 120 : } else if (reader.name == "constructor") {
3153 21 : parse_constructor ();
3154 99 : } else if (reader.name == "function") {
3155 8 : parse_method ("function");
3156 91 : } else if (reader.name == "function-macro") {
3157 0 : skip_element ();
3158 91 : } else if (reader.name == "method") {
3159 62 : parse_method ("method");
3160 29 : } else if (reader.name == "virtual-method") {
3161 25 : parse_method ("virtual-method");
3162 4 : } else if (reader.name == "union") {
3163 0 : parse_union ();
3164 4 : } else if (reader.name == "glib:signal") {
3165 4 : parse_signal ();
3166 : } else {
3167 : // error
3168 0 : Report.error (get_current_src (), "unknown child element `%s' in `class'", reader.name);
3169 0 : skip_element ();
3170 : }
3171 :
3172 163 : pop_metadata ();
3173 : }
3174 :
3175 : // There is no instance field therefore this type might be final/sealed
3176 26 : if (first_field && !cl.is_abstract && !(cl.is_opaque || cl.is_sealed)) {
3177 0 : if (!cl.is_compact
3178 0 : && !metadata.has_argument (ArgumentType.ABSTRACT)
3179 0 : && !metadata.has_argument (ArgumentType.COMPACT)
3180 0 : && !metadata.has_argument (ArgumentType.SEALED)) {
3181 0 : cl.is_sealed = true;
3182 : }
3183 : }
3184 :
3185 26 : pop_node ();
3186 26 : end_element ("class");
3187 : }
3188 :
3189 12 : void parse_interface () {
3190 6 : start_element ("interface");
3191 6 : push_node (element_get_name (), true);
3192 :
3193 : Interface iface;
3194 6 : if (current.new_symbol) {
3195 6 : iface = new Interface (current.name, current.source_reference);
3196 6 : if (metadata.has_argument (ArgumentType.TYPE_GET_FUNCTION)){
3197 0 : iface.set_attribute_string ("CCode", "type_get_function", metadata.get_string (ArgumentType.TYPE_GET_FUNCTION));
3198 : }
3199 :
3200 12 : current.symbol = iface;
3201 : } else {
3202 0 : iface = (Interface) current.symbol;
3203 : }
3204 :
3205 6 : set_type_id_ccode (iface);
3206 :
3207 6 : iface.access = SymbolAccessibility.PUBLIC;
3208 :
3209 6 : if (metadata.has_argument (ArgumentType.TYPE_PARAMETERS)) {
3210 0 : parse_type_parameters_from_string (iface, metadata.get_string (ArgumentType.TYPE_PARAMETERS), metadata.get_source_reference (ArgumentType.TYPE_PARAMETERS));
3211 : }
3212 6 : if (metadata.has_argument (ArgumentType.PREREQUISITES)) {
3213 0 : current.inherited_types = parse_list_of_types_from_string (metadata.get_string (ArgumentType.PREREQUISITES), metadata.get_source_reference (ArgumentType.PREREQUISITES));
3214 : }
3215 :
3216 6 : next ();
3217 :
3218 6 : iface.comment = parse_symbol_doc ();
3219 :
3220 42 : while (current_token == MarkupTokenType.START_ELEMENT) {
3221 36 : if (!push_metadata ()) {
3222 6 : skip_element ();
3223 6 : continue;
3224 : }
3225 :
3226 30 : if (reader.name == "prerequisite") {
3227 4 : start_element ("prerequisite");
3228 4 : iface.add_prerequisite (parse_type_from_gir_name (reader.get_attribute ("name")));
3229 4 : next ();
3230 4 : end_element ("prerequisite");
3231 26 : } else if (reader.name == "field") {
3232 0 : parse_field ();
3233 26 : } else if (reader.name == "property") {
3234 2 : parse_property ();
3235 24 : } else if (reader.name == "virtual-method") {
3236 11 : parse_method ("virtual-method");
3237 13 : } else if (reader.name == "function") {
3238 1 : parse_method ("function");
3239 12 : } else if (reader.name == "function-macro") {
3240 0 : skip_element ();
3241 12 : } else if (reader.name == "method") {
3242 11 : parse_method ("method");
3243 1 : } else if (reader.name == "glib:signal") {
3244 1 : parse_signal ();
3245 : } else {
3246 : // error
3247 0 : Report.error (get_current_src (), "unknown child element `%s' in `interface'", reader.name);
3248 0 : skip_element ();
3249 : }
3250 :
3251 30 : pop_metadata ();
3252 : }
3253 :
3254 6 : pop_node ();
3255 6 : end_element ("interface");
3256 : }
3257 :
3258 124 : void parse_field () {
3259 62 : start_element ("field");
3260 62 : push_node (element_get_name (), false);
3261 :
3262 62 : string nullable = reader.get_attribute ("nullable");
3263 62 : string allow_none = reader.get_attribute ("allow-none");
3264 62 : next ();
3265 :
3266 62 : var comment = parse_symbol_doc ();
3267 :
3268 : bool no_array_length;
3269 : bool array_null_terminated;
3270 : int array_length_idx;
3271 62 : var type = parse_type (null, out array_length_idx, true, out no_array_length, out array_null_terminated);
3272 62 : type = element_get_type (type, true, ref no_array_length, ref array_null_terminated);
3273 :
3274 62 : string name = current.name;
3275 62 : string cname = current.girdata["name"];
3276 :
3277 62 : var field = new Field (name, type, null, current.source_reference);
3278 62 : field.access = SymbolAccessibility.PUBLIC;
3279 62 : field.comment = comment;
3280 62 : if (name != cname) {
3281 0 : field.set_attribute_string ("CCode", "cname", cname);
3282 : }
3283 62 : if (type is ArrayType) {
3284 3 : if (!no_array_length && array_length_idx > -1) {
3285 0 : current.array_length_idx = array_length_idx;
3286 : }
3287 3 : if (no_array_length || array_null_terminated) {
3288 3 : field.set_attribute_bool ("CCode", "array_length", !no_array_length);
3289 : }
3290 3 : if (array_null_terminated) {
3291 1 : field.set_attribute_bool ("CCode", "array_null_terminated", true);
3292 : }
3293 : }
3294 62 : if (nullable == "1" || allow_none == "1") {
3295 1 : type.nullable = true;
3296 : }
3297 124 : current.symbol = field;
3298 :
3299 62 : pop_node ();
3300 62 : end_element ("field");
3301 : }
3302 :
3303 16 : Property parse_property () {
3304 16 : start_element ("property");
3305 16 : push_node (element_get_name().replace ("-", "_"), false);
3306 16 : bool is_abstract = metadata.get_bool (ArgumentType.ABSTRACT, current.parent.symbol is Interface);
3307 16 : string transfer = reader.get_attribute ("transfer-ownership");
3308 :
3309 16 : next ();
3310 :
3311 16 : var comment = parse_symbol_doc ();
3312 :
3313 : bool no_array_length;
3314 : bool array_null_terminated;
3315 16 : var type = parse_type (null, null, transfer != "container", out no_array_length, out array_null_terminated);
3316 16 : type = element_get_type (type, true, ref no_array_length, ref array_null_terminated);
3317 16 : var prop = new Property (current.name, type, null, null, current.source_reference);
3318 16 : prop.comment = comment;
3319 16 : prop.access = SymbolAccessibility.PUBLIC;
3320 16 : prop.is_abstract = is_abstract;
3321 16 : if (no_array_length || array_null_terminated) {
3322 0 : prop.set_attribute_bool ("CCode", "array_length", !no_array_length);
3323 : }
3324 16 : if (array_null_terminated) {
3325 0 : prop.set_attribute_bool ("CCode", "array_null_terminated", true);
3326 : }
3327 32 : current.symbol = prop;
3328 :
3329 16 : pop_node ();
3330 16 : end_element ("property");
3331 16 : return prop;
3332 : }
3333 :
3334 43 : void parse_callback () {
3335 43 : parse_function ("callback");
3336 : }
3337 :
3338 24 : void parse_constructor () {
3339 24 : parse_function ("constructor");
3340 : }
3341 :
3342 2902 : class ParameterInfo {
3343 700 : public ParameterInfo (Parameter param, int array_length_idx, int closure_idx, int destroy_idx, bool is_async = false) {
3344 350 : this.param = param;
3345 350 : this.array_length_idx = array_length_idx;
3346 350 : this.closure_idx = closure_idx;
3347 350 : this.destroy_idx = destroy_idx;
3348 350 : this.vala_idx = 0.0F;
3349 350 : this.keep = true;
3350 350 : this.is_async = is_async;
3351 : }
3352 :
3353 350 : public Parameter param;
3354 : public float vala_idx;
3355 : public int array_length_idx;
3356 : public int closure_idx;
3357 : public int destroy_idx;
3358 : public bool keep;
3359 : public bool is_async;
3360 : public bool is_async_result;
3361 : public bool is_error;
3362 : public bool caller_allocates;
3363 : }
3364 :
3365 480 : void parse_function (string element_name) {
3366 240 : start_element (element_name);
3367 240 : push_node (element_get_name (reader.get_attribute ("invoker")).replace ("-", "_"), false);
3368 :
3369 : string symbol_type;
3370 240 : if (metadata.has_argument (ArgumentType.SYMBOL_TYPE)) {
3371 0 : symbol_type = metadata.get_string (ArgumentType.SYMBOL_TYPE);
3372 : } else {
3373 480 : symbol_type = element_name;
3374 : }
3375 :
3376 240 : string? ctype = null;
3377 240 : if (metadata.has_argument (ArgumentType.CTYPE)) {
3378 0 : ctype = metadata.get_string (ArgumentType.CTYPE);
3379 : }
3380 :
3381 240 : string name = current.name;
3382 240 : string throws_string = reader.get_attribute ("throws");
3383 240 : string invoker = reader.get_attribute ("invoker");
3384 240 : current.deprecated_replacement = reader.get_attribute ("moved-to");
3385 :
3386 240 : next ();
3387 :
3388 240 : var comment = parse_symbol_doc ();
3389 :
3390 : DataType return_type;
3391 240 : string return_ctype = null;
3392 240 : int return_array_length_idx = -1;
3393 240 : bool return_no_array_length = false;
3394 240 : bool return_array_null_terminated = false;
3395 240 : if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "return-value") {
3396 : Comment? return_comment;
3397 240 : 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);
3398 240 : if (return_comment != null) {
3399 0 : if (comment == null) {
3400 0 : comment = new GirComment (null, current.source_reference);
3401 : }
3402 0 : comment.return_content = return_comment;
3403 : }
3404 : } else {
3405 0 : return_type = new VoidType ();
3406 : }
3407 :
3408 : Symbol s;
3409 :
3410 240 : if (symbol_type == "callback") {
3411 43 : s = new Delegate (name, return_type, current.source_reference);
3412 43 : ((Delegate) s).has_target = false;
3413 43 : if (metadata.has_argument (ArgumentType.TYPE_PARAMETERS)) {
3414 0 : parse_type_parameters_from_string ((Delegate) s, metadata.get_string (ArgumentType.TYPE_PARAMETERS), metadata.get_source_reference (ArgumentType.TYPE_PARAMETERS));
3415 : }
3416 221 : } else if (symbol_type == "constructor") {
3417 24 : if (name == "new") {
3418 17 : name = null;
3419 7 : } else if (name.has_prefix ("new_")) {
3420 2 : name = name.substring ("new_".length);
3421 : }
3422 24 : var m = new CreationMethod (null, name, current.source_reference);
3423 24 : m.has_construct_function = false;
3424 :
3425 24 : if (name != null && !current.name.has_prefix ("new_")) {
3426 5 : m.set_attribute_string ("CCode", "cname", current.girdata["c:identifier"]);
3427 : }
3428 :
3429 24 : string parent_ctype = null;
3430 24 : if (current.parent.symbol is Class) {
3431 23 : parent_ctype = current.parent.get_cname ();
3432 : }
3433 24 : if (return_ctype != null && (parent_ctype == null || return_ctype != parent_ctype + "*")) {
3434 1 : m.set_attribute_string ("CCode", "type", return_ctype);
3435 : }
3436 24 : if (metadata.has_argument (ArgumentType.TYPE_PARAMETERS)) {
3437 0 : parse_type_parameters_from_string (m, metadata.get_string (ArgumentType.TYPE_PARAMETERS), metadata.get_source_reference (ArgumentType.TYPE_PARAMETERS));
3438 : }
3439 48 : s = m;
3440 173 : } else if (symbol_type == "glib:signal") {
3441 5 : s = new Signal (name, return_type, current.source_reference);
3442 : } else {
3443 168 : s = new Method (name, return_type, current.source_reference);
3444 168 : if (metadata.has_argument (ArgumentType.TYPE_PARAMETERS)) {
3445 0 : parse_type_parameters_from_string ((Method) s, metadata.get_string (ArgumentType.TYPE_PARAMETERS), metadata.get_source_reference (ArgumentType.TYPE_PARAMETERS));
3446 : }
3447 : }
3448 :
3449 240 : s.access = SymbolAccessibility.PUBLIC;
3450 240 : s.comment = comment;
3451 :
3452 : // Transform fixed-array properties of return-type into ccode-attribute
3453 240 : var array_type = return_type as ArrayType;
3454 12 : if (array_type != null && array_type.fixed_length) {
3455 1 : s.set_attribute_string ("CCode", "array_length_cexpr", ((IntegerLiteral) array_type.length).value);
3456 1 : array_type.fixed_length = false;
3457 1 : array_type.length = null;
3458 : }
3459 :
3460 240 : if (s is Signal) {
3461 5 : if (current.girdata["name"] != name.replace ("_", "-")) {
3462 0 : s.set_attribute_string ("CCode", "cname", current.girdata["name"]);
3463 : }
3464 : }
3465 :
3466 432 : if (s is Method) {
3467 192 : var m = (Method) s;
3468 192 : if (symbol_type == "virtual-method" || symbol_type == "callback") {
3469 36 : if (current.parent.symbol is Interface) {
3470 11 : m.is_abstract = true;
3471 : } else {
3472 25 : m.is_virtual = true;
3473 : }
3474 36 : if (metadata.has_argument (ArgumentType.NO_WRAPPER)) {
3475 0 : s.set_attribute ("NoWrapper", metadata.get_bool (ArgumentType.NO_WRAPPER), s.source_reference);
3476 36 : } else if (invoker == null && !metadata.has_argument (ArgumentType.VFUNC_NAME)) {
3477 11 : s.set_attribute ("NoWrapper", true, s.source_reference);
3478 : }
3479 36 : if (current.girdata["name"] != name) {
3480 0 : m.set_attribute_string ("CCode", "vfunc_name", current.girdata["name"]);
3481 : }
3482 156 : } else if (symbol_type == "function") {
3483 46 : m.binding = MemberBinding.STATIC;
3484 : }
3485 192 : if (metadata.has_argument (ArgumentType.FLOATING)) {
3486 0 : m.returns_floating_reference = metadata.get_bool (ArgumentType.FLOATING);
3487 0 : m.return_type.value_owned = true;
3488 : }
3489 192 : if (metadata.has_argument (ArgumentType.NEW)) {
3490 0 : m.hides = metadata.get_bool (ArgumentType.NEW);
3491 : }
3492 : }
3493 :
3494 408 : if (s is Method && !(s is CreationMethod)) {
3495 168 : var method = (Method) s;
3496 168 : if (metadata.has_argument (ArgumentType.VIRTUAL)) {
3497 10 : method.is_virtual = metadata.get_bool (ArgumentType.VIRTUAL);
3498 10 : method.is_abstract = false;
3499 158 : } else if (metadata.has_argument (ArgumentType.ABSTRACT)) {
3500 10 : method.is_abstract = metadata.get_bool (ArgumentType.ABSTRACT);
3501 10 : method.is_virtual = false;
3502 : }
3503 168 : if (metadata.has_argument (ArgumentType.VFUNC_NAME)) {
3504 0 : method.set_attribute_string ("CCode", "vfunc_name", metadata.get_string (ArgumentType.VFUNC_NAME));
3505 0 : method.is_virtual = true;
3506 : }
3507 168 : if (metadata.has_argument (ArgumentType.FINISH_VFUNC_NAME)) {
3508 0 : method.set_attribute_string ("CCode", "finish_vfunc_name", metadata.get_string (ArgumentType.FINISH_VFUNC_NAME));
3509 0 : method.is_virtual = true;
3510 : }
3511 : }
3512 :
3513 240 : if (!(metadata.get_expression (ArgumentType.THROWS) is NullLiteral)) {
3514 249 : if (metadata.has_argument (ArgumentType.THROWS)) {
3515 9 : var error_types = metadata.get_string (ArgumentType.THROWS).split(",");
3516 36 : foreach (var error_type_name in error_types) {
3517 9 : var error_type = parse_type_from_string (error_type_name, true, metadata.get_source_reference (ArgumentType.THROWS));
3518 9 : if (s is Method) {
3519 8 : ((Method) s).add_error_type (error_type);
3520 : } else {
3521 1 : ((Delegate) s).add_error_type (error_type);
3522 : }
3523 : }
3524 231 : } else if (throws_string == "1") {
3525 16 : if (s is Method) {
3526 12 : ((Method) s).add_error_type (new ErrorType (null, null));
3527 : } else {
3528 4 : ((Delegate) s).add_error_type (new ErrorType (null, null));
3529 : }
3530 : }
3531 : }
3532 :
3533 432 : if (s is Method) {
3534 192 : var m = (Method) s;
3535 192 : m.set_attribute ("PrintfFormat", metadata.get_bool (ArgumentType.PRINTF_FORMAT));
3536 192 : if (metadata.has_argument (ArgumentType.SENTINEL)) {
3537 0 : m.set_attribute_string ("CCode", "sentinel", metadata.get_string (ArgumentType.SENTINEL));
3538 : }
3539 : }
3540 :
3541 240 : if (return_type is ArrayType && metadata.has_argument (ArgumentType.ARRAY_LENGTH_IDX)) {
3542 0 : return_array_length_idx = metadata.get_integer (ArgumentType.ARRAY_LENGTH_IDX);
3543 : } else {
3544 240 : if (return_no_array_length || return_array_null_terminated) {
3545 2 : s.set_attribute_bool ("CCode", "array_length", !return_no_array_length);
3546 : }
3547 240 : if (return_array_null_terminated) {
3548 1 : s.set_attribute_bool ("CCode", "array_null_terminated", true);
3549 : }
3550 : }
3551 240 : current.return_array_length_idx = return_array_length_idx;
3552 :
3553 240 : if (ctype != null) {
3554 0 : s.set_attribute_string ("CCode", "type", ctype);
3555 : }
3556 :
3557 480 : current.symbol = s;
3558 :
3559 240 : if (metadata.has_argument (ArgumentType.FINISH_NAME)) {
3560 0 : s.set_attribute_string ("CCode", "finish_name", metadata.get_string (ArgumentType.FINISH_NAME));
3561 : }
3562 240 : if (metadata.has_argument (ArgumentType.FINISH_INSTANCE)) {
3563 0 : s.set_attribute_bool ("CCode", "finish_instance", metadata.get_bool (ArgumentType.FINISH_INSTANCE));
3564 : }
3565 :
3566 240 : int instance_idx = -2;
3567 240 : if (element_name == "function" && symbol_type == "method") {
3568 0 : if (metadata.has_argument (ArgumentType.INSTANCE_IDX)) {
3569 0 : instance_idx = metadata.get_integer (ArgumentType.INSTANCE_IDX);
3570 0 : if (instance_idx != 0) {
3571 0 : s.set_attribute_double ("CCode", "instance_pos", instance_idx + 0.5);
3572 : }
3573 : } else {
3574 0 : Report.error (get_current_src (), "instance_idx required when converting function to method");
3575 : }
3576 : }
3577 240 : if (element_name == "callback") {
3578 43 : if (metadata.has_argument (ArgumentType.INSTANCE_IDX)) {
3579 0 : instance_idx = metadata.get_integer (ArgumentType.INSTANCE_IDX);
3580 0 : s.set_attribute_double ("CCode", "instance_pos", instance_idx + 0.9);
3581 0 : ((Delegate) s).has_target = true;
3582 : }
3583 : }
3584 :
3585 240 : var parameters = new ArrayList<ParameterInfo> ();
3586 240 : current.array_length_parameters = new ArrayList<int> ();
3587 240 : current.closure_parameters = new ArrayList<int> ();
3588 240 : current.destroy_parameters = new ArrayList<int> ();
3589 240 : if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "parameters") {
3590 203 : start_element ("parameters");
3591 203 : next ();
3592 :
3593 203 : var current_parameter_idx = -1;
3594 1011 : while (current_token == MarkupTokenType.START_ELEMENT) {
3595 458 : var is_instance_parameter = (reader.name == "instance-parameter"
3596 108 : && !(symbol_type == "function" || symbol_type == "constructor"));
3597 :
3598 108 : if (!is_instance_parameter) {
3599 350 : current_parameter_idx++;
3600 : }
3601 :
3602 458 : if (instance_idx > -2 && instance_idx == current_parameter_idx) {
3603 0 : skip_element ();
3604 108 : continue;
3605 : }
3606 :
3607 458 : if (!push_metadata ()) {
3608 0 : skip_element ();
3609 0 : continue;
3610 : }
3611 :
3612 : bool caller_allocates;
3613 : int array_length_idx, closure_idx, destroy_idx;
3614 : string scope;
3615 458 : string default_param_name = null;
3616 : Comment? param_comment;
3617 458 : default_param_name = "arg%d".printf (parameters.size);
3618 458 : var param = parse_parameter (out caller_allocates, out array_length_idx, out closure_idx, out destroy_idx, out scope, out param_comment, default_param_name);
3619 :
3620 458 : if (is_instance_parameter) {
3621 108 : unowned Method? m = s as Method;
3622 108 : if (m != null) {
3623 108 : if (param.direction == ParameterDirection.IN) {
3624 104 : if (param.variable_type.value_owned) {
3625 2 : m.set_attribute ("DestroysInstance", true);
3626 : }
3627 104 : pop_metadata ();
3628 104 : continue;
3629 4 : } else if (current.parent.symbol is Struct
3630 4 : && caller_allocates && param.direction == ParameterDirection.OUT) {
3631 : // struct methods that have instance parameters with 'out' direction are usually creation methods
3632 4 : string? cm_name = m.name;
3633 4 : if (cm_name != null && (cm_name == "init" || cm_name.has_prefix ("init_"))) {
3634 4 : if (cm_name == "init") {
3635 2 : cm_name = null;
3636 2 : } else if (cm_name.has_prefix ("init_")) {
3637 2 : cm_name = cm_name.substring ("init_".length);
3638 : }
3639 4 : s = new CreationMethod (null, cm_name, m.source_reference, m.comment);
3640 4 : s.access = SymbolAccessibility.PUBLIC;
3641 8 : current.symbol = s;
3642 4 : pop_metadata ();
3643 4 : continue;
3644 : }
3645 0 : } else if (current.parent.symbol is Class && ((Class) current.parent.symbol).is_compact
3646 0 : && caller_allocates && param.direction == ParameterDirection.OUT) {
3647 0 : pop_metadata ();
3648 0 : continue;
3649 : }
3650 : //TODO can more be done here?
3651 0 : m.binding = MemberBinding.STATIC;
3652 : }
3653 : }
3654 :
3655 350 : if (array_length_idx != -1) {
3656 20 : if (instance_idx > -2 && instance_idx < array_length_idx) {
3657 0 : array_length_idx--;
3658 : }
3659 20 : current.array_length_parameters.add (array_length_idx);
3660 : }
3661 350 : if (closure_idx != -1) {
3662 43 : if (instance_idx > -2 && instance_idx < closure_idx) {
3663 0 : closure_idx--;
3664 : }
3665 43 : if (current.closure_parameters.index_of (current_parameter_idx) < 0) {
3666 41 : current.closure_parameters.add (closure_idx);
3667 : }
3668 : }
3669 350 : if (destroy_idx != -1) {
3670 16 : if (instance_idx > -2 && instance_idx < destroy_idx) {
3671 0 : destroy_idx--;
3672 : }
3673 16 : if (current.destroy_parameters.index_of (current_parameter_idx) < 0) {
3674 14 : current.destroy_parameters.add (destroy_idx);
3675 : }
3676 : }
3677 350 : if (param_comment != null) {
3678 2 : if (comment == null) {
3679 1 : comment = new GirComment (null, s.source_reference);
3680 1 : s.comment = comment;
3681 : }
3682 :
3683 2 : comment.add_content_for_parameter ((param.ellipsis)? "..." : param.name, param_comment);
3684 : }
3685 :
3686 350 : var info = new ParameterInfo (param, array_length_idx, closure_idx, destroy_idx, scope == "async");
3687 350 : info.caller_allocates = caller_allocates;
3688 350 : parameters.add (info);
3689 350 : pop_metadata ();
3690 : }
3691 203 : end_element ("parameters");
3692 : }
3693 480 : current.parameters = parameters;
3694 :
3695 240 : pop_node ();
3696 240 : end_element (element_name);
3697 : }
3698 :
3699 168 : void parse_method (string element_name) {
3700 168 : parse_function (element_name);
3701 : }
3702 :
3703 5 : void parse_signal () {
3704 5 : parse_function ("glib:signal");
3705 : }
3706 :
3707 8 : void parse_boxed (string element_name) {
3708 4 : start_element (element_name);
3709 4 : string name = reader.get_attribute ("name");
3710 4 : if (name == null) {
3711 0 : name = reader.get_attribute ("glib:name");
3712 : }
3713 4 : push_node (element_get_name (name), true);
3714 :
3715 : Class cl;
3716 4 : bool require_copy_free = false;
3717 4 : if (current.new_symbol) {
3718 4 : cl = new Class (current.name, current.source_reference);
3719 4 : if (metadata.has_argument (ArgumentType.COMPACT)) {
3720 0 : cl.set_attribute ("Compact", metadata.get_bool (ArgumentType.COMPACT));
3721 : } else {
3722 4 : cl.set_attribute ("Compact", true);
3723 : }
3724 4 : if (metadata.has_argument (ArgumentType.SEALED) && metadata.get_bool (ArgumentType.SEALED)) {
3725 0 : if (cl.is_compact) {
3726 0 : cl.set_attribute_bool ("Compact", "opaque", true);
3727 : } else {
3728 0 : cl.is_sealed = true;
3729 : }
3730 : }
3731 :
3732 8 : current.symbol = cl;
3733 : } else {
3734 0 : cl = (Class) current.symbol;
3735 : }
3736 :
3737 4 : set_type_id_ccode (cl);
3738 4 : require_copy_free = cl.has_attribute_argument ("CCode", "type_id");
3739 :
3740 4 : cl.access = SymbolAccessibility.PUBLIC;
3741 :
3742 4 : if (metadata.has_argument (ArgumentType.BASE_TYPE)) {
3743 0 : cl.add_base_type (parse_type_from_string (metadata.get_string (ArgumentType.BASE_TYPE), true, metadata.get_source_reference (ArgumentType.BASE_TYPE)));
3744 : }
3745 4 : if (metadata.has_argument (ArgumentType.COPY_FUNCTION)) {
3746 0 : cl.set_attribute_string ("CCode", "copy_function", metadata.get_string (ArgumentType.COPY_FUNCTION));
3747 4 : } else if (reader.has_attribute ("copy-function")) {
3748 1 : cl.set_attribute_string ("CCode", "copy_function", reader.get_attribute ("copy-function"));
3749 : }
3750 4 : if (metadata.has_argument (ArgumentType.FREE_FUNCTION)) {
3751 0 : cl.set_attribute_string ("CCode", "free_function", metadata.get_string (ArgumentType.FREE_FUNCTION));
3752 4 : } else if (reader.has_attribute ("free-function")) {
3753 1 : cl.set_attribute_string ("CCode", "free_function", reader.get_attribute ("free-function"));
3754 : }
3755 4 : if (metadata.has_argument (ArgumentType.REF_FUNCTION)) {
3756 0 : cl.set_attribute_string ("CCode", "ref_function", metadata.get_string (ArgumentType.REF_FUNCTION));
3757 4 : } else if (reader.has_attribute ("glib:ref-func")) {
3758 0 : cl.set_attribute_string ("CCode", "ref_function", reader.get_attribute ("glib:ref-func"));
3759 : }
3760 4 : if (metadata.has_argument (ArgumentType.REF_SINK_FUNCTION)) {
3761 0 : cl.set_attribute_string ("CCode", "ref_sink_function", metadata.get_string (ArgumentType.REF_SINK_FUNCTION));
3762 : }
3763 4 : if (metadata.has_argument (ArgumentType.UNREF_FUNCTION)) {
3764 0 : cl.set_attribute_string ("CCode", "unref_function", metadata.get_string (ArgumentType.UNREF_FUNCTION));
3765 4 : } else if (reader.has_attribute ("glib:unref-func")) {
3766 0 : cl.set_attribute_string ("CCode", "unref_function", reader.get_attribute ("glib:unref-func"));
3767 : }
3768 :
3769 4 : next ();
3770 :
3771 4 : cl.comment = parse_symbol_doc ();
3772 :
3773 : Node? ref_method = null;
3774 : Node? unref_method = null;
3775 :
3776 12 : while (current_token == MarkupTokenType.START_ELEMENT) {
3777 8 : if (!push_metadata ()) {
3778 0 : skip_element ();
3779 0 : continue;
3780 : }
3781 :
3782 8 : if (reader.name == "field") {
3783 4 : parse_field ();
3784 4 : } else if (reader.name == "constructor") {
3785 2 : parse_constructor ();
3786 4 : } else if (reader.name == "method") {
3787 2 : parse_method ("method");
3788 2 : var cname = old_current.get_cname ();
3789 2 : if (cname.has_suffix ("_ref") && (ref_method == null || old_current.name == "ref")) {
3790 0 : ref_method = old_current;
3791 2 : } else if (cname.has_suffix ("_unref") && (unref_method == null || old_current.name == "unref")) {
3792 0 : unref_method = old_current;
3793 : }
3794 0 : } else if (reader.name == "function") {
3795 0 : parse_method ("function");
3796 0 : } else if (reader.name == "function-macro") {
3797 0 : skip_element ();
3798 0 : } else if (reader.name == "union") {
3799 0 : parse_union ();
3800 : } else {
3801 : // error
3802 0 : Report.error (get_current_src (), "unknown child element `%s' in `class'", reader.name);
3803 0 : skip_element ();
3804 : }
3805 :
3806 8 : pop_metadata ();
3807 : }
3808 :
3809 : // Add ccode-attributes for ref/unref methodes if available
3810 : // otherwise fallback to default g_boxed_copy/free
3811 11 : if (cl.has_attribute_argument ("CCode", "ref_function") || cl.has_attribute_argument ("CCode", "unref_function")
3812 7 : || cl.has_attribute_argument ("CCode", "copy_function") || cl.has_attribute_argument ("CCode", "free_function")) {
3813 : //do nothing
3814 3 : } else if (ref_method != null && unref_method != null) {
3815 0 : cl.set_attribute_string ("CCode", "ref_function", ref_method.get_cname ());
3816 0 : cl.set_attribute_string ("CCode", "unref_function", unref_method.get_cname ());
3817 3 : } else if (require_copy_free) {
3818 2 : cl.set_attribute_string ("CCode", "copy_function", "g_boxed_copy");
3819 2 : cl.set_attribute_string ("CCode", "free_function", "g_boxed_free");
3820 : }
3821 :
3822 4 : pop_node ();
3823 4 : end_element (element_name);
3824 : }
3825 :
3826 3 : void parse_union () {
3827 2 : start_element ("union");
3828 :
3829 2 : string? element_name = element_get_name ();
3830 2 : if (element_name == null) {
3831 1 : next ();
3832 :
3833 1 : parse_symbol_doc ();
3834 :
3835 3 : while (current_token == MarkupTokenType.START_ELEMENT) {
3836 2 : if (!push_metadata ()) {
3837 1 : skip_element ();
3838 1 : continue;
3839 : }
3840 :
3841 1 : if (reader.name == "field") {
3842 1 : parse_field ();
3843 0 : } else if (reader.name == "record") {
3844 0 : Report.warning (get_current_src (), "unhandled child element `%s' in `transparent union'", reader.name);
3845 0 : skip_element ();
3846 : } else {
3847 : // error
3848 0 : Report.error (get_current_src (), "unknown child element `%s' in `transparent union'", reader.name);
3849 0 : skip_element ();
3850 : }
3851 :
3852 1 : pop_metadata ();
3853 : }
3854 :
3855 1 : end_element ("union");
3856 1 : return;
3857 : }
3858 :
3859 1 : push_node (element_name, true);
3860 :
3861 : Struct st;
3862 1 : if (current.new_symbol) {
3863 1 : st = new Struct (reader.get_attribute ("name"), current.source_reference);
3864 2 : current.symbol = st;
3865 : } else {
3866 0 : st = (Struct) current.symbol;
3867 : }
3868 1 : st.access = SymbolAccessibility.PUBLIC;
3869 :
3870 1 : if (metadata.has_argument (ArgumentType.TYPE_PARAMETERS)) {
3871 0 : parse_type_parameters_from_string (st, metadata.get_string (ArgumentType.TYPE_PARAMETERS), metadata.get_source_reference (ArgumentType.TYPE_PARAMETERS));
3872 : }
3873 :
3874 1 : next ();
3875 :
3876 1 : st.comment = parse_symbol_doc ();
3877 :
3878 3 : while (current_token == MarkupTokenType.START_ELEMENT) {
3879 2 : if (!push_metadata ()) {
3880 0 : skip_element ();
3881 0 : continue;
3882 : }
3883 :
3884 2 : if (reader.name == "field") {
3885 2 : parse_field ();
3886 0 : } else if (reader.name == "constructor") {
3887 0 : parse_constructor ();
3888 0 : } else if (reader.name == "method") {
3889 0 : parse_method ("method");
3890 0 : } else if (reader.name == "function") {
3891 0 : parse_method ("function");
3892 0 : } else if (reader.name == "function-macro") {
3893 0 : skip_element ();
3894 0 : } else if (reader.name == "record") {
3895 0 : parse_record ();
3896 : } else {
3897 : // error
3898 0 : Report.error (get_current_src (), "unknown child element `%s' in `union'", reader.name);
3899 0 : skip_element ();
3900 : }
3901 :
3902 2 : pop_metadata ();
3903 : }
3904 :
3905 1 : pop_node ();
3906 1 : end_element ("union");
3907 : }
3908 :
3909 22 : void parse_constant () {
3910 11 : start_element ("constant");
3911 11 : push_node (element_get_name (), false);
3912 :
3913 11 : next ();
3914 :
3915 11 : var comment = parse_symbol_doc ();
3916 :
3917 : bool no_array_length;
3918 : bool array_null_terminated;
3919 : int array_length_idx;
3920 11 : var type = parse_type (null, out array_length_idx, true, out no_array_length, out array_null_terminated);
3921 11 : type = element_get_type (type, true, ref no_array_length, ref array_null_terminated);
3922 11 : var c = new Constant (current.name, type, null, current.source_reference);
3923 22 : current.symbol = c;
3924 11 : c.access = SymbolAccessibility.PUBLIC;
3925 11 : c.comment = comment;
3926 11 : if (no_array_length || array_null_terminated) {
3927 1 : c.set_attribute_bool ("CCode", "array_length", !no_array_length);
3928 : }
3929 11 : if (array_null_terminated) {
3930 1 : c.set_attribute_bool ("CCode", "array_null_terminated", true);
3931 : }
3932 :
3933 11 : pop_node ();
3934 11 : end_element ("constant");
3935 : }
3936 :
3937 : /* Reporting */
3938 27 : void report_unused_metadata (Metadata metadata) {
3939 27 : if (metadata == Metadata.empty) {
3940 : return;
3941 : }
3942 :
3943 27 : if (metadata.args.size == 0 && metadata.children.size == 0) {
3944 0 : Report.warning (metadata.source_reference, "empty metadata");
3945 0 : return;
3946 : }
3947 :
3948 78 : foreach (var arg_type in metadata.args.get_keys ()) {
3949 24 : var arg = metadata.args[arg_type];
3950 24 : if (!arg.used) {
3951 : // if metadata is used and argument is not, then it's a unexpected argument
3952 0 : Report.warning (arg.source_reference, "argument never used");
3953 : }
3954 : }
3955 :
3956 53 : foreach (var child in metadata.children) {
3957 26 : if (!child.used) {
3958 0 : Report.warning (child.source_reference, "metadata never used");
3959 : } else {
3960 26 : report_unused_metadata (child);
3961 : }
3962 : }
3963 : }
3964 :
3965 : /* Post-parsing */
3966 :
3967 1538 : void resolve_gir_symbols () {
3968 : // gir has simple namespaces, we won't get deeper than 2 levels here, except reparenting
3969 2356 : foreach (var map_from in unresolved_gir_symbols) {
3970 1057 : while (map_from != null) {
3971 720 : var map_to = unresolved_symbols_map[map_from];
3972 720 : if (map_to != null) {
3973 : // remap the original symbol to match the target
3974 72 : map_from.inner = null;
3975 72 : map_from.name = map_to.name;
3976 72 : if (map_to is UnresolvedSymbol) {
3977 0 : var umap_to = (UnresolvedSymbol) map_to;
3978 0 : while (umap_to.inner != null) {
3979 0 : umap_to = umap_to.inner;
3980 0 : map_from.inner = new UnresolvedSymbol (null, umap_to.name);
3981 0 : map_from = map_from.inner;
3982 : }
3983 : } else {
3984 73 : while (map_to.parent_symbol != null && map_to.parent_symbol != context.root) {
3985 2 : map_to = map_to.parent_symbol;
3986 1 : map_from.inner = new UnresolvedSymbol (null, map_to.name);
3987 2 : map_from = map_from.inner;
3988 : }
3989 : }
3990 72 : break;
3991 : }
3992 959 : map_from = map_from.inner;
3993 : }
3994 : }
3995 : }
3996 :
3997 1538 : void create_new_namespaces () {
3998 1539 : foreach (var node in Node.new_namespaces) {
3999 1 : if (node.symbol == null) {
4000 1 : node.symbol = new Namespace (node.name, node.source_reference);
4001 : }
4002 : }
4003 : }
4004 :
4005 3076 : void resolve_type_arguments () {
4006 1538 : var it = unresolved_type_arguments.map_iterator ();
4007 1540 : while (it.next ()) {
4008 1 : var element_type = it.get_key ();
4009 1 : var parent = it.get_value ();
4010 1 : var sym = (TypeSymbol) resolve_symbol (parent, element_type.unresolved_symbol);
4011 :
4012 : // box structs in type arguments
4013 1 : var st = sym as Struct;
4014 1 : if (st != null && !st.is_integer_type () && !st.is_floating_type ()) {
4015 0 : element_type.nullable = true;
4016 : }
4017 : }
4018 : }
4019 :
4020 38 : void resolve_inherited_types (Node object_node) {
4021 38 : if (object_node.inherited_types == null) {
4022 : return;
4023 : }
4024 :
4025 0 : int i = 0;
4026 0 : foreach (var t in object_node.inherited_types) {
4027 0 : Symbol? sym = null;
4028 0 : if (t is UnresolvedType) {
4029 0 : var unresolved_symbol = ((UnresolvedType) t).unresolved_symbol;
4030 0 : sym = resolve_symbol (object_node.parent, unresolved_symbol);
4031 : }
4032 0 : if (sym is ObjectTypeSymbol) {
4033 0 : var type = new ObjectType ((ObjectTypeSymbol) sym, t.source_reference);
4034 0 : foreach (var arg in t.get_type_arguments ()) {
4035 0 : type.add_type_argument (arg);
4036 : }
4037 0 : object_node.inherited_types[i] = type;
4038 : }
4039 0 : i++;
4040 : }
4041 : }
4042 :
4043 62 : void process_class (Node class_node) {
4044 31 : resolve_inherited_types (class_node);
4045 :
4046 62 : Class cl = (Class) class_node.symbol;
4047 81 : foreach (DataType base_type in cl.get_base_types ()) {
4048 25 : Symbol sym = null;
4049 50 : if (base_type is UnresolvedType) {
4050 25 : var unresolved_symbol = ((UnresolvedType) base_type).unresolved_symbol;
4051 25 : sym = resolve_symbol (class_node.parent, unresolved_symbol);
4052 : } else {
4053 0 : sym = base_type.type_symbol;
4054 : }
4055 25 : if (class_node.inherited_types != null) {
4056 0 : foreach (var t in class_node.inherited_types) {
4057 0 : if (sym == t.type_symbol) {
4058 0 : cl.replace_type (base_type, t);
4059 : }
4060 : }
4061 : }
4062 : }
4063 : }
4064 :
4065 14 : void process_interface (Node iface_node) {
4066 7 : resolve_inherited_types (iface_node);
4067 :
4068 : /* Temporarily workaround G-I bug not adding GLib.Object prerequisite:
4069 : ensure we have at least one instantiable prerequisite */
4070 7 : Interface iface = (Interface) iface_node.symbol;
4071 7 : bool has_instantiable_prereq = false;
4072 17 : foreach (DataType prereq in iface.get_prerequisites ()) {
4073 5 : Symbol sym = null;
4074 10 : if (prereq is UnresolvedType) {
4075 5 : var unresolved_symbol = ((UnresolvedType) prereq).unresolved_symbol;
4076 5 : sym = resolve_symbol (iface_node.parent, unresolved_symbol);
4077 : } else {
4078 0 : sym = prereq.type_symbol;
4079 : }
4080 5 : if (iface_node.inherited_types != null) {
4081 0 : foreach (var t in iface_node.inherited_types) {
4082 0 : if (sym == t.type_symbol) {
4083 0 : iface.replace_type (prereq, t);
4084 : }
4085 : }
4086 : }
4087 5 : if (sym is Class) {
4088 5 : has_instantiable_prereq = true;
4089 : }
4090 : }
4091 :
4092 7 : if (!has_instantiable_prereq) {
4093 4 : ifaces_needing_object_prereq.add (iface);
4094 : }
4095 : }
4096 :
4097 10 : void process_alias (Node alias) {
4098 : /* this is unfortunate because <alias> tag has no type information, thus we have
4099 : to guess it from the base type */
4100 5 : DataType base_type = null;
4101 5 : Symbol type_sym = null;
4102 5 : Node base_node = null;
4103 5 : bool simple_type = false;
4104 5 : if (alias.base_type is UnresolvedType) {
4105 5 : base_type = alias.base_type;
4106 5 : base_node = resolve_node (alias.parent, ((UnresolvedType) base_type).unresolved_symbol);
4107 5 : if (base_node != null) {
4108 5 : type_sym = base_node.symbol;
4109 : }
4110 0 : } else if (alias.base_type is PointerType && ((PointerType) alias.base_type).base_type is VoidType) {
4111 : // gpointer, if it's a struct make it a simpletype
4112 : simple_type = true;
4113 : } else {
4114 0 : base_type = alias.base_type;
4115 0 : type_sym = base_type.type_symbol;
4116 0 : if (type_sym != null) {
4117 0 : base_node = resolve_node (alias.parent, parse_symbol_from_string (type_sym.get_full_name (), alias.source_reference));
4118 : }
4119 : }
4120 :
4121 5 : if (type_sym is Struct && ((Struct) type_sym).is_simple_type ()) {
4122 5 : simple_type = true;
4123 : }
4124 :
4125 6 : if (base_type == null || type_sym == null || type_sym is Struct) {
4126 1 : var st = new Struct (alias.name, alias.source_reference);
4127 1 : st.access = SymbolAccessibility.PUBLIC;
4128 1 : if (base_type != null) {
4129 : // threat target="none" as a new struct
4130 1 : st.base_type = base_type;
4131 : }
4132 1 : st.comment = alias.comment;
4133 1 : st.set_simple_type (simple_type);
4134 2 : alias.symbol = st;
4135 5 : } else if (type_sym is Class) {
4136 1 : var cl = new Class (alias.name, alias.source_reference);
4137 1 : cl.access = SymbolAccessibility.PUBLIC;
4138 1 : if (base_type != null) {
4139 1 : cl.add_base_type (base_type);
4140 : }
4141 1 : cl.comment = alias.comment;
4142 1 : cl.set_attribute ("Compact", ((Class) type_sym).is_compact);
4143 2 : alias.symbol = cl;
4144 4 : } else if (type_sym is Interface) {
4145 : // this is not a correct alias, but what can we do otherwise?
4146 1 : var iface = new Interface (alias.name, alias.source_reference);
4147 1 : iface.access = SymbolAccessibility.PUBLIC;
4148 1 : if (base_type != null) {
4149 1 : iface.add_prerequisite (base_type);
4150 : }
4151 1 : iface.comment = alias.comment;
4152 2 : alias.symbol = iface;
4153 4 : } else if (type_sym is Delegate) {
4154 2 : var orig = (Delegate) type_sym;
4155 2 : if (base_node != null) {
4156 2 : base_node.process (this);
4157 4 : orig = (Delegate) base_node.symbol;
4158 : }
4159 :
4160 2 : var deleg = new Delegate (alias.name, orig.return_type.copy (), alias.source_reference);
4161 2 : deleg.access = orig.access;
4162 :
4163 4 : foreach (var param in orig.get_parameters ()) {
4164 1 : deleg.add_parameter (param.copy ());
4165 : }
4166 :
4167 2 : var error_types = new ArrayList<DataType> ();
4168 2 : orig.get_error_types (error_types, alias.source_reference);
4169 2 : foreach (var error_type in error_types) {
4170 0 : deleg.add_error_type (error_type.copy ());
4171 : }
4172 :
4173 4 : foreach (var attribute in orig.attributes) {
4174 2 : deleg.add_attribute (attribute);
4175 : }
4176 :
4177 4 : alias.symbol = deleg;
4178 0 : } else if (type_sym != null) {
4179 0 : Report.warning (alias.source_reference, "alias `%s' for `%s' is not supported", alias.get_full_name (), type_sym.get_full_name ());
4180 0 : alias.symbol = type_sym;
4181 0 : alias.merged = true;
4182 : }
4183 :
4184 : // inherit attributes, like type_id
4185 5 : if (type_sym is Class || (type_sym is Struct && !simple_type)) {
4186 1 : if (type_sym.has_attribute_argument ("CCode", "has_type_id")) {
4187 0 : alias.symbol.set_attribute_bool ("CCode", "has_type_id", type_sym.get_attribute_bool ("CCode", "has_type_id"));
4188 1 : } else if (type_sym.has_attribute_argument ("CCode", "type_id")) {
4189 1 : alias.symbol.set_attribute_string ("CCode", "type_id", type_sym.get_attribute_string ("CCode", "type_id"));
4190 : }
4191 : }
4192 : }
4193 :
4194 482 : void process_callable (Node node) {
4195 242 : if (node.element_type == "alias" && node.symbol is Delegate) {
4196 : // processed in parse_alias
4197 : return;
4198 : }
4199 :
4200 240 : var s = node.symbol;
4201 240 : List<ParameterInfo> parameters = node.parameters;
4202 :
4203 240 : DataType return_type = null;
4204 240 : if (s is Callable) {
4205 240 : return_type = ((Callable) s).return_type;
4206 : }
4207 :
4208 240 : if (return_type is ArrayType && node.return_array_length_idx >= 0) {
4209 11 : if (node.return_array_length_idx >= parameters.size) {
4210 0 : Report.error (return_type.source_reference, "invalid array length index");
4211 : } else {
4212 11 : parameters[node.return_array_length_idx].keep = false;
4213 11 : node.array_length_parameters.add (node.return_array_length_idx);
4214 : }
4215 229 : } else if (return_type is VoidType && parameters.size > 0) {
4216 135 : int n_out_parameters = 0;
4217 414 : foreach (var info in parameters) {
4218 279 : if (info.param.direction == ParameterDirection.OUT) {
4219 26 : n_out_parameters++;
4220 : }
4221 : }
4222 :
4223 153 : if (n_out_parameters == 1) {
4224 18 : ParameterInfo last_param = parameters[parameters.size-1];
4225 18 : if (last_param.param.direction == ParameterDirection.OUT) {
4226 : // use last out real-non-null-struct parameter as return type
4227 25 : if (last_param.param.variable_type is UnresolvedType) {
4228 14 : var st = resolve_symbol (node.parent, ((UnresolvedType) last_param.param.variable_type).unresolved_symbol) as Struct;
4229 16 : if (st != null && !st.is_simple_type () && !last_param.param.variable_type.nullable) {
4230 2 : if (!node.metadata.get_bool (ArgumentType.RETURN_VOID, false)) {
4231 2 : last_param.keep = false;
4232 2 : return_type = last_param.param.variable_type.copy ();
4233 : }
4234 : }
4235 : }
4236 : }
4237 : }
4238 : } else {
4239 114 : if (return_type is UnresolvedType && !return_type.nullable) {
4240 39 : var st = resolve_symbol (node.parent, ((UnresolvedType) return_type).unresolved_symbol) as Struct;
4241 40 : if (st != null) {
4242 20 : bool is_simple_type = false;
4243 20 : Struct? base_st = st;
4244 :
4245 21 : while (base_st != null) {
4246 20 : if (base_st.is_simple_type ()) {
4247 : is_simple_type = true;
4248 : break;
4249 : }
4250 :
4251 1 : if (base_st.base_type is UnresolvedType) {
4252 0 : base_st = resolve_symbol (node.parent, ((UnresolvedType) base_st.base_type).unresolved_symbol) as Struct;
4253 : } else {
4254 1 : base_st = base_st.base_struct;
4255 : }
4256 : }
4257 :
4258 20 : if (!is_simple_type) {
4259 1 : return_type.nullable = true;
4260 : }
4261 : }
4262 : }
4263 : }
4264 :
4265 240 : bool first_param = true;
4266 590 : foreach (ParameterInfo info in parameters) {
4267 350 : unowned DataType type = info.param.variable_type;
4268 :
4269 : // Do not mark out-parameters as nullable if they are simple-types,
4270 : // since it would result in a boxed-type in vala
4271 351 : if (info.param.direction == ParameterDirection.OUT && type.nullable) {
4272 5 : Struct? st = null;
4273 5 : if (type is UnresolvedType) {
4274 1 : st = resolve_symbol (node.parent, ((UnresolvedType) type).unresolved_symbol) as Struct;
4275 4 : } else if (type is ValueType) {
4276 0 : st = type.type_symbol as Struct;
4277 : }
4278 6 : if (st != null && st.is_simple_type ()) {
4279 1 : type.nullable = false;
4280 : }
4281 : }
4282 :
4283 : // Check and mark GAsync-style methods
4284 596 : if (s is Method) {
4285 246 : string? type_name = null;
4286 246 : unowned UnresolvedType? unresolved_type = type as UnresolvedType;
4287 246 : if (unresolved_type != null) {
4288 388 : type_name = unresolved_type.unresolved_symbol.name;
4289 52 : } else if (type != null) {
4290 50 : type_name = type.to_string ();
4291 : }
4292 246 : if (info.is_async) {
4293 14 : if ((unresolved_type != null && type_name == "AsyncReadyCallback")
4294 0 : || type_name == "GLib.AsyncReadyCallback" || type_name == "Gio.AsyncReadyCallback"
4295 0 : || type_name == "GLib.AsyncReadyCallback?" || type_name == "Gio.AsyncReadyCallback?") {
4296 14 : ((Method) s).coroutine = true;
4297 14 : info.keep = false;
4298 : }
4299 : }
4300 246 : if ((unresolved_type != null && type_name == "AsyncResult")
4301 232 : || type_name == "GLib.AsyncResult" || type_name == "Gio.AsyncResult"
4302 232 : || type_name == "GLib.AsyncResult?" || type_name == "Gio.AsyncResult?") {
4303 14 : info.is_async_result = true;
4304 : }
4305 : }
4306 :
4307 : // More thorough check for delegates throwing an error
4308 350 : if (info.param.direction == ParameterDirection.OUT && s is Delegate && !s.tree_can_fail) {
4309 3 : unowned UnresolvedType? unresolved_type = type as UnresolvedType;
4310 3 : if (unresolved_type != null && unresolved_type.unresolved_symbol.to_string () == "GLib.Error") {
4311 1 : ((Delegate) s).add_error_type (new ErrorType (null, null));
4312 1 : info.is_error = true;
4313 1 : info.keep = false;
4314 : }
4315 : }
4316 :
4317 : // Try to transform static function to instance method
4318 385 : if (first_param && info.keep && type != null && s is Method && ((Method) s).binding == MemberBinding.STATIC) {
4319 : Symbol? sym;
4320 35 : if (type is UnresolvedType) {
4321 31 : sym = resolve_symbol (node.parent, ((UnresolvedType) type).unresolved_symbol);
4322 : } else {
4323 4 : sym = type.type_symbol;
4324 : }
4325 35 : if (sym == node.parent.symbol && !type.nullable
4326 4 : && ((sym is TypeSymbol && info.param.direction == ParameterDirection.IN)
4327 4 : || (info.caller_allocates && info.param.direction == ParameterDirection.OUT
4328 0 : && (sym is Struct || (sym is Class && ((Class) sym).is_compact))))) {
4329 0 : ((Method) s).binding = MemberBinding.INSTANCE;
4330 0 : info.keep = false;
4331 : }
4332 : }
4333 :
4334 350 : first_param = false;
4335 : }
4336 :
4337 : // Add null-literal as default-value for trailing GLib.Cancellable parameters
4338 242 : for (int param_n = parameters.size - 1 ; param_n >= 0 ; param_n--) {
4339 178 : ParameterInfo info = parameters[param_n];
4340 178 : if (!info.param.ellipsis && info.param.initializer == null) {
4341 176 : string type_string = info.param.variable_type.to_string ();
4342 176 : if (type_string == "GLib.Cancellable?" || type_string == "Gio.Cancellable?") {
4343 0 : info.param.initializer = new Vala.NullLiteral ();
4344 : } else {
4345 176 : break;
4346 : }
4347 : }
4348 : }
4349 :
4350 324 : if (parameters.size > 1) {
4351 84 : ParameterInfo last_param = parameters[parameters.size-1];
4352 86 : if (last_param.param.ellipsis) {
4353 2 : var first_vararg_param = parameters[parameters.size-2];
4354 2 : if (first_vararg_param.param.name.has_prefix ("first_")) {
4355 0 : first_vararg_param.keep = false;
4356 : }
4357 : }
4358 : }
4359 :
4360 240 : int i = 0, j=1;
4361 :
4362 240 : int first_out = -1;
4363 240 : int last = -1;
4364 940 : foreach (ParameterInfo info in parameters) {
4365 355 : if (s is Delegate && info.closure_idx == i) {
4366 5 : var d = (Delegate) s;
4367 5 : d.has_target = true;
4368 5 : d.set_attribute_double ("CCode", "instance_pos", j - 0.1);
4369 5 : info.keep = false;
4370 345 : } else if (info.keep
4371 317 : && !node.array_length_parameters.contains (i)
4372 297 : && !node.closure_parameters.contains (i)
4373 261 : && !node.destroy_parameters.contains (i)) {
4374 247 : info.vala_idx = (float) j;
4375 247 : info.keep = true;
4376 :
4377 : /* interpolate for vala_idx between this and last*/
4378 247 : float last_idx = 0.0F;
4379 247 : if (last != -1) {
4380 88 : last_idx = parameters[last].vala_idx;
4381 : }
4382 260 : for (int k=last+1; k < i; k++) {
4383 13 : parameters[k].vala_idx = last_idx + (((j - last_idx) / (i-last)) * (k-last));
4384 : }
4385 247 : last = i;
4386 247 : j++;
4387 : } else {
4388 98 : info.keep = false;
4389 : // make sure that vala_idx is always set
4390 : // the above if branch does not set vala_idx for
4391 : // hidden parameters at the end of the parameter list
4392 98 : info.vala_idx = (j - 1) + (i - last) * 0.1F;
4393 : }
4394 350 : if (first_out < 0 && info.param.direction == ParameterDirection.OUT) {
4395 350 : first_out = i;
4396 : }
4397 350 : if (first_out >= 0 && info.is_async_result && s is Method) {
4398 1 : var shift = ((Method) s).binding == MemberBinding.INSTANCE ? 1.1 : 0.1;
4399 1 : s.set_attribute_double ("CCode", "async_result_pos", i + shift);
4400 : }
4401 350 : if (s is Delegate && info.is_error) {
4402 1 : if (!s.has_attribute_argument ("CCode", "instance_pos")) {
4403 1 : s.set_attribute_double ("CCode", "error_pos", j - 0.2);
4404 : }
4405 : }
4406 350 : i++;
4407 : }
4408 :
4409 837 : foreach (ParameterInfo info in parameters) {
4410 350 : if (!info.keep) {
4411 103 : continue;
4412 : }
4413 :
4414 : /* add_parameter sets carray_length_parameter_position and cdelegate_target_parameter_position
4415 : so do it first*/
4416 247 : if (s is Callable) {
4417 247 : ((Callable) s).add_parameter (info.param);
4418 : }
4419 :
4420 247 : if (info.array_length_idx != -1) {
4421 20 : if ((info.array_length_idx) >= parameters.size) {
4422 0 : Report.error (info.param.source_reference, "invalid array_length index");
4423 0 : continue;
4424 : }
4425 20 : set_array_ccode (info.param, parameters[info.array_length_idx]);
4426 : }
4427 :
4428 247 : if (info.closure_idx != -1) {
4429 22 : if ((info.closure_idx) >= parameters.size) {
4430 0 : Report.error (info.param.source_reference, "invalid closure index");
4431 0 : continue;
4432 : }
4433 22 : if ("%g".printf (parameters[info.closure_idx].vala_idx) != "%g".printf (info.vala_idx + 0.1)) {
4434 1 : info.param.set_attribute_double ("CCode", "delegate_target_pos", parameters[info.closure_idx].vala_idx);
4435 : }
4436 : }
4437 247 : if (info.destroy_idx != -1) {
4438 14 : if (info.destroy_idx >= parameters.size) {
4439 0 : Report.error (info.param.source_reference, "invalid destroy index");
4440 0 : continue;
4441 : }
4442 14 : if ("%g".printf (parameters[info.destroy_idx].vala_idx) != "%g".printf (info.vala_idx + 0.2)) {
4443 0 : info.param.set_attribute_double ("CCode", "destroy_notify_pos", parameters[info.destroy_idx].vala_idx);
4444 : }
4445 : }
4446 :
4447 494 : if (info.is_async) {
4448 6 : var resolved_type = info.param.variable_type;
4449 12 : if (resolved_type is UnresolvedType) {
4450 6 : var resolved_symbol = resolve_symbol (node.parent, ((UnresolvedType) resolved_type).unresolved_symbol);
4451 6 : if (resolved_symbol is Delegate) {
4452 6 : resolved_type = new DelegateType ((Delegate) resolved_symbol);
4453 : }
4454 : }
4455 :
4456 12 : if (resolved_type is DelegateType) {
4457 6 : var d = ((DelegateType) resolved_type).delegate_symbol;
4458 6 : if (!(d.name == "DestroyNotify" && d.parent_symbol.name == "GLib")) {
4459 6 : info.param.set_attribute_string ("CCode", "scope", "async");
4460 6 : info.param.variable_type.value_owned = (info.closure_idx != -1 && info.destroy_idx != -1);
4461 : }
4462 : }
4463 : } else {
4464 241 : var resolved_type = info.param.variable_type;
4465 241 : if (resolved_type is DelegateType) {
4466 0 : info.param.variable_type.value_owned = (info.closure_idx != -1 && info.destroy_idx != -1);
4467 : }
4468 : }
4469 : }
4470 :
4471 240 : if (return_type is ArrayType && node.return_array_length_idx >= 0) {
4472 11 : set_array_ccode (s, parameters[node.return_array_length_idx]);
4473 : }
4474 :
4475 240 : if (s is Callable) {
4476 240 : ((Callable) s).return_type = return_type;
4477 : }
4478 : }
4479 :
4480 72 : void find_parent (string cname, Node current, ref Node best, ref int match) {
4481 36 : var old_best = best;
4482 36 : if (current.symbol is Namespace) {
4483 598 : foreach (var child in current.members) {
4484 : // symbol is null only for aliases that aren't yet processed
4485 562 : if ((child.symbol == null || is_container (child.symbol)) && cname.has_prefix (child.get_lower_case_cprefix ())) {
4486 0 : find_parent (cname, child, ref best, ref match);
4487 : }
4488 : }
4489 : }
4490 36 : if (best != old_best) {
4491 : // child is better
4492 0 : return;
4493 : }
4494 :
4495 36 : var current_match = current.get_lower_case_cprefix().length;
4496 36 : if (current_match > match) {
4497 36 : match = current_match;
4498 36 : best = current;
4499 : }
4500 : }
4501 :
4502 60 : bool same_gir (Symbol gir_component, Symbol sym) {
4503 60 : var gir_name = gir_component.source_reference.file.gir_namespace;
4504 60 : var gir_version = gir_component.source_reference.file.gir_version;
4505 60 : return "%s-%s".printf (gir_name, gir_version) in sym.source_reference.file.filename;
4506 : }
4507 :
4508 72 : void process_namespace_method (Node ns, Node node) {
4509 : /* transform static methods into instance methods if possible.
4510 : In most of cases this is a .gir fault we are going to fix */
4511 :
4512 36 : var ns_cprefix = ns.get_lower_case_cprefix ();
4513 36 : var method = (Method) node.symbol;
4514 36 : var cname = node.get_cname ();
4515 :
4516 36 : Parameter first_param = null;
4517 36 : if (node.parameters.size > 0) {
4518 33 : first_param = node.parameters[0].param;
4519 : }
4520 57 : if (first_param != null && first_param.direction == ParameterDirection.IN && first_param.variable_type is UnresolvedType) {
4521 : // check if it's a missed instance method (often happens for structs)
4522 24 : var sym = ((UnresolvedType) first_param.variable_type).unresolved_symbol;
4523 24 : var parent = resolve_node (ns, sym);
4524 24 : if (parent != null && same_gir (method, parent.symbol) && parent.parent == ns && is_container (parent.symbol) && cname.has_prefix (parent.get_lower_case_cprefix ())) {
4525 : // instance method
4526 0 : var new_name = method.name.substring (parent.get_lower_case_cprefix().length - ns_cprefix.length);
4527 0 : if (parent.lookup (new_name) == null) {
4528 0 : ns.remove_member (node);
4529 0 : node.name = new_name;
4530 0 : node.parameters.remove_at (0);
4531 0 : node.return_array_length_idx--;
4532 0 : method.name = new_name;
4533 0 : method.binding = MemberBinding.INSTANCE;
4534 0 : parent.add_member (node);
4535 : }
4536 0 : return;
4537 : }
4538 : }
4539 :
4540 36 : int match = 0;
4541 36 : Node parent = ns;
4542 36 : find_parent (cname, ns, ref parent, ref match);
4543 36 : var new_name = method.name.substring (parent.get_lower_case_cprefix().length - ns_cprefix.length);
4544 36 : if (same_gir (method, parent.symbol) && parent.lookup (new_name) == null) {
4545 0 : ns.remove_member (node);
4546 0 : node.name = new_name;
4547 0 : method.name = new_name;
4548 0 : parent.add_member (node);
4549 : }
4550 : }
4551 :
4552 65 : void process_virtual_method_field (Node node, Delegate d, UnresolvedSymbol gtype_struct_for) {
4553 34 : var gtype_node = resolve_node (node.parent, gtype_struct_for);
4554 34 : if (gtype_node == null || !(gtype_node.symbol is ObjectTypeSymbol)) {
4555 0 : Report.error (gtype_struct_for.source_reference, "Unknown symbol `%s' for virtual method field `%s'", gtype_struct_for.to_string (), node.to_string ());
4556 : }
4557 34 : var nodes = gtype_node.lookup_all (d.name);
4558 34 : if (nodes == null) {
4559 3 : return;
4560 : }
4561 135 : foreach (var n in nodes) {
4562 52 : if (node != n) {
4563 52 : n.process (this);
4564 : }
4565 : }
4566 111 : foreach (var n in nodes) {
4567 52 : if (n.merged) {
4568 24 : continue;
4569 : }
4570 28 : var sym = n.symbol;
4571 28 : if (sym is Signal) {
4572 0 : var sig = (Signal) sym;
4573 0 : sig.is_virtual = true;
4574 0 : assume_parameter_names (sig, d, true);
4575 28 : } else if (sym is Property) {
4576 0 : var prop = (Property) sym;
4577 0 : prop.is_virtual = true;
4578 : }
4579 : }
4580 : }
4581 :
4582 28 : void process_async_method (Node node) {
4583 14 : var m = (Method) node.symbol;
4584 :
4585 : // TODO: async methods with out-parameters before in-parameters are not supported
4586 14 : bool requires_pointer = false;
4587 28 : foreach (var param in m.get_parameters ()) {
4588 7 : if (param.direction == ParameterDirection.IN) {
4589 : requires_pointer = true;
4590 1 : } else if (requires_pointer) {
4591 1 : param.direction = ParameterDirection.IN;
4592 1 : param.variable_type.nullable = false;
4593 1 : param.variable_type = new PointerType (param.variable_type);
4594 1 : Report.warning (param.source_reference, "Synchronous out-parameters are not supported in async methods");
4595 : }
4596 : }
4597 :
4598 : string finish_method_base;
4599 14 : if (m.name == null) {
4600 0 : assert (m is CreationMethod);
4601 0 : finish_method_base = "new";
4602 14 : } else if (m.name.has_suffix ("_async")) {
4603 12 : finish_method_base = m.name.substring (0, m.name.length - "_async".length);
4604 : } else {
4605 4 : finish_method_base = m.name;
4606 : }
4607 14 : var finish_method_node = node.parent.lookup (finish_method_base + "_finish");
4608 :
4609 : // check if the method is using non-standard finish method name
4610 14 : if (finish_method_node == null) {
4611 0 : var method_cname = node.get_finish_cname ();
4612 0 : foreach (var n in node.parent.members) {
4613 0 : if (n.symbol is Method && n.get_cname () == method_cname) {
4614 0 : finish_method_node = n;
4615 0 : break;
4616 : }
4617 : }
4618 : }
4619 :
4620 14 : Method method = m;
4621 :
4622 28 : if (finish_method_node != null && finish_method_node.symbol is Method) {
4623 14 : finish_method_node.process (this);
4624 14 : var finish_method = (Method) finish_method_node.symbol;
4625 27 : if (finish_method is CreationMethod) {
4626 1 : method = new CreationMethod (((CreationMethod) finish_method).class_name, null, m.source_reference);
4627 1 : method.access = m.access;
4628 1 : method.coroutine = true;
4629 1 : method.has_construct_function = finish_method.has_construct_function;
4630 :
4631 : // cannot use List.copy()
4632 : // as it returns a list of unowned elements
4633 1 : foreach (Attribute a in m.attributes) {
4634 0 : method.add_attribute (a);
4635 : }
4636 :
4637 1 : method.set_attribute_string ("CCode", "cname", node.get_cname ());
4638 1 : if (finish_method_base == "new") {
4639 1 : method.name = null;
4640 0 : } else if (finish_method_base.has_prefix ("new_")) {
4641 0 : method.name = m.name.substring ("new_".length);
4642 : }
4643 3 : foreach (var param in m.get_parameters ()) {
4644 1 : method.add_parameter (param);
4645 : }
4646 2 : node.symbol = method;
4647 : } else {
4648 13 : method.return_type = finish_method.return_type.copy ();
4649 13 : var a = finish_method.get_attribute ("CCode");
4650 1 : if (a != null && a.has_argument ("array_length")) {
4651 0 : method.set_attribute_bool ("CCode", "array_length", a.get_bool ("array_length"));
4652 : }
4653 13 : if (a != null && a.has_argument ("array_null_terminated")) {
4654 0 : method.set_attribute_bool ("CCode", "array_null_terminated", a.get_bool ("array_null_terminated"));
4655 : }
4656 : }
4657 :
4658 14 : method.copy_attribute_double (finish_method, "CCode", "async_result_pos");
4659 :
4660 52 : foreach (var param in finish_method.get_parameters ()) {
4661 24 : if (param.direction == ParameterDirection.OUT) {
4662 5 : var async_param = param.copy ();
4663 5 : if (method.scope.lookup (param.name) != null) {
4664 : // parameter name conflict
4665 0 : async_param.name += "_out";
4666 : }
4667 5 : method.add_parameter (async_param);
4668 : }
4669 : }
4670 :
4671 14 : var error_types = new ArrayList<DataType> ();
4672 14 : finish_method.get_error_types (error_types, method.source_reference);
4673 26 : foreach (DataType error_type in error_types) {
4674 6 : method.add_error_type (error_type);
4675 : }
4676 14 : finish_method_node.processed = true;
4677 14 : finish_method_node.merged = true;
4678 : }
4679 : }
4680 :
4681 : /* Hash and equal functions */
4682 :
4683 : static uint unresolved_symbol_hash (UnresolvedSymbol? sym) {
4684 107509 : var builder = new StringBuilder ();
4685 315625 : while (sym != null) {
4686 208116 : builder.append (sym.name);
4687 208116 : sym = sym.inner;
4688 : }
4689 107509 : return builder.str.hash ();
4690 : }
4691 :
4692 : static bool unresolved_symbol_equal (UnresolvedSymbol? sym1, UnresolvedSymbol? sym2) {
4693 46091 : while (sym1 != sym2) {
4694 23046 : if (sym1 == null || sym2 == null) {
4695 : return false;
4696 : }
4697 23046 : if (sym1.name != sym2.name) {
4698 : return false;
4699 : }
4700 23046 : sym1 = sym1.inner;
4701 23046 : sym2 = sym2.inner;
4702 : }
4703 : return true;
4704 : }
4705 :
4706 : /* Helper methods */
4707 :
4708 11 : Node? base_interface_property (Node prop_node) {
4709 11 : var cl = prop_node.parent.symbol as Class;
4710 11 : if (cl == null) {
4711 0 : return null;
4712 : }
4713 :
4714 33 : foreach (DataType type in cl.get_base_types ()) {
4715 12 : if (!(type is UnresolvedType)) {
4716 0 : continue;
4717 : }
4718 :
4719 12 : var base_node = resolve_node (prop_node.parent, ((UnresolvedType) type).unresolved_symbol);
4720 12 : if (base_node != null && base_node.symbol is Interface) {
4721 1 : var base_prop_node = base_node.lookup (prop_node.name);
4722 1 : if (base_prop_node != null && base_prop_node.symbol is Property) {
4723 1 : var base_property = (Property) base_prop_node.symbol;
4724 1 : if (base_property.is_abstract || base_property.is_virtual) {
4725 : // found
4726 1 : return base_prop_node;
4727 : }
4728 : }
4729 : }
4730 : }
4731 :
4732 10 : return null;
4733 : }
4734 :
4735 : }
|