glib-2.0: Add float.parse/try_parse()
[vala-gnome.git] / vala / valamethod.vala
blob1db46ae456193271619b16ea934c002b128a7cfc
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 : Subroutine, Callable {
31 List<TypeParameter> type_parameters;
33 /**
34 * The return type of this method.
36 public DataType return_type {
37 get { return _return_type; }
38 set {
39 _return_type = value;
40 _return_type.parent_node = this;
44 public override bool has_result {
45 get { return !(return_type is VoidType); }
48 /**
49 * Specifies whether this method may only be called with an instance of
50 * the contained type.
52 public MemberBinding binding { get; set; default = MemberBinding.INSTANCE; }
54 /**
55 * Specifies whether this method is abstract. Abstract methods have no
56 * body, may only be specified within abstract classes, and must be
57 * overriden by derived non-abstract classes.
59 public bool is_abstract { get; set; }
61 /**
62 * Specifies whether this method is virtual. Virtual methods may be
63 * overridden by derived classes.
65 public bool is_virtual { get; set; }
67 /**
68 * Specifies whether this method overrides a virtual or abstract method
69 * of a base type.
71 public bool overrides { get; set; }
73 /**
74 * Specifies whether this method should be inlined.
76 public bool is_inline { get; set; }
78 public bool returns_floating_reference {
79 get {
80 return get_attribute_bool ("CCode", "returns_floating_reference");
82 set {
83 set_attribute_bool ("CCode", "returns_floating_reference", value);
88 * Specifies whether the C method returns a new instance pointer which
89 * may be different from the previous instance pointer. Only valid for
90 * imported methods.
92 public bool returns_modified_pointer {
93 get {
94 return get_attribute ("ReturnsModifiedPointer") != null;
96 set {
97 set_attribute ("ReturnsModifiedPointer", value);
102 * Specifies the virtual or abstract method this method overrides.
103 * Reference must be weak as virtual and abstract methods set
104 * base_method to themselves.
106 public Method base_method {
107 get {
108 find_base_methods ();
109 return _base_method;
114 * Specifies the abstract interface method this method implements.
116 public Method base_interface_method {
117 get {
118 find_base_methods ();
119 return _base_interface_method;
124 * Specifies the explicit interface containing the method this method implements.
126 public DataType base_interface_type {
127 get { return _base_interface_type; }
128 set {
129 _base_interface_type = value;
130 _base_interface_type.parent_node = this;
134 public bool entry_point { get; private set; }
137 * Specifies the generated `this` parameter for instance methods.
139 public Parameter this_parameter { get; set; }
142 * Specifies whether this method expects printf-style format arguments.
144 public bool printf_format {
145 get {
146 return get_attribute ("PrintfFormat") != null;
148 set {
149 set_attribute ("PrintfFormat", value);
154 * Specifies whether this method expects scanf-style format arguments.
156 public bool scanf_format {
157 get {
158 return get_attribute ("ScanfFormat") != null;
160 set {
161 set_attribute ("ScanfFormat", value);
166 * Specifies whether a construct function with a GType parameter is
167 * available. This is only applicable to creation methods.
169 public bool has_construct_function {
170 get {
171 return get_attribute_bool ("CCode", "has_construct_function", true);
173 set {
174 set_attribute_bool ("CCode", "has_construct_function", value);
178 public weak Signal signal_reference { get; set; }
180 public bool closure { get; set; }
182 public bool coroutine { get; set; }
184 public bool is_async_callback { get; set; }
186 private List<Parameter> parameters = new ArrayList<Parameter> ();
187 private List<Expression> preconditions;
188 private List<Expression> postconditions;
189 private DataType _return_type;
191 private weak Method _base_method;
192 private weak Method _base_interface_method;
193 private DataType _base_interface_type;
194 private bool base_methods_valid;
196 Method? callback_method;
197 Method? end_method;
199 // only valid for closures
200 List<LocalVariable> captured_variables;
202 static List<Expression> _empty_expression_list;
203 static List<TypeParameter> _empty_type_parameter_list;
206 * Creates a new method.
208 * @param name method name
209 * @param return_type method return type
210 * @param source_reference reference to source code
211 * @return newly created method
213 public Method (string? name, DataType return_type, SourceReference? source_reference = null, Comment? comment = null) {
214 base (name, source_reference, comment);
215 this.return_type = return_type;
219 * Appends parameter to this method.
221 * @param param a formal parameter
223 public void add_parameter (Parameter param) {
224 // default C parameter position
225 parameters.add (param);
226 scope.add (param.name, param);
229 public List<Parameter> get_parameters () {
230 return parameters;
234 * Remove all parameters from this method.
236 public void clear_parameters () {
237 foreach (Parameter param in parameters) {
238 if (!param.ellipsis) {
239 scope.remove (param.name);
242 parameters.clear ();
245 public bool is_variadic () {
246 foreach (Parameter param in parameters) {
247 if (param.ellipsis) {
248 return true;
251 return false;
254 public override void accept (CodeVisitor visitor) {
255 visitor.visit_method (this);
258 public override void accept_children (CodeVisitor visitor) {
259 foreach (TypeParameter p in get_type_parameters ()) {
260 p.accept (visitor);
263 if (base_interface_type != null) {
264 base_interface_type.accept (visitor);
267 if (return_type != null) {
268 return_type.accept (visitor);
271 foreach (Parameter param in parameters) {
272 param.accept (visitor);
275 foreach (DataType error_type in get_error_types ()) {
276 error_type.accept (visitor);
279 if (result_var != null) {
280 result_var.accept (visitor);
283 if (preconditions != null) {
284 foreach (Expression precondition in preconditions) {
285 precondition.accept (visitor);
289 if (postconditions != null) {
290 foreach (Expression postcondition in postconditions) {
291 postcondition.accept (visitor);
295 if (body != null) {
296 body.accept (visitor);
301 * Checks whether the parameters and return type of this method are
302 * compatible with the specified method
304 * @param base_method a method
305 * @param invalid_match error string about which check failed
306 * @return true if the specified method is compatible to this method
308 public bool compatible (Method base_method, out string? invalid_match) {
309 // method is always compatible to itself
310 if (this == base_method) {
311 invalid_match = null;
312 return true;
315 if (binding != base_method.binding) {
316 invalid_match = "incompatible binding";
317 return false;
320 ObjectType object_type = null;
321 if (parent_symbol is ObjectTypeSymbol) {
322 object_type = new ObjectType ((ObjectTypeSymbol) parent_symbol);
323 foreach (TypeParameter type_parameter in object_type.type_symbol.get_type_parameters ()) {
324 var type_arg = new GenericType (type_parameter);
325 type_arg.value_owned = true;
326 object_type.add_type_argument (type_arg);
330 if (this.get_type_parameters ().size < base_method.get_type_parameters ().size) {
331 invalid_match = "too few type parameters";
332 return false;
333 } else if (this.get_type_parameters ().size > base_method.get_type_parameters ().size) {
334 invalid_match = "too many type parameters";
335 return false;
338 List<DataType> method_type_args = null;
339 if (this.get_type_parameters ().size > 0) {
340 method_type_args = new ArrayList<DataType> ();
341 foreach (TypeParameter type_parameter in this.get_type_parameters ()) {
342 var type_arg = new GenericType (type_parameter);
343 type_arg.value_owned = true;
344 method_type_args.add (type_arg);
348 var actual_base_type = base_method.return_type.get_actual_type (object_type, method_type_args, this);
349 if (!return_type.equals (actual_base_type)) {
350 invalid_match = "Base method expected return type `%s', but `%s' was provided".printf (actual_base_type.to_prototype_string (), return_type.to_prototype_string ());
351 return false;
354 Iterator<Parameter> method_params_it = parameters.iterator ();
355 int param_index = 1;
356 foreach (Parameter base_param in base_method.parameters) {
357 /* this method may not expect less arguments */
358 if (!method_params_it.next ()) {
359 invalid_match = "too few parameters";
360 return false;
363 var param = method_params_it.get ();
364 if (base_param.ellipsis != param.ellipsis) {
365 invalid_match = "ellipsis parameter mismatch";
366 return false;
368 if (!base_param.ellipsis) {
369 if (base_param.direction != param.direction) {
370 invalid_match = "incompatible direction of parameter %d".printf (param_index);
371 return false;
374 actual_base_type = base_param.variable_type.get_actual_type (object_type, method_type_args, this);
375 if (!actual_base_type.equals (param.variable_type)) {
376 invalid_match = "incompatible type of parameter %d".printf (param_index);
377 return false;
380 param_index++;
383 /* this method may not expect more arguments */
384 if (method_params_it.next ()) {
385 invalid_match = "too many parameters";
386 return false;
389 /* this method may throw less but not more errors than the base method */
390 foreach (DataType method_error_type in get_error_types ()) {
391 bool match = false;
392 foreach (DataType base_method_error_type in base_method.get_error_types ()) {
393 if (method_error_type.compatible (base_method_error_type)) {
394 match = true;
395 break;
399 if (!match) {
400 invalid_match = "incompatible error type `%s'".printf (method_error_type.to_string ());
401 return false;
404 if (base_method.coroutine != this.coroutine) {
405 invalid_match = "async mismatch";
406 return false;
409 invalid_match = null;
410 return true;
414 * Appends the specified parameter to the list of type parameters.
416 * @param p a type parameter
418 public void add_type_parameter (TypeParameter p) {
419 if (type_parameters == null) {
420 type_parameters = new ArrayList<TypeParameter> ();
422 type_parameters.add (p);
423 scope.add (p.name, p);
427 * Returns a copy of the type parameter list.
429 * @return list of type parameters
431 public List<TypeParameter> get_type_parameters () {
432 if (type_parameters != null) {
433 return type_parameters;
435 if (_empty_type_parameter_list == null) {
436 _empty_type_parameter_list = new ArrayList<TypeParameter> ();
438 return _empty_type_parameter_list;
441 public int get_type_parameter_index (string name) {
442 if (type_parameters == null) {
443 return -1;
446 int i = 0;
447 foreach (TypeParameter parameter in type_parameters) {
448 if (parameter.name == name) {
449 return i;
451 i++;
453 return -1;
457 * Adds a precondition to this method.
459 * @param precondition a boolean precondition expression
461 public void add_precondition (Expression precondition) {
462 if (preconditions == null) {
463 preconditions = new ArrayList<Expression> ();
465 preconditions.add (precondition);
466 precondition.parent_node = this;
470 * Returns a copy of the list of preconditions of this method.
472 * @return list of preconditions
474 public List<Expression> get_preconditions () {
475 if (preconditions != null) {
476 return preconditions;
478 if (_empty_expression_list == null) {
479 _empty_expression_list = new ArrayList<Expression> ();
481 return _empty_expression_list;
485 * Adds a postcondition to this method.
487 * @param postcondition a boolean postcondition expression
489 public void add_postcondition (Expression postcondition) {
490 if (postconditions == null) {
491 postconditions = new ArrayList<Expression> ();
493 postconditions.add (postcondition);
494 postcondition.parent_node = this;
498 * Returns a copy of the list of postconditions of this method.
500 * @return list of postconditions
502 public List<Expression> get_postconditions () {
503 if (postconditions != null) {
504 return postconditions;
506 if (_empty_expression_list == null) {
507 _empty_expression_list = new ArrayList<Expression> ();
509 return _empty_expression_list;
512 public override void replace_type (DataType old_type, DataType new_type) {
513 if (base_interface_type == old_type) {
514 base_interface_type = new_type;
515 return;
517 if (return_type == old_type) {
518 return_type = new_type;
519 return;
521 var error_types = get_error_types ();
522 for (int i = 0; i < error_types.size; i++) {
523 if (error_types[i] == old_type) {
524 error_types[i] = new_type;
525 return;
530 private void find_base_methods () {
531 if (base_methods_valid) {
532 return;
535 if (parent_symbol is Class) {
536 if (!(this is CreationMethod)) {
537 find_base_interface_method ((Class) parent_symbol);
538 if (is_virtual || is_abstract || overrides) {
539 find_base_class_method ((Class) parent_symbol);
542 } else if (parent_symbol is Interface) {
543 if (is_virtual || is_abstract) {
544 _base_interface_method = this;
548 base_methods_valid = true;
551 private void find_base_class_method (Class cl) {
552 var sym = cl.scope.lookup (name);
553 if (sym is Signal) {
554 var sig = (Signal) sym;
555 sym = sig.default_handler;
557 if (sym is Method) {
558 var base_method = (Method) sym;
559 if (base_method.is_abstract || base_method.is_virtual) {
560 string invalid_match;
561 if (!compatible (base_method, out invalid_match)) {
562 error = true;
563 var base_method_type = new MethodType (base_method);
564 Report.error (source_reference, "overriding method `%s' is incompatible with base method `%s': %s.".printf (get_full_name (), base_method_type.to_prototype_string (), invalid_match));
565 return;
568 _base_method = base_method;
569 return;
573 if (cl.base_class != null) {
574 find_base_class_method (cl.base_class);
578 private void find_base_interface_method (Class cl) {
579 foreach (DataType type in cl.get_base_types ()) {
580 if (type.data_type is Interface) {
581 if (base_interface_type != null && base_interface_type.data_type != type.data_type) {
582 continue;
585 var sym = type.data_type.scope.lookup (name);
586 if (sym is Signal) {
587 var sig = (Signal) sym;
588 sym = sig.default_handler;
590 if (sym is Method) {
591 var base_method = (Method) sym;
592 if (base_method.is_abstract || base_method.is_virtual) {
593 if (base_interface_type == null) {
594 // check for existing explicit implementation
595 var has_explicit_implementation = false;
596 foreach (var m in cl.get_methods ()) {
597 if (m.base_interface_type != null && base_method == m.base_interface_method) {
598 has_explicit_implementation = true;
599 break;
602 if (has_explicit_implementation) {
603 continue;
607 string invalid_match = null;
608 if (!compatible (base_method, out invalid_match)) {
609 error = true;
610 var base_method_type = new MethodType (base_method);
611 Report.error (source_reference, "overriding method `%s' is incompatible with base method `%s': %s.".printf (get_full_name (), base_method_type.to_prototype_string (), invalid_match));
612 return;
615 _base_interface_method = base_method;
616 return;
622 if (base_interface_type != null) {
623 Report.error (source_reference, "`%s': no suitable interface method found to implement".printf (get_full_name ()));
627 public override bool check (CodeContext context) {
628 if (checked) {
629 return !error;
632 checked = true;
634 if (get_attribute ("DestroysInstance") != null) {
635 this_parameter.variable_type.value_owned = true;
637 if (get_attribute ("NoThrow") != null) {
638 get_error_types ().clear ();
641 if (parent_symbol is Class && (is_abstract || is_virtual)) {
642 var cl = (Class) parent_symbol;
643 if (cl.is_compact && cl.base_class != null) {
644 error = true;
645 Report.error (source_reference, "Abstract and virtual methods may not be declared in derived compact classes");
646 return false;
650 if (is_variadic () && (is_abstract || is_virtual)) {
651 error = true;
652 Report.error (source_reference, "Abstract and virtual methods may not be variadic. Use a `va_list' parameter instead of `...'.");
653 return false;
656 if (is_abstract) {
657 if (parent_symbol is Class) {
658 var cl = (Class) parent_symbol;
659 if (!cl.is_abstract) {
660 error = true;
661 Report.error (source_reference, "Abstract methods may not be declared in non-abstract classes");
662 return false;
664 } else if (!(parent_symbol is Interface)) {
665 error = true;
666 Report.error (source_reference, "Abstract methods may not be declared outside of classes and interfaces");
667 return false;
669 } else if (is_virtual) {
670 if (!(parent_symbol is Class) && !(parent_symbol is Interface)) {
671 error = true;
672 Report.error (source_reference, "Virtual methods may not be declared outside of classes and interfaces");
673 return false;
675 } else if (overrides) {
676 if (!(parent_symbol is Class)) {
677 error = true;
678 Report.error (source_reference, "Methods may not be overridden outside of classes");
679 return false;
681 } else if (access == SymbolAccessibility.PROTECTED) {
682 if (!(parent_symbol is Class) && !(parent_symbol is Interface)) {
683 error = true;
684 Report.error (source_reference, "Protected methods may not be declared outside of classes and interfaces");
685 return false;
689 if (is_abstract && body != null) {
690 Report.error (source_reference, "Abstract methods cannot have bodies");
691 } else if ((is_abstract || is_virtual) && external && !external_package && !parent_symbol.external) {
692 Report.error (source_reference, "Extern methods cannot be abstract or virtual");
693 } else if (external && body != null) {
694 Report.error (source_reference, "Extern methods cannot have bodies");
695 } else if (!is_abstract && !external && source_type == SourceFileType.SOURCE && body == null) {
696 Report.error (source_reference, "Non-abstract, non-extern methods must have bodies");
699 if (coroutine && !external_package && !context.has_package ("gio-2.0")) {
700 error = true;
701 Report.error (source_reference, "gio-2.0 package required for async methods");
702 return false;
705 var old_source_file = context.analyzer.current_source_file;
706 var old_symbol = context.analyzer.current_symbol;
708 if (source_reference != null) {
709 context.analyzer.current_source_file = source_reference.file;
711 context.analyzer.current_symbol = this;
713 return_type.floating_reference = returns_floating_reference;
714 return_type.check (context);
716 var init_attr = get_attribute ("ModuleInit");
717 if (init_attr != null) {
718 source_reference.file.context.module_init_method = this;
721 if (return_type != null) {
722 return_type.check (context);
725 if (parameters.size == 1 && parameters[0].ellipsis && body != null && binding != MemberBinding.INSTANCE) {
726 // accept just `...' for external methods and instance methods
727 error = true;
728 Report.error (parameters[0].source_reference, "Named parameter required before `...'");
731 var optional_param = false;
732 foreach (Parameter param in parameters) {
733 param.check (context);
734 if (coroutine && param.direction == ParameterDirection.REF) {
735 error = true;
736 Report.error (param.source_reference, "Reference parameters are not supported for async methods");
738 // TODO: begin and end parameters must be checked separately for coroutines
739 if (coroutine) {
740 continue;
742 if (optional_param && param.initializer == null && !param.ellipsis) {
743 Report.warning (param.source_reference, "parameter without default follows parameter with default");
744 } else if (param.initializer != null) {
745 optional_param = true;
749 foreach (DataType error_type in get_error_types ()) {
750 error_type.check (context);
752 // check whether error type is at least as accessible as the method
753 if (!context.analyzer.is_type_accessible (this, error_type)) {
754 error = true;
755 Report.error (source_reference, "error type `%s' is less accessible than method `%s'".printf (error_type.to_string (), get_full_name ()));
756 return false;
760 if (result_var != null) {
761 result_var.check (context);
764 if (preconditions != null) {
765 foreach (Expression precondition in preconditions) {
766 precondition.check (context);
770 if (postconditions != null) {
771 foreach (Expression postcondition in postconditions) {
772 postcondition.check (context);
776 if (body != null) {
777 body.check (context);
780 if (context.analyzer.current_struct != null) {
781 if (is_abstract || is_virtual || overrides) {
782 error = true;
783 Report.error (source_reference, "A struct member `%s' cannot be marked as override, virtual, or abstract".printf (get_full_name ()));
784 return false;
786 } else if (overrides && base_method == null) {
787 Report.error (source_reference, "`%s': no suitable method found to override".printf (get_full_name ()));
788 } else if ((is_abstract || is_virtual || overrides) && access == SymbolAccessibility.PRIVATE) {
789 error = true;
790 Report.error (source_reference, "Private member `%s' cannot be marked as override, virtual, or abstract".printf (get_full_name ()));
791 return false;
794 if (base_interface_type != null && base_interface_method != null && parent_symbol is Class) {
795 var cl = (Class) parent_symbol;
796 foreach (var m in cl.get_methods ()) {
797 if (m != this && m.base_interface_method == base_interface_method) {
798 m.checked = true;
799 m.error = true;
800 error = true;
801 Report.error (source_reference, "`%s' already contains an implementation for `%s'".printf (cl.get_full_name (), base_interface_method.get_full_name ()));
802 Report.notice (m.source_reference, "previous implementation of `%s' was here".printf (base_interface_method.get_full_name ()));
803 return false;
808 context.analyzer.current_source_file = old_source_file;
809 context.analyzer.current_symbol = old_symbol;
811 if (!external_package && !overrides && !hides && get_hidden_member () != null) {
812 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 ()));
815 // check whether return type is at least as accessible as the method
816 if (!context.analyzer.is_type_accessible (this, return_type)) {
817 error = true;
818 Report.error (source_reference, "return type `%s' is less accessible than method `%s'".printf (return_type.to_string (), get_full_name ()));
819 return false;
822 foreach (Expression precondition in get_preconditions ()) {
823 if (precondition.error) {
824 // if there was an error in the precondition, skip this check
825 error = true;
826 return false;
829 if (!precondition.value_type.compatible (context.analyzer.bool_type)) {
830 error = true;
831 Report.error (precondition.source_reference, "Precondition must be boolean");
832 return false;
836 foreach (Expression postcondition in get_postconditions ()) {
837 if (postcondition.error) {
838 // if there was an error in the postcondition, skip this check
839 error = true;
840 return false;
843 if (!postcondition.value_type.compatible (context.analyzer.bool_type)) {
844 error = true;
845 Report.error (postcondition.source_reference, "Postcondition must be boolean");
846 return false;
850 // check that all errors that can be thrown in the method body are declared
851 if (body != null) {
852 foreach (DataType body_error_type in body.get_error_types ()) {
853 bool can_propagate_error = false;
854 foreach (DataType method_error_type in get_error_types ()) {
855 if (body_error_type.compatible (method_error_type)) {
856 can_propagate_error = true;
859 bool is_dynamic_error = body_error_type is ErrorType && ((ErrorType) body_error_type).dynamic_error;
860 if (!can_propagate_error && !is_dynamic_error) {
861 Report.warning (body_error_type.source_reference, "unhandled error `%s'".printf (body_error_type.to_string()));
866 // check that DBus methods at least throw "GLib.Error" or "GLib.DBusError, GLib.IOError"
867 if (!(this is CreationMethod) && binding == MemberBinding.INSTANCE
868 && !overrides && access == SymbolAccessibility.PUBLIC
869 && parent_symbol is ObjectTypeSymbol && parent_symbol.get_attribute ("DBus") != null) {
870 Attribute? dbus_attr = get_attribute ("DBus");
871 if (dbus_attr == null || dbus_attr.get_bool ("visible", true)) {
872 bool throws_gerror = false;
873 bool throws_gioerror = false;
874 bool throws_gdbuserror = false;
875 foreach (DataType error_type in get_error_types ()) {
876 if (!(error_type is ErrorType)) {
877 continue;
879 unowned ErrorDomain? error_domain = ((ErrorType) error_type).error_domain;
880 if (error_domain == null) {
881 throws_gerror = true;
882 break;
884 string? full_error_domain = error_domain.get_full_name ();
885 if (full_error_domain == "GLib.IOError") {
886 throws_gioerror = true;
887 } else if (full_error_domain == "GLib.DBusError") {
888 throws_gdbuserror = true;
891 if (!throws_gerror && !(throws_gioerror && throws_gdbuserror)) {
892 Report.warning (source_reference, "DBus methods are recommended to throw at least `GLib.Error' or `GLib.DBusError, GLib.IOError'");
897 if (is_possible_entry_point (context)) {
898 if (context.entry_point != null) {
899 error = true;
900 Report.error (source_reference, "program already has an entry point `%s'".printf (context.entry_point.get_full_name ()));
901 return false;
903 entry_point = true;
904 context.entry_point = this;
906 if (tree_can_fail) {
907 Report.error (source_reference, "\"main\" method cannot throw errors");
910 if (is_inline) {
911 Report.error (source_reference, "\"main\" method cannot be inline");
914 if (coroutine) {
915 Report.error (source_reference, "\"main\" method cannot be async");
919 if (get_attribute ("GtkCallback") != null) {
920 used = true;
923 return !error;
926 bool is_possible_entry_point (CodeContext context) {
927 if (external_package) {
928 return false;
931 if (context.entry_point_name == null) {
932 if (name == null || name != "main") {
933 // method must be called "main"
934 return false;
936 } else {
937 // custom entry point name
938 if (get_full_name () != context.entry_point_name) {
939 return false;
943 if (binding == MemberBinding.INSTANCE) {
944 // method must be static
945 return false;
948 if (return_type is VoidType) {
949 } else if (return_type.data_type == context.analyzer.int_type.data_type) {
950 } else {
951 // return type must be void or int
952 return false;
955 var params = get_parameters ();
956 if (params.size == 0) {
957 // method may have no parameters
958 return true;
961 if (params.size > 1) {
962 // method must not have more than one parameter
963 return false;
966 Iterator<Parameter> params_it = params.iterator ();
967 params_it.next ();
968 var param = params_it.get ();
970 if (param.direction == ParameterDirection.OUT) {
971 // parameter must not be an out parameter
972 return false;
975 if (!(param.variable_type is ArrayType)) {
976 // parameter must be an array
977 return false;
980 var array_type = (ArrayType) param.variable_type;
981 if (array_type.element_type.data_type != context.analyzer.string_type.data_type) {
982 // parameter must be an array of strings
983 return false;
986 return true;
989 public int get_required_arguments () {
990 int n = 0;
991 foreach (var param in parameters) {
992 if (param.initializer != null || param.ellipsis) {
993 // optional argument
994 break;
996 n++;
998 return n;
1001 public Method get_end_method () {
1002 assert (this.coroutine);
1004 if (end_method == null) {
1005 end_method = new Method ("end", return_type, source_reference);
1006 end_method.access = SymbolAccessibility.PUBLIC;
1007 end_method.external = true;
1008 end_method.owner = scope;
1009 foreach (var param in get_async_end_parameters ()) {
1010 end_method.add_parameter (param.copy ());
1012 foreach (var param in get_type_parameters ()) {
1013 end_method.add_type_parameter (param);
1016 return end_method;
1019 public Method get_callback_method () {
1020 assert (this.coroutine);
1022 if (callback_method == null) {
1023 var bool_type = new BooleanType ((Struct) CodeContext.get ().root.scope.lookup ("bool"));
1024 bool_type.value_owned = true;
1025 callback_method = new Method ("callback", bool_type, source_reference);
1026 callback_method.access = SymbolAccessibility.PUBLIC;
1027 callback_method.external = true;
1028 callback_method.binding = MemberBinding.INSTANCE;
1029 callback_method.owner = scope;
1030 callback_method.is_async_callback = true;
1032 return callback_method;
1035 public List<Parameter> get_async_begin_parameters () {
1036 assert (this.coroutine);
1038 var glib_ns = CodeContext.get ().root.scope.lookup ("GLib");
1040 var params = new ArrayList<Parameter> ();
1041 Parameter ellipsis = null;
1042 foreach (var param in parameters) {
1043 if (param.ellipsis) {
1044 ellipsis = param;
1045 } else if (param.direction == ParameterDirection.IN) {
1046 params.add (param);
1050 var callback_type = new DelegateType ((Delegate) glib_ns.scope.lookup ("AsyncReadyCallback"));
1051 callback_type.nullable = true;
1052 callback_type.value_owned = true;
1053 callback_type.is_called_once = true;
1055 var callback_param = new Parameter ("_callback_", callback_type);
1056 callback_param.initializer = new NullLiteral (source_reference);
1057 callback_param.initializer.target_type = callback_type.copy ();
1058 callback_param.set_attribute_double ("CCode", "pos", -1);
1059 callback_param.set_attribute_double ("CCode", "delegate_target_pos", -0.9);
1061 params.add (callback_param);
1063 if (ellipsis != null) {
1064 params.add (ellipsis);
1067 return params;
1070 public List<Parameter> get_async_end_parameters () {
1071 assert (this.coroutine);
1073 var params = new ArrayList<Parameter> ();
1075 var glib_ns = CodeContext.get ().root.scope.lookup ("GLib");
1076 var result_type = new ObjectType ((ObjectTypeSymbol) glib_ns.scope.lookup ("AsyncResult"));
1078 var result_param = new Parameter ("_res_", result_type);
1079 result_param.set_attribute_double ("CCode", "pos", 0.1);
1080 params.add (result_param);
1082 foreach (var param in parameters) {
1083 if (param.direction == ParameterDirection.OUT) {
1084 params.add (param);
1088 return params;
1091 public void add_captured_variable (LocalVariable local) {
1092 assert (this.closure);
1094 if (captured_variables == null) {
1095 captured_variables = new ArrayList<LocalVariable> ();
1097 captured_variables.add (local);
1100 public void get_captured_variables (Collection<LocalVariable> variables) {
1101 if (captured_variables != null) {
1102 foreach (var local in captured_variables) {
1103 variables.add (local);
1108 public override void get_defined_variables (Collection<Variable> collection) {
1109 // capturing variables is only supported if they are initialized
1110 // therefore assume that captured variables are initialized
1111 if (closure) {
1112 get_captured_variables ((Collection<LocalVariable>) collection);
1116 public int get_format_arg_index () {
1117 for (int i = 0; i < parameters.size; i++) {
1118 if (parameters[i].format_arg) {
1119 return i;
1122 return -1;
1125 public bool has_error_type_parameter () {
1126 if (get_error_types ().size > 0) {
1127 return true;
1129 if (base_method != null && base_method != this && base_method.has_error_type_parameter ()) {
1130 return true;
1132 if (base_interface_method != null && base_interface_method != this && base_interface_method.has_error_type_parameter ()) {
1133 return true;
1135 return false;
1139 // vim:sw=8 noet