Insert "%s" argument in printf calls with non-literal format string
[vala-lang.git] / vala / valamethod.vala
blobd64326b87f9333e9801f0cb7a5a3aafa0d86836e
1 /* valamethod.vala
3 * Copyright (C) 2006-2009 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using GLib;
26 using Gee;
28 /**
29 * Represents a type or namespace method.
31 public class Vala.Method : Member {
32 Gee.List<TypeParameter> type_parameters = new ArrayList<TypeParameter> ();
34 public const string DEFAULT_SENTINEL = "NULL";
36 /**
37 * The return type of this method.
39 public DataType return_type {
40 get { return _return_type; }
41 set {
42 _return_type = value;
43 _return_type.parent_node = this;
47 public Block body {
48 get { return _body; }
49 set {
50 _body = value;
51 if (_body != null) {
52 _body.owner = scope;
57 public BasicBlock entry_block { get; set; }
59 public BasicBlock exit_block { get; set; }
61 /**
62 * Specifies whether this method may only be called with an instance of
63 * the contained type.
65 public MemberBinding binding { get; set; default = MemberBinding.INSTANCE; }
67 /**
68 * The name of the vfunc of this method as it is used in C code.
70 public string vfunc_name {
71 get {
72 if (_vfunc_name == null) {
73 _vfunc_name = this.name;
75 return _vfunc_name;
77 set {
78 _vfunc_name = value;
82 /**
83 * The sentinel to use for terminating variable length argument lists.
85 public string sentinel {
86 get {
87 if (_sentinel == null) {
88 return DEFAULT_SENTINEL;
91 return _sentinel;
94 set {
95 _sentinel = value;
99 /**
100 * Specifies whether this method is abstract. Abstract methods have no
101 * body, may only be specified within abstract classes, and must be
102 * overriden by derived non-abstract classes.
104 public bool is_abstract { get; set; }
107 * Specifies whether this method is virtual. Virtual methods may be
108 * overridden by derived classes.
110 public bool is_virtual { get; set; }
113 * Specifies whether this method overrides a virtual or abstract method
114 * of a base type.
116 public bool overrides { get; set; }
119 * Specifies whether this method should be inlined.
121 public bool is_inline { get; set; }
124 * Specifies whether the C method returns a new instance pointer which
125 * may be different from the previous instance pointer. Only valid for
126 * imported methods.
128 public bool returns_modified_pointer { get; set; }
131 * Specifies the virtual or abstract method this method overrides.
132 * Reference must be weak as virtual and abstract methods set
133 * base_method to themselves.
135 public Method base_method {
136 get {
137 find_base_methods ();
138 return _base_method;
143 * Specifies the abstract interface method this method implements.
145 public Method base_interface_method {
146 get {
147 find_base_methods ();
148 return _base_interface_method;
152 public bool entry_point { get; private set; }
155 * Specifies the generated `this' parameter for instance methods.
157 public FormalParameter this_parameter { get; set; }
160 * Specifies the generated `result' variable for postconditions.
162 public LocalVariable result_var { get; set; }
165 * Specifies the position of the instance parameter in the C function.
167 public double cinstance_parameter_position { get; set; }
170 * Specifies the position of the array length out parameter in the C
171 * function.
173 public double carray_length_parameter_position { get; set; }
176 * Specifies the position of the delegate target out parameter in the C
177 * function.
179 public double cdelegate_target_parameter_position { get; set; }
182 * Specifies whether the array length should be returned implicitly
183 * if the return type is an array.
185 public bool no_array_length { get; set; }
188 * Specifies whether the array is null terminated.
190 public bool array_null_terminated { get; set; }
193 * Specified a custom type for the array length parameter.
195 public string? array_length_type { get; set; default = null; }
198 * Specifies whether this method expects printf-style format arguments.
200 public bool printf_format { get; set; }
203 * Specifies whether this method expects scanf-style format arguments.
205 public bool scanf_format { get; set; }
208 * Specifies whether a new function without a GType parameter is
209 * available. This is only applicable to creation methods.
211 public bool has_new_function { get; set; default = true; }
214 * Specifies whether a construct function with a GType parameter is
215 * available. This is only applicable to creation methods.
217 public bool has_construct_function { get; set; default = true; }
219 public bool has_generic_type_parameter { get; set; }
221 public double generic_type_parameter_position { get; set; }
223 public weak Signal signal_reference { get; set; }
225 public bool closure { get; set; }
227 public bool coroutine { get; set; }
229 public bool is_async_callback { get; set; }
231 private Gee.List<FormalParameter> parameters = new ArrayList<FormalParameter> ();
232 private string cname;
233 private string _vfunc_name;
234 private string _sentinel;
235 private Gee.List<Expression> preconditions = new ArrayList<Expression> ();
236 private Gee.List<Expression> postconditions = new ArrayList<Expression> ();
237 private DataType _return_type;
238 private Block _body;
240 private weak Method _base_method;
241 private Method _base_interface_method;
242 private bool base_methods_valid;
244 Method? callback_method;
246 // only valid for closures
247 Gee.List<LocalVariable> captured_variables;
250 * Creates a new method.
252 * @param name method name
253 * @param return_type method return type
254 * @param source reference to source code
255 * @return newly created method
257 public Method (string? name, DataType return_type, SourceReference? source_reference = null, Comment? comment = null) {
258 base (name, source_reference, comment);
259 this.return_type = return_type;
261 carray_length_parameter_position = -3;
262 cdelegate_target_parameter_position = -3;
266 * Appends parameter to this method.
268 * @param param a formal parameter
270 public void add_parameter (FormalParameter param) {
271 // default C parameter position
272 param.cparameter_position = parameters.size + 1;
273 param.carray_length_parameter_position = param.cparameter_position + 0.1;
274 param.cdelegate_target_parameter_position = param.cparameter_position + 0.1;
276 parameters.add (param);
277 if (!param.ellipsis) {
278 scope.add (param.name, param);
282 public Gee.List<FormalParameter> get_parameters () {
283 return new ReadOnlyList<FormalParameter> (parameters);
287 * Remove all parameters from this method.
289 public void clear_parameters () {
290 foreach (FormalParameter param in parameters) {
291 if (!param.ellipsis) {
292 scope.remove (param.name);
295 parameters.clear ();
298 public override void accept (CodeVisitor visitor) {
299 visitor.visit_method (this);
302 public override void accept_children (CodeVisitor visitor) {
303 if (return_type != null) {
304 return_type.accept (visitor);
307 foreach (FormalParameter param in parameters) {
308 param.accept (visitor);
311 foreach (DataType error_type in get_error_types ()) {
312 error_type.accept (visitor);
315 if (result_var != null) {
316 result_var.accept (visitor);
319 foreach (Expression precondition in preconditions) {
320 precondition.accept (visitor);
323 foreach (Expression postcondition in postconditions) {
324 postcondition.accept (visitor);
327 if (body != null) {
328 body.accept (visitor);
333 * Returns the interface name of this method as it is used in C code.
335 * @return the name to be used in C code
337 public string get_cname () {
338 if (cname == null) {
339 cname = get_default_cname ();
341 return cname;
344 public string get_finish_cname () {
345 assert (coroutine);
346 string result = get_cname ();
347 if (result.has_suffix ("_async")) {
348 result = result.substring (0, result.length - "_async".length);
350 result += "_finish";
351 return result;
355 * Returns the default interface name of this method as it is used in C
356 * code.
358 * @return the name to be used in C code by default
360 public virtual string get_default_cname () {
361 if (name == "main" && parent_symbol.name == null) {
362 // avoid conflict with generated main function
363 return "_main";
364 } else if (name.has_prefix ("_")) {
365 return "_%s%s".printf (parent_symbol.get_lower_case_cprefix (), name.offset (1));
366 } else {
367 return "%s%s".printf (parent_symbol.get_lower_case_cprefix (), name);
372 * Returns the implementation name of this data type as it is used in C
373 * code.
375 * @return the name to be used in C code
377 public virtual string get_real_cname () {
378 if (base_method != null || base_interface_method != null) {
379 return "%sreal_%s".printf (parent_symbol.get_lower_case_cprefix (), name);
380 } else {
381 return get_cname ();
385 public string get_finish_real_cname () {
386 assert (coroutine);
387 string result = get_real_cname ();
388 if (result.has_suffix ("_async")) {
389 result = result.substring (0, result.length - "_async".length);
391 result += "_finish";
392 return result;
395 public string get_finish_vfunc_name () {
396 assert (coroutine);
397 string result = vfunc_name;
398 if (result.has_suffix ("_async")) {
399 result = result.substring (0, result.length - "_async".length);
401 result += "_finish";
402 return result;
406 * Sets the name of this method as it is used in C code.
408 * @param cname the name to be used in C code
410 public void set_cname (string cname) {
411 this.cname = cname;
414 private void process_ccode_attribute (Attribute a) {
415 if (a.has_argument ("cname")) {
416 set_cname (a.get_string ("cname"));
418 if (a.has_argument ("cheader_filename")) {
419 var val = a.get_string ("cheader_filename");
420 foreach (string filename in val.split (",")) {
421 add_cheader_filename (filename);
424 if (a.has_argument ("vfunc_name")) {
425 this.vfunc_name = a.get_string ("vfunc_name");
427 if (a.has_argument ("sentinel")) {
428 this.sentinel = a.get_string ("sentinel");
430 if (a.has_argument ("instance_pos")) {
431 cinstance_parameter_position = a.get_double ("instance_pos");
433 if (a.has_argument ("array_length")) {
434 no_array_length = !a.get_bool ("array_length");
436 if (a.has_argument ("array_length_type")) {
437 array_length_type = a.get_string ("array_length_type");
439 if (a.has_argument ("array_null_terminated")) {
440 array_null_terminated = a.get_bool ("array_null_terminated");
442 if (a.has_argument ("array_length_pos")) {
443 carray_length_parameter_position = a.get_double ("array_length_pos");
445 if (a.has_argument ("delegate_target_pos")) {
446 cdelegate_target_parameter_position = a.get_double ("delegate_target_pos");
448 if (a.has_argument ("has_new_function")) {
449 has_new_function = a.get_bool ("has_new_function");
451 if (a.has_argument ("has_construct_function")) {
452 has_construct_function = a.get_bool ("has_construct_function");
454 if (a.has_argument ("generic_type_pos")) {
455 has_generic_type_parameter = true;
456 generic_type_parameter_position = a.get_double ("generic_type_pos");
461 * Process all associated attributes.
463 public void process_attributes () {
464 foreach (Attribute a in attributes) {
465 if (a.name == "CCode") {
466 process_ccode_attribute (a);
467 } else if (a.name == "ReturnsModifiedPointer") {
468 returns_modified_pointer = true;
469 } else if (a.name == "FloatingReference") {
470 return_type.floating_reference = true;
471 } else if (a.name == "PrintfFormat") {
472 printf_format = true;
473 } else if (a.name == "ScanfFormat") {
474 scanf_format = true;
480 * Checks whether the parameters and return type of this method are
481 * compatible with the specified method
483 * @param base_method a method
484 * @param invalid_match error string about which check failed
485 * @return true if the specified method is compatible to this method
487 public bool compatible (Method base_method, out string? invalid_match) {
488 if (binding != base_method.binding) {
489 invalid_match = "incompatible binding";
490 return false;
493 ObjectType object_type = null;
494 if (parent_symbol is ObjectTypeSymbol) {
495 object_type = new ObjectType ((ObjectTypeSymbol) parent_symbol);
496 foreach (TypeParameter type_parameter in object_type.type_symbol.get_type_parameters ()) {
497 var type_arg = new GenericType (type_parameter);
498 type_arg.value_owned = true;
499 object_type.add_type_argument (type_arg);
503 var actual_base_type = base_method.return_type.get_actual_type (object_type, null, this);
504 if (!return_type.equals (actual_base_type)) {
505 invalid_match = "incompatible return type";
506 return false;
509 Iterator<FormalParameter> method_params_it = parameters.iterator ();
510 int param_index = 1;
511 foreach (FormalParameter base_param in base_method.parameters) {
512 /* this method may not expect less arguments */
513 if (!method_params_it.next ()) {
514 invalid_match = "too few parameters";
515 return false;
518 actual_base_type = base_param.parameter_type.get_actual_type (object_type, null, this);
519 if (!actual_base_type.equals (method_params_it.get ().parameter_type)) {
520 invalid_match = "incompatible type of parameter %d".printf (param_index);
521 return false;
523 param_index++;
526 /* this method may not expect more arguments */
527 if (method_params_it.next ()) {
528 invalid_match = "too many parameters";
529 return false;
532 /* this method may throw less but not more errors than the base method */
533 foreach (DataType method_error_type in get_error_types ()) {
534 bool match = false;
535 foreach (DataType base_method_error_type in base_method.get_error_types ()) {
536 if (method_error_type.compatible (base_method_error_type)) {
537 match = true;
538 break;
542 if (!match) {
543 invalid_match = "incompatible error type `%s'".printf (method_error_type.to_string ());
544 return false;
548 return true;
552 * Appends the specified parameter to the list of type parameters.
554 * @param p a type parameter
556 public void add_type_parameter (TypeParameter p) {
557 type_parameters.add (p);
558 scope.add (p.name, p);
562 * Returns a copy of the type parameter list.
564 * @return list of type parameters
566 public Gee.List<TypeParameter> get_type_parameters () {
567 return new ReadOnlyList<TypeParameter> (type_parameters);
570 public int get_type_parameter_index (string name) {
571 int i = 0;
572 foreach (TypeParameter parameter in type_parameters) {
573 if (parameter.name == name) {
574 return i;
576 i++;
578 return -1;
582 * Adds a precondition to this method.
584 * @param precondition a boolean precondition expression
586 public void add_precondition (Expression precondition) {
587 preconditions.add (precondition);
588 precondition.parent_node = this;
592 * Returns a copy of the list of preconditions of this method.
594 * @return list of preconditions
596 public Gee.List<Expression> get_preconditions () {
597 return new ReadOnlyList<Expression> (preconditions);
601 * Adds a postcondition to this method.
603 * @param postcondition a boolean postcondition expression
605 public void add_postcondition (Expression postcondition) {
606 postconditions.add (postcondition);
607 postcondition.parent_node = this;
611 * Returns a copy of the list of postconditions of this method.
613 * @return list of postconditions
615 public Gee.List<Expression> get_postconditions () {
616 return new ReadOnlyList<Expression> (postconditions);
619 public override void replace_type (DataType old_type, DataType new_type) {
620 if (return_type == old_type) {
621 return_type = new_type;
622 return;
624 var error_types = get_error_types ();
625 for (int i = 0; i < error_types.size; i++) {
626 if (error_types[i] == old_type) {
627 error_types[i] = new_type;
628 return;
633 private void find_base_methods () {
634 if (base_methods_valid) {
635 return;
638 if (parent_symbol is Class) {
639 if (!(this is CreationMethod)) {
640 find_base_interface_method ((Class) parent_symbol);
641 if (is_virtual || is_abstract || overrides) {
642 find_base_class_method ((Class) parent_symbol);
645 } else if (parent_symbol is Interface) {
646 if (is_virtual || is_abstract) {
647 _base_interface_method = this;
651 base_methods_valid = true;
654 private void find_base_class_method (Class cl) {
655 var sym = cl.scope.lookup (name);
656 if (sym is Method) {
657 var base_method = (Method) sym;
658 if (base_method.is_abstract || base_method.is_virtual) {
659 string invalid_match;
660 if (!compatible (base_method, out invalid_match)) {
661 error = true;
662 Report.error (source_reference, "overriding method `%s' is incompatible with base method `%s': %s.".printf (get_full_name (), base_method.get_full_name (), invalid_match));
663 return;
666 _base_method = base_method;
667 return;
669 } else if (sym is Signal) {
670 var sig = (Signal) sym;
671 if (sig.is_virtual) {
672 var base_method = sig.default_handler;
673 string invalid_match;
674 if (!compatible (base_method, out invalid_match)) {
675 error = true;
676 Report.error (source_reference, "overriding method `%s' is incompatible with base method `%s': %s.".printf (get_full_name (), base_method.get_full_name (), invalid_match));
677 return;
680 _base_method = base_method;
681 return;
685 if (cl.base_class != null) {
686 find_base_class_method (cl.base_class);
690 private void find_base_interface_method (Class cl) {
691 // FIXME report error if multiple possible base methods are found
692 foreach (DataType type in cl.get_base_types ()) {
693 if (type.data_type is Interface) {
694 var sym = type.data_type.scope.lookup (name);
695 if (sym is Method) {
696 var base_method = (Method) sym;
697 if (base_method.is_abstract || base_method.is_virtual) {
698 string invalid_match;
699 if (!compatible (base_method, out invalid_match)) {
700 error = true;
701 Report.error (source_reference, "overriding method `%s' is incompatible with base method `%s': %s.".printf (get_full_name (), base_method.get_full_name (), invalid_match));
702 return;
705 _base_interface_method = base_method;
706 return;
713 public override bool check (SemanticAnalyzer analyzer) {
714 if (checked) {
715 return !error;
718 checked = true;
720 process_attributes ();
722 if (is_abstract) {
723 if (parent_symbol is Class) {
724 var cl = (Class) parent_symbol;
725 if (!cl.is_abstract) {
726 error = true;
727 Report.error (source_reference, "Abstract methods may not be declared in non-abstract classes");
728 return false;
730 } else if (!(parent_symbol is Interface)) {
731 error = true;
732 Report.error (source_reference, "Abstract methods may not be declared outside of classes and interfaces");
733 return false;
735 } else if (is_virtual) {
736 if (!(parent_symbol is Class) && !(parent_symbol is Interface)) {
737 error = true;
738 Report.error (source_reference, "Virtual methods may not be declared outside of classes and interfaces");
739 return false;
742 if (parent_symbol is Class) {
743 var cl = (Class) parent_symbol;
744 if (cl.is_compact) {
745 Report.error (source_reference, "Virtual methods may not be declared in compact classes");
746 return false;
749 } else if (overrides) {
750 if (!(parent_symbol is Class)) {
751 error = true;
752 Report.error (source_reference, "Methods may not be overridden outside of classes");
753 return false;
757 if (is_abstract && body != null) {
758 Report.error (source_reference, "Abstract methods cannot have bodies");
759 } else if ((is_abstract || is_virtual) && external && !external_package && !parent_symbol.external) {
760 Report.error (source_reference, "Extern methods cannot be abstract or virtual");
761 } else if (external && body != null) {
762 Report.error (source_reference, "Extern methods cannot have bodies");
763 } else if (!is_abstract && !external && !external_package && body == null) {
764 Report.error (source_reference, "Non-abstract, non-extern methods must have bodies");
767 if (coroutine && !external_package && !analyzer.context.has_package ("gio-2.0")) {
768 error = true;
769 Report.error (source_reference, "gio-2.0 package required for async methods");
770 return false;
773 var old_source_file = analyzer.current_source_file;
774 var old_symbol = analyzer.current_symbol;
776 if (source_reference != null) {
777 analyzer.current_source_file = source_reference.file;
779 analyzer.current_symbol = this;
781 return_type.check (analyzer);
783 var init_attr = get_attribute ("ModuleInit");
784 if (init_attr != null) {
785 source_reference.file.context.module_init_method = this;
788 if (return_type != null) {
789 return_type.check (analyzer);
792 foreach (FormalParameter param in parameters) {
793 param.check (analyzer);
796 foreach (DataType error_type in get_error_types ()) {
797 error_type.check (analyzer);
800 if (result_var != null) {
801 result_var.check (analyzer);
804 foreach (Expression precondition in preconditions) {
805 precondition.check (analyzer);
808 foreach (Expression postcondition in postconditions) {
809 postcondition.check (analyzer);
812 if (body != null) {
813 body.check (analyzer);
816 analyzer.current_source_file = old_source_file;
817 analyzer.current_symbol = old_symbol;
819 if (analyzer.current_struct != null) {
820 if (is_abstract || is_virtual || overrides) {
821 Report.error (source_reference, "A struct member `%s' cannot be marked as override, virtual, or abstract".printf (get_full_name ()));
822 return false;
824 } else if (overrides && base_method == null) {
825 Report.error (source_reference, "%s: no suitable method found to override".printf (get_full_name ()));
828 if (!external_package && !overrides && !hides && get_hidden_member () != null) {
829 Report.warning (source_reference, "%s hides inherited method `%s'. Use the `new' keyword if hiding was intentional".printf (get_full_name (), get_hidden_member ().get_full_name ()));
832 // check whether return type is at least as accessible as the method
833 if (!analyzer.is_type_accessible (this, return_type)) {
834 error = true;
835 Report.error (source_reference, "return type `%s` is less accessible than method `%s`".printf (return_type.to_string (), get_full_name ()));
836 return false;
839 foreach (Expression precondition in get_preconditions ()) {
840 if (precondition.error) {
841 // if there was an error in the precondition, skip this check
842 error = true;
843 return false;
846 if (!precondition.value_type.compatible (analyzer.bool_type)) {
847 error = true;
848 Report.error (precondition.source_reference, "Precondition must be boolean");
849 return false;
853 foreach (Expression postcondition in get_postconditions ()) {
854 if (postcondition.error) {
855 // if there was an error in the postcondition, skip this check
856 error = true;
857 return false;
860 if (!postcondition.value_type.compatible (analyzer.bool_type)) {
861 error = true;
862 Report.error (postcondition.source_reference, "Postcondition must be boolean");
863 return false;
867 // check that all errors that can be thrown in the method body are declared
868 if (body != null) {
869 foreach (DataType body_error_type in body.get_error_types ()) {
870 bool can_propagate_error = false;
871 foreach (DataType method_error_type in get_error_types ()) {
872 if (body_error_type.compatible (method_error_type)) {
873 can_propagate_error = true;
876 if (!can_propagate_error && !((ErrorType) body_error_type).dynamic_error) {
877 Report.warning (body_error_type.source_reference, "unhandled error `%s'".printf (body_error_type.to_string()));
882 if (is_possible_entry_point (analyzer)) {
883 if (analyzer.context.entry_point != null) {
884 error = true;
885 Report.error (source_reference, "program already has an entry point `%s'".printf (analyzer.context.entry_point.get_full_name ()));
886 return false;
888 entry_point = true;
889 analyzer.context.entry_point = this;
891 if (tree_can_fail) {
892 Report.error (source_reference, "\"main\" method cannot throw errors");
896 return !error;
899 bool is_possible_entry_point (SemanticAnalyzer analyzer) {
900 if (external_package) {
901 return false;
904 if (analyzer.context.entry_point_name == null) {
905 if (name == null || name != "main") {
906 // method must be called "main"
907 return false;
909 } else {
910 // custom entry point name
911 if (get_full_name () != analyzer.context.entry_point_name) {
912 return false;
916 if (binding == MemberBinding.INSTANCE) {
917 // method must be static
918 return false;
921 if (return_type is VoidType) {
922 } else if (return_type.data_type == analyzer.int_type.data_type) {
923 } else {
924 // return type must be void or int
925 return false;
928 var params = get_parameters ();
929 if (params.size == 0) {
930 // method may have no parameters
931 return true;
934 if (params.size > 1) {
935 // method must not have more than one parameter
936 return false;
939 Iterator<FormalParameter> params_it = params.iterator ();
940 params_it.next ();
941 var param = params_it.get ();
943 if (param.direction == ParameterDirection.OUT) {
944 // parameter must not be an out parameter
945 return false;
948 if (!(param.parameter_type is ArrayType)) {
949 // parameter must be an array
950 return false;
953 var array_type = (ArrayType) param.parameter_type;
954 if (array_type.element_type.data_type != analyzer.string_type.data_type) {
955 // parameter must be an array of strings
956 return false;
959 return true;
962 public int get_required_arguments () {
963 int n = 0;
964 foreach (var param in parameters) {
965 if (param.default_expression != null || param.ellipsis) {
966 // optional argument
967 break;
969 n++;
971 return n;
974 public Method get_callback_method () {
975 assert (this.coroutine);
977 if (callback_method == null) {
978 var bool_type = new BooleanType ((Struct) CodeContext.get ().root.scope.lookup ("bool"));
979 bool_type.value_owned = true;
980 callback_method = new Method ("callback", bool_type, source_reference);
981 callback_method.access = SymbolAccessibility.PUBLIC;
982 callback_method.external = true;
983 callback_method.binding = MemberBinding.INSTANCE;
984 callback_method.owner = scope;
985 callback_method.is_async_callback = true;
986 callback_method.set_cname (get_real_cname () + "_co");
988 return callback_method;
991 public Gee.List<FormalParameter> get_async_begin_parameters () {
992 assert (this.coroutine);
994 var glib_ns = CodeContext.get ().root.scope.lookup ("GLib");
996 var params = new ArrayList<FormalParameter> ();
997 foreach (var param in parameters) {
998 if (param.direction == ParameterDirection.IN) {
999 params.add (param);
1003 var callback_type = new DelegateType ((Delegate) glib_ns.scope.lookup ("AsyncReadyCallback"));
1004 callback_type.nullable = true;
1006 var callback_param = new FormalParameter ("_callback_", callback_type);
1007 callback_param.default_expression = new NullLiteral (source_reference);
1008 callback_param.cparameter_position = -1;
1009 callback_param.cdelegate_target_parameter_position = -0.9;
1011 params.add (callback_param);
1013 return params;
1016 public Gee.List<FormalParameter> get_async_end_parameters () {
1017 assert (this.coroutine);
1019 var params = new ArrayList<FormalParameter> ();
1021 var glib_ns = CodeContext.get ().root.scope.lookup ("GLib");
1022 var result_type = new ObjectType ((ObjectTypeSymbol) glib_ns.scope.lookup ("AsyncResult"));
1024 var result_param = new FormalParameter ("_res_", result_type);
1025 result_param.cparameter_position = 0.1;
1026 params.add (result_param);
1028 foreach (var param in parameters) {
1029 if (param.direction == ParameterDirection.OUT) {
1030 params.add (param);
1034 return params;
1037 public void add_captured_variable (LocalVariable local) {
1038 assert (this.closure);
1040 if (captured_variables == null) {
1041 captured_variables = new ArrayList<LocalVariable> ();
1043 captured_variables.add (local);
1046 public void get_captured_variables (Collection<LocalVariable> variables) {
1047 if (captured_variables != null) {
1048 foreach (var local in captured_variables) {
1049 variables.add (local);
1055 // vim:sw=8 noet