girparser: Fix parameter index calculation
[vala-lang.git] / vala / valamethod.vala
blob8b75efd75e6c2b0ec7c574bfcad068972294abcd
1 /* valamethod.vala
3 * Copyright (C) 2006-2010 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;
27 /**
28 * Represents a type or namespace method.
30 public class Vala.Method : Member {
31 List<TypeParameter> type_parameters = new ArrayList<TypeParameter> ();
33 public const string DEFAULT_SENTINEL = "NULL";
35 /**
36 * The return type of this method.
38 public DataType return_type {
39 get { return _return_type; }
40 set {
41 _return_type = value;
42 _return_type.parent_node = this;
46 public Block body {
47 get { return _body; }
48 set {
49 _body = value;
50 if (_body != null) {
51 _body.owner = scope;
56 public BasicBlock entry_block { get; set; }
58 public BasicBlock return_block { get; set; }
60 public BasicBlock exit_block { get; set; }
62 /**
63 * Specifies whether this method may only be called with an instance of
64 * the contained type.
66 public MemberBinding binding { get; set; default = MemberBinding.INSTANCE; }
68 /**
69 * The name of the vfunc of this method as it is used in C code.
71 public string vfunc_name {
72 get {
73 if (_vfunc_name == null) {
74 _vfunc_name = this.name;
76 return _vfunc_name;
78 set {
79 _vfunc_name = value;
83 /**
84 * The sentinel to use for terminating variable length argument lists.
86 public string sentinel {
87 get {
88 if (_sentinel == null) {
89 return DEFAULT_SENTINEL;
92 return _sentinel;
95 set {
96 _sentinel = value;
101 * Specifies whether this method is abstract. Abstract methods have no
102 * body, may only be specified within abstract classes, and must be
103 * overriden by derived non-abstract classes.
105 public bool is_abstract { get; set; }
108 * Specifies whether this method is virtual. Virtual methods may be
109 * overridden by derived classes.
111 public bool is_virtual { get; set; }
114 * Specifies whether this method overrides a virtual or abstract method
115 * of a base type.
117 public bool overrides { get; set; }
120 * Specifies whether this method should be inlined.
122 public bool is_inline { get; set; }
124 public bool returns_floating_reference { get; set; }
127 * Specifies whether the C method returns a new instance pointer which
128 * may be different from the previous instance pointer. Only valid for
129 * imported methods.
131 public bool returns_modified_pointer { get; set; }
134 * Specifies the virtual or abstract method this method overrides.
135 * Reference must be weak as virtual and abstract methods set
136 * base_method to themselves.
138 public Method base_method {
139 get {
140 find_base_methods ();
141 return _base_method;
146 * Specifies the abstract interface method this method implements.
148 public Method base_interface_method {
149 get {
150 find_base_methods ();
151 return _base_interface_method;
155 public bool entry_point { get; private set; }
158 * Specifies the generated `this` parameter for instance methods.
160 public FormalParameter this_parameter { get; set; }
163 * Specifies the generated `result` variable for postconditions.
165 public LocalVariable result_var { get; set; }
168 * Specifies the position of the instance parameter in the C function.
170 public double cinstance_parameter_position { get; set; }
173 * Specifies the position of the array length out parameter in the C
174 * function.
176 public double carray_length_parameter_position { get; set; }
179 * Specifies the position of the delegate target out parameter in the C
180 * function.
182 public double cdelegate_target_parameter_position { get; set; }
185 * Specifies whether the array length should be returned implicitly
186 * if the return type is an array.
188 public bool no_array_length { get; set; }
191 * Specifies whether the array is null terminated.
193 public bool array_null_terminated { get; set; }
196 * Specified a custom type for the array length parameter.
198 public string? array_length_type { get; set; default = null; }
201 * Specifies whether this method expects printf-style format arguments.
203 public bool printf_format { get; set; }
206 * Specifies whether this method expects scanf-style format arguments.
208 public bool scanf_format { get; set; }
211 * Specifies whether a new function without a GType parameter is
212 * available. This is only applicable to creation methods.
214 public bool has_new_function { get; set; default = true; }
217 * Specifies whether a construct function with a GType parameter is
218 * available. This is only applicable to creation methods.
220 public bool has_construct_function { get; set; default = true; }
222 public bool has_generic_type_parameter { get; set; }
224 public double generic_type_parameter_position { get; set; }
226 public bool simple_generics { get; set; }
228 public weak Signal signal_reference { get; set; }
230 public bool closure { get; set; }
232 public bool coroutine { get; set; }
234 public bool is_async_callback { get; set; }
236 private List<FormalParameter> parameters = new ArrayList<FormalParameter> ();
237 private string cname;
238 private string finish_name;
239 private string _vfunc_name;
240 private string _sentinel;
241 private List<Expression> preconditions = new ArrayList<Expression> ();
242 private List<Expression> postconditions = new ArrayList<Expression> ();
243 private DataType _return_type;
244 private Block _body;
246 private weak Method _base_method;
247 private Method _base_interface_method;
248 private bool base_methods_valid;
250 Method? callback_method;
252 // only valid for closures
253 List<LocalVariable> captured_variables;
256 * Creates a new method.
258 * @param name method name
259 * @param return_type method return type
260 * @param source reference to source code
261 * @return newly created method
263 public Method (string? name, DataType return_type, SourceReference? source_reference = null, Comment? comment = null) {
264 base (name, source_reference, comment);
265 this.return_type = return_type;
267 carray_length_parameter_position = -3;
268 cdelegate_target_parameter_position = -3;
272 * Appends parameter to this method.
274 * @param param a formal parameter
276 public void add_parameter (FormalParameter param) {
277 // default C parameter position
278 param.cparameter_position = parameters.size + 1;
279 param.carray_length_parameter_position = param.cparameter_position + 0.1;
280 param.cdelegate_target_parameter_position = param.cparameter_position + 0.1;
281 param.cdestroy_notify_parameter_position = param.cparameter_position + 0.1;
283 parameters.add (param);
284 if (!param.ellipsis) {
285 scope.add (param.name, param);
289 public List<FormalParameter> get_parameters () {
290 return parameters;
294 * Remove all parameters from this method.
296 public void clear_parameters () {
297 foreach (FormalParameter param in parameters) {
298 if (!param.ellipsis) {
299 scope.remove (param.name);
302 parameters.clear ();
305 public override void accept (CodeVisitor visitor) {
306 visitor.visit_method (this);
309 public override void accept_children (CodeVisitor visitor) {
310 foreach (TypeParameter p in get_type_parameters ()) {
311 p.accept (visitor);
314 if (return_type != null) {
315 return_type.accept (visitor);
318 foreach (FormalParameter param in parameters) {
319 param.accept (visitor);
322 foreach (DataType error_type in get_error_types ()) {
323 error_type.accept (visitor);
326 if (result_var != null) {
327 result_var.accept (visitor);
330 foreach (Expression precondition in preconditions) {
331 precondition.accept (visitor);
334 foreach (Expression postcondition in postconditions) {
335 postcondition.accept (visitor);
338 if (body != null) {
339 body.accept (visitor);
344 * Returns the interface name of this method as it is used in C code.
346 * @return the name to be used in C code
348 public string get_cname () {
349 if (cname == null) {
350 cname = get_default_cname ();
352 return cname;
355 public string get_finish_cname () {
356 assert (coroutine);
357 if (finish_name == null) {
358 finish_name = get_default_finish_cname ();
360 return finish_name;
363 public void set_finish_cname (string name) {
364 finish_name = name;
368 * Returns the default interface name of this method as it is used in C
369 * code.
371 * @return the name to be used in C code by default
373 public virtual string get_default_cname () {
374 if (name == "main" && parent_symbol.name == null) {
375 // avoid conflict with generated main function
376 return "_vala_main";
377 } else if (name.has_prefix ("_")) {
378 return "_%s%s".printf (parent_symbol.get_lower_case_cprefix (), name.offset (1));
379 } else {
380 return "%s%s".printf (parent_symbol.get_lower_case_cprefix (), name);
385 * Returns the implementation name of this data type as it is used in C
386 * code.
388 * @return the name to be used in C code
390 public virtual string get_real_cname () {
391 if (base_method != null || base_interface_method != null) {
392 return "%sreal_%s".printf (parent_symbol.get_lower_case_cprefix (), name);
393 } else {
394 return get_cname ();
398 protected string get_finish_name_for_basename (string basename) {
399 string result = basename;
400 if (result.has_suffix ("_async")) {
401 result = result.substring (0, result.length - "_async".length);
403 result += "_finish";
404 return result;
407 public string get_finish_real_cname () {
408 assert (coroutine);
409 return get_finish_name_for_basename (get_real_cname ());
412 public string get_finish_vfunc_name () {
413 assert (coroutine);
414 return get_finish_name_for_basename (vfunc_name);
417 public string get_default_finish_cname () {
418 return get_finish_name_for_basename (get_cname ());
422 * Sets the name of this method as it is used in C code.
424 * @param cname the name to be used in C code
426 public void set_cname (string cname) {
427 this.cname = cname;
430 private void process_ccode_attribute (Attribute a) {
431 if (a.has_argument ("cname")) {
432 set_cname (a.get_string ("cname"));
434 if (a.has_argument ("cheader_filename")) {
435 var val = a.get_string ("cheader_filename");
436 foreach (string filename in val.split (",")) {
437 add_cheader_filename (filename);
440 if (a.has_argument ("vfunc_name")) {
441 this.vfunc_name = a.get_string ("vfunc_name");
443 if (a.has_argument ("finish_name")) {
444 this.finish_name = a.get_string ("finish_name");
446 if (a.has_argument ("sentinel")) {
447 this.sentinel = a.get_string ("sentinel");
449 if (a.has_argument ("instance_pos")) {
450 cinstance_parameter_position = a.get_double ("instance_pos");
452 if (a.has_argument ("array_length")) {
453 no_array_length = !a.get_bool ("array_length");
455 if (a.has_argument ("array_length_type")) {
456 array_length_type = a.get_string ("array_length_type");
458 if (a.has_argument ("array_null_terminated")) {
459 array_null_terminated = a.get_bool ("array_null_terminated");
461 if (a.has_argument ("array_length_pos")) {
462 carray_length_parameter_position = a.get_double ("array_length_pos");
464 if (a.has_argument ("delegate_target_pos")) {
465 cdelegate_target_parameter_position = a.get_double ("delegate_target_pos");
467 if (a.has_argument ("has_new_function")) {
468 has_new_function = a.get_bool ("has_new_function");
470 if (a.has_argument ("has_construct_function")) {
471 has_construct_function = a.get_bool ("has_construct_function");
473 if (a.has_argument ("generic_type_pos")) {
474 has_generic_type_parameter = true;
475 generic_type_parameter_position = a.get_double ("generic_type_pos");
477 if (a.has_argument ("simple_generics")) {
478 simple_generics = a.get_bool ("simple_generics");
480 if (a.has_argument ("returns_floating_reference")) {
481 returns_floating_reference = a.get_bool ("returns_floating_reference");
486 * Process all associated attributes.
488 public void process_attributes () {
489 foreach (Attribute a in attributes) {
490 if (a.name == "CCode") {
491 process_ccode_attribute (a);
492 } else if (a.name == "ReturnsModifiedPointer") {
493 returns_modified_pointer = true;
494 } else if (a.name == "FloatingReference") {
495 return_type.floating_reference = true;
496 } else if (a.name == "PrintfFormat") {
497 printf_format = true;
498 } else if (a.name == "ScanfFormat") {
499 scanf_format = true;
500 } else if (a.name == "NoArrayLength") {
501 Report.warning (source_reference, "NoArrayLength attribute is deprecated, use [CCode (array_length = false)] instead.");
502 no_array_length = true;
503 } else if (a.name == "Deprecated") {
504 process_deprecated_attribute (a);
510 * Checks whether the parameters and return type of this method are
511 * compatible with the specified method
513 * @param base_method a method
514 * @param invalid_match error string about which check failed
515 * @return true if the specified method is compatible to this method
517 public bool compatible (Method base_method, out string? invalid_match) {
518 if (binding != base_method.binding) {
519 invalid_match = "incompatible binding";
520 return false;
523 ObjectType object_type = null;
524 if (parent_symbol is ObjectTypeSymbol) {
525 object_type = new ObjectType ((ObjectTypeSymbol) parent_symbol);
526 foreach (TypeParameter type_parameter in object_type.type_symbol.get_type_parameters ()) {
527 var type_arg = new GenericType (type_parameter);
528 type_arg.value_owned = true;
529 object_type.add_type_argument (type_arg);
533 var actual_base_type = base_method.return_type.get_actual_type (object_type, null, this);
534 if (!return_type.equals (actual_base_type)) {
535 invalid_match = "incompatible return type";
536 return false;
539 Iterator<FormalParameter> method_params_it = parameters.iterator ();
540 int param_index = 1;
541 foreach (FormalParameter base_param in base_method.parameters) {
542 /* this method may not expect less arguments */
543 if (!method_params_it.next ()) {
544 invalid_match = "too few parameters";
545 return false;
548 actual_base_type = base_param.parameter_type.get_actual_type (object_type, null, this);
549 if (!actual_base_type.equals (method_params_it.get ().parameter_type)) {
550 invalid_match = "incompatible type of parameter %d".printf (param_index);
551 return false;
553 param_index++;
556 /* this method may not expect more arguments */
557 if (method_params_it.next ()) {
558 invalid_match = "too many parameters";
559 return false;
562 /* this method may throw less but not more errors than the base method */
563 foreach (DataType method_error_type in get_error_types ()) {
564 bool match = false;
565 foreach (DataType base_method_error_type in base_method.get_error_types ()) {
566 if (method_error_type.compatible (base_method_error_type)) {
567 match = true;
568 break;
572 if (!match) {
573 invalid_match = "incompatible error type `%s'".printf (method_error_type.to_string ());
574 return false;
577 if (base_method.coroutine != this.coroutine) {
578 invalid_match = "async mismatch";
579 return false;
582 return true;
586 * Appends the specified parameter to the list of type parameters.
588 * @param p a type parameter
590 public void add_type_parameter (TypeParameter p) {
591 type_parameters.add (p);
592 scope.add (p.name, p);
596 * Returns a copy of the type parameter list.
598 * @return list of type parameters
600 public List<TypeParameter> get_type_parameters () {
601 return type_parameters;
604 public int get_type_parameter_index (string name) {
605 int i = 0;
606 foreach (TypeParameter parameter in type_parameters) {
607 if (parameter.name == name) {
608 return i;
610 i++;
612 return -1;
616 * Adds a precondition to this method.
618 * @param precondition a boolean precondition expression
620 public void add_precondition (Expression precondition) {
621 preconditions.add (precondition);
622 precondition.parent_node = this;
626 * Returns a copy of the list of preconditions of this method.
628 * @return list of preconditions
630 public List<Expression> get_preconditions () {
631 return preconditions;
635 * Adds a postcondition to this method.
637 * @param postcondition a boolean postcondition expression
639 public void add_postcondition (Expression postcondition) {
640 postconditions.add (postcondition);
641 postcondition.parent_node = this;
645 * Returns a copy of the list of postconditions of this method.
647 * @return list of postconditions
649 public List<Expression> get_postconditions () {
650 return postconditions;
653 public override void replace_type (DataType old_type, DataType new_type) {
654 if (return_type == old_type) {
655 return_type = new_type;
656 return;
658 var error_types = get_error_types ();
659 for (int i = 0; i < error_types.size; i++) {
660 if (error_types[i] == old_type) {
661 error_types[i] = new_type;
662 return;
667 private void find_base_methods () {
668 if (base_methods_valid) {
669 return;
672 if (parent_symbol is Class) {
673 if (!(this is CreationMethod)) {
674 find_base_interface_method ((Class) parent_symbol);
675 if (is_virtual || is_abstract || overrides) {
676 find_base_class_method ((Class) parent_symbol);
679 } else if (parent_symbol is Interface) {
680 if (is_virtual || is_abstract) {
681 _base_interface_method = this;
685 base_methods_valid = true;
688 private void find_base_class_method (Class cl) {
689 var sym = cl.scope.lookup (name);
690 if (sym is Method) {
691 var base_method = (Method) sym;
692 if (base_method.is_abstract || base_method.is_virtual) {
693 string invalid_match;
694 if (!compatible (base_method, out invalid_match)) {
695 error = true;
696 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));
697 return;
700 _base_method = base_method;
701 return;
703 } else if (sym is Signal) {
704 var sig = (Signal) sym;
705 if (sig.is_virtual) {
706 var base_method = sig.default_handler;
707 string invalid_match;
708 if (!compatible (base_method, out invalid_match)) {
709 error = true;
710 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));
711 return;
714 _base_method = base_method;
715 return;
719 if (cl.base_class != null) {
720 find_base_class_method (cl.base_class);
724 private void find_base_interface_method (Class cl) {
725 // FIXME report error if multiple possible base methods are found
726 foreach (DataType type in cl.get_base_types ()) {
727 if (type.data_type is Interface) {
728 var sym = type.data_type.scope.lookup (name);
729 if (sym is Method) {
730 var base_method = (Method) sym;
731 if (base_method.is_abstract || base_method.is_virtual) {
732 string invalid_match;
733 if (!compatible (base_method, out invalid_match)) {
734 error = true;
735 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));
736 return;
739 _base_interface_method = base_method;
740 return;
747 public override bool check (SemanticAnalyzer analyzer) {
748 if (checked) {
749 return !error;
752 checked = true;
754 process_attributes ();
756 if (is_abstract) {
757 if (parent_symbol is Class) {
758 var cl = (Class) parent_symbol;
759 if (!cl.is_abstract) {
760 error = true;
761 Report.error (source_reference, "Abstract methods may not be declared in non-abstract classes");
762 return false;
764 } else if (!(parent_symbol is Interface)) {
765 error = true;
766 Report.error (source_reference, "Abstract methods may not be declared outside of classes and interfaces");
767 return false;
769 } else if (is_virtual) {
770 if (!(parent_symbol is Class) && !(parent_symbol is Interface)) {
771 error = true;
772 Report.error (source_reference, "Virtual methods may not be declared outside of classes and interfaces");
773 return false;
776 if (parent_symbol is Class) {
777 var cl = (Class) parent_symbol;
778 if (cl.is_compact) {
779 Report.error (source_reference, "Virtual methods may not be declared in compact classes");
780 return false;
783 } else if (overrides) {
784 if (!(parent_symbol is Class)) {
785 error = true;
786 Report.error (source_reference, "Methods may not be overridden outside of classes");
787 return false;
789 } else if (access == SymbolAccessibility.PROTECTED) {
790 if (!(parent_symbol is Class) && !(parent_symbol is Interface)) {
791 error = true;
792 Report.error (source_reference, "Protected methods may not be declared outside of classes and interfaces");
793 return false;
797 if (is_abstract && body != null) {
798 Report.error (source_reference, "Abstract methods cannot have bodies");
799 } else if ((is_abstract || is_virtual) && external && !external_package && !parent_symbol.external) {
800 Report.error (source_reference, "Extern methods cannot be abstract or virtual");
801 } else if (external && body != null) {
802 Report.error (source_reference, "Extern methods cannot have bodies");
803 } else if (!is_abstract && !external && !external_package && body == null) {
804 Report.error (source_reference, "Non-abstract, non-extern methods must have bodies");
807 if (coroutine && !external_package && !analyzer.context.has_package ("gio-2.0")) {
808 error = true;
809 Report.error (source_reference, "gio-2.0 package required for async methods");
810 return false;
813 var old_source_file = analyzer.current_source_file;
814 var old_symbol = analyzer.current_symbol;
816 if (source_reference != null) {
817 analyzer.current_source_file = source_reference.file;
819 analyzer.current_symbol = this;
821 return_type.check (analyzer);
823 var init_attr = get_attribute ("ModuleInit");
824 if (init_attr != null) {
825 source_reference.file.context.module_init_method = this;
828 if (return_type != null) {
829 return_type.check (analyzer);
832 if (parameters.size == 1 && parameters[0].ellipsis && body != null) {
833 // accept just `...' for external methods for convenience
834 error = true;
835 Report.error (parameters[0].source_reference, "Named parameter required before `...'");
838 foreach (FormalParameter param in parameters) {
839 param.check (analyzer);
840 if (coroutine && param.direction == ParameterDirection.REF) {
841 error = true;
842 Report.error (param.source_reference, "Reference parameters are not supported for async methods");
846 foreach (DataType error_type in get_error_types ()) {
847 error_type.check (analyzer);
850 if (result_var != null) {
851 result_var.check (analyzer);
854 foreach (Expression precondition in preconditions) {
855 precondition.check (analyzer);
858 foreach (Expression postcondition in postconditions) {
859 postcondition.check (analyzer);
862 if (body != null) {
863 body.check (analyzer);
866 analyzer.current_source_file = old_source_file;
867 analyzer.current_symbol = old_symbol;
869 if (analyzer.current_struct != null) {
870 if (is_abstract || is_virtual || overrides) {
871 Report.error (source_reference, "A struct member `%s' cannot be marked as override, virtual, or abstract".printf (get_full_name ()));
872 return false;
874 } else if (overrides && base_method == null) {
875 Report.error (source_reference, "%s: no suitable method found to override".printf (get_full_name ()));
878 if (!external_package && !overrides && !hides && get_hidden_member () != null) {
879 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 ()));
882 // check whether return type is at least as accessible as the method
883 if (!analyzer.is_type_accessible (this, return_type)) {
884 error = true;
885 Report.error (source_reference, "return type `%s` is less accessible than method `%s`".printf (return_type.to_string (), get_full_name ()));
886 return false;
889 foreach (Expression precondition in get_preconditions ()) {
890 if (precondition.error) {
891 // if there was an error in the precondition, skip this check
892 error = true;
893 return false;
896 if (!precondition.value_type.compatible (analyzer.bool_type)) {
897 error = true;
898 Report.error (precondition.source_reference, "Precondition must be boolean");
899 return false;
903 foreach (Expression postcondition in get_postconditions ()) {
904 if (postcondition.error) {
905 // if there was an error in the postcondition, skip this check
906 error = true;
907 return false;
910 if (!postcondition.value_type.compatible (analyzer.bool_type)) {
911 error = true;
912 Report.error (postcondition.source_reference, "Postcondition must be boolean");
913 return false;
917 // check that all errors that can be thrown in the method body are declared
918 if (body != null) {
919 foreach (DataType body_error_type in body.get_error_types ()) {
920 bool can_propagate_error = false;
921 foreach (DataType method_error_type in get_error_types ()) {
922 if (body_error_type.compatible (method_error_type)) {
923 can_propagate_error = true;
926 bool is_dynamic_error = body_error_type is ErrorType && ((ErrorType) body_error_type).dynamic_error;
927 if (!can_propagate_error && !is_dynamic_error) {
928 Report.warning (body_error_type.source_reference, "unhandled error `%s'".printf (body_error_type.to_string()));
933 if (is_possible_entry_point (analyzer)) {
934 if (analyzer.context.entry_point != null) {
935 error = true;
936 Report.error (source_reference, "program already has an entry point `%s'".printf (analyzer.context.entry_point.get_full_name ()));
937 return false;
939 entry_point = true;
940 analyzer.context.entry_point = this;
942 if (tree_can_fail) {
943 Report.error (source_reference, "\"main\" method cannot throw errors");
947 return !error;
950 bool is_possible_entry_point (SemanticAnalyzer analyzer) {
951 if (external_package) {
952 return false;
955 if (analyzer.context.entry_point_name == null) {
956 if (name == null || name != "main") {
957 // method must be called "main"
958 return false;
960 } else {
961 // custom entry point name
962 if (get_full_name () != analyzer.context.entry_point_name) {
963 return false;
967 if (binding == MemberBinding.INSTANCE) {
968 // method must be static
969 return false;
972 if (return_type is VoidType) {
973 } else if (return_type.data_type == analyzer.int_type.data_type) {
974 } else {
975 // return type must be void or int
976 return false;
979 var params = get_parameters ();
980 if (params.size == 0) {
981 // method may have no parameters
982 return true;
985 if (params.size > 1) {
986 // method must not have more than one parameter
987 return false;
990 Iterator<FormalParameter> params_it = params.iterator ();
991 params_it.next ();
992 var param = params_it.get ();
994 if (param.direction == ParameterDirection.OUT) {
995 // parameter must not be an out parameter
996 return false;
999 if (!(param.parameter_type is ArrayType)) {
1000 // parameter must be an array
1001 return false;
1004 var array_type = (ArrayType) param.parameter_type;
1005 if (array_type.element_type.data_type != analyzer.string_type.data_type) {
1006 // parameter must be an array of strings
1007 return false;
1010 return true;
1013 public int get_required_arguments () {
1014 int n = 0;
1015 foreach (var param in parameters) {
1016 if (param.default_expression != null || param.ellipsis) {
1017 // optional argument
1018 break;
1020 n++;
1022 return n;
1025 public Method get_callback_method () {
1026 assert (this.coroutine);
1028 if (callback_method == null) {
1029 var bool_type = new BooleanType ((Struct) CodeContext.get ().root.scope.lookup ("bool"));
1030 bool_type.value_owned = true;
1031 callback_method = new Method ("callback", bool_type, source_reference);
1032 callback_method.access = SymbolAccessibility.PUBLIC;
1033 callback_method.external = true;
1034 callback_method.binding = MemberBinding.INSTANCE;
1035 callback_method.owner = scope;
1036 callback_method.is_async_callback = true;
1037 callback_method.set_cname (get_real_cname () + "_co");
1039 return callback_method;
1042 public List<FormalParameter> get_async_begin_parameters () {
1043 assert (this.coroutine);
1045 var glib_ns = CodeContext.get ().root.scope.lookup ("GLib");
1047 var params = new ArrayList<FormalParameter> ();
1048 foreach (var param in parameters) {
1049 if (param.direction == ParameterDirection.IN) {
1050 params.add (param);
1054 var callback_type = new DelegateType ((Delegate) glib_ns.scope.lookup ("AsyncReadyCallback"));
1055 callback_type.nullable = true;
1056 callback_type.is_called_once = true;
1058 var callback_param = new FormalParameter ("_callback_", callback_type);
1059 callback_param.default_expression = new NullLiteral (source_reference);
1060 callback_param.cparameter_position = -1;
1061 callback_param.cdelegate_target_parameter_position = -0.9;
1063 params.add (callback_param);
1065 return params;
1068 public List<FormalParameter> get_async_end_parameters () {
1069 assert (this.coroutine);
1071 var params = new ArrayList<FormalParameter> ();
1073 var glib_ns = CodeContext.get ().root.scope.lookup ("GLib");
1074 var result_type = new ObjectType ((ObjectTypeSymbol) glib_ns.scope.lookup ("AsyncResult"));
1076 var result_param = new FormalParameter ("_res_", result_type);
1077 result_param.cparameter_position = 0.1;
1078 params.add (result_param);
1080 foreach (var param in parameters) {
1081 if (param.direction == ParameterDirection.OUT) {
1082 params.add (param);
1086 return params;
1089 public void add_captured_variable (LocalVariable local) {
1090 assert (this.closure);
1092 if (captured_variables == null) {
1093 captured_variables = new ArrayList<LocalVariable> ();
1095 captured_variables.add (local);
1098 public void get_captured_variables (Collection<LocalVariable> variables) {
1099 if (captured_variables != null) {
1100 foreach (var local in captured_variables) {
1101 variables.add (local);
1106 public override void get_defined_variables (Collection<LocalVariable> collection) {
1107 // capturing variables is only supported if they are initialized
1108 // therefore assume that captured variables are initialized
1109 if (closure) {
1110 get_captured_variables (collection);
1115 // vim:sw=8 noet