girparser: Add common parse_symbol_from_string method
[vala-lang.git] / vala / valamethodcall.vala
blobea3c556c2d602db84a2b29e0fd7be18d25d64716
1 /* valamethodcall.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
25 /**
26 * Represents an invocation expression in the source code.
28 public class Vala.MethodCall : Expression {
29 /**
30 * The method to call.
32 public Expression call {
33 get { return _call; }
34 set {
35 _call = value;
36 _call.parent_node = this;
40 public bool is_yield_expression { get; set; }
42 public bool is_assert { get; private set; }
44 public Expression _call;
46 private List<Expression> argument_list = new ArrayList<Expression> ();
48 /**
49 * Creates a new invocation expression.
51 * @param call method to call
52 * @param source_reference reference to source code
53 * @return newly created invocation expression
55 public MethodCall (Expression call, SourceReference? source_reference = null) {
56 this.source_reference = source_reference;
57 this.call = call;
60 /**
61 * Appends the specified expression to the list of arguments.
63 * @param arg an argument
65 public void add_argument (Expression arg) {
66 argument_list.add (arg);
67 arg.parent_node = this;
70 /**
71 * Returns a copy of the argument list.
73 * @return argument list
75 public List<Expression> get_argument_list () {
76 return argument_list;
79 public override void accept (CodeVisitor visitor) {
80 visitor.visit_method_call (this);
82 visitor.visit_expression (this);
85 public override void accept_children (CodeVisitor visitor) {
86 call.accept (visitor);
88 foreach (Expression expr in argument_list) {
89 expr.accept (visitor);
93 public override void replace_expression (Expression old_node, Expression new_node) {
94 if (call == old_node) {
95 call = new_node;
98 int index = argument_list.index_of (old_node);
99 if (index >= 0 && new_node.parent_node == null) {
100 argument_list[index] = new_node;
101 new_node.parent_node = this;
105 public override bool is_pure () {
106 return false;
109 bool is_chainup () {
110 if (!(call.symbol_reference is CreationMethod)) {
111 return false;
114 var expr = call;
116 var ma = (MemberAccess) call;
117 if (ma.inner != null) {
118 expr = ma.inner;
121 ma = expr as MemberAccess;
122 if (ma != null && ma.member_name == "this") {
123 return true;
124 } else if (expr is BaseAccess) {
125 return true;
126 } else {
127 return false;
131 public override bool check (CodeContext context) {
132 if (checked) {
133 return !error;
136 checked = true;
138 if (!call.check (context)) {
139 /* if method resolving didn't succeed, skip this check */
140 error = true;
141 return false;
144 // type of target object
145 DataType target_object_type = null;
147 if (call.value_type is DelegateType) {
148 // delegate invocation, resolve generic types relative to delegate
149 target_object_type = call.value_type;
150 } else if (call is MemberAccess) {
151 var ma = (MemberAccess) call;
152 if (ma.prototype_access) {
153 error = true;
154 Report.error (source_reference, "Access to instance member `%s' denied".printf (call.symbol_reference.get_full_name ()));
155 return false;
158 if (ma.inner != null) {
159 target_object_type = ma.inner.value_type;
162 if (ma.symbol_reference != null && ma.symbol_reference.get_attribute ("Assert") != null) {
163 this.is_assert = true;
167 var mtype = call.value_type;
169 if (mtype is ObjectType || (context.profile == Profile.GOBJECT && call.symbol_reference == context.analyzer.object_type)) {
170 // constructor chain-up
171 var cm = context.analyzer.find_current_method () as CreationMethod;
172 if (cm == null) {
173 error = true;
174 Report.error (source_reference, "invocation not supported in this context");
175 return false;
176 } else if (cm.chain_up) {
177 error = true;
178 Report.error (source_reference, "Multiple constructor calls in the same constructor are not permitted");
179 return false;
181 cm.chain_up = true;
183 if (mtype is ObjectType) {
184 var otype = (ObjectType) mtype;
185 var cl = (Class) otype.type_symbol;
186 var base_cm = cl.default_construction_method;
187 if (base_cm == null) {
188 error = true;
189 Report.error (source_reference, "chain up to `%s' not supported".printf (cl.get_full_name ()));
190 return false;
191 } else if (!base_cm.has_construct_function) {
192 error = true;
193 Report.error (source_reference, "chain up to `%s' not supported".printf (base_cm.get_full_name ()));
194 return false;
196 } else {
197 // GObject chain up
198 var cl = cm.parent_symbol as Class;
199 if (cl == null || !cl.is_subtype_of (context.analyzer.object_type)) {
200 error = true;
201 Report.error (source_reference, "chain up to `GLib.Object' not supported");
202 return false;
204 call.value_type = new ObjectType (context.analyzer.object_type);
205 mtype = call.value_type;
209 // check for struct construction
210 if (call is MemberAccess &&
211 ((call.symbol_reference is CreationMethod
212 && call.symbol_reference.parent_symbol is Struct)
213 || call.symbol_reference is Struct)) {
214 var st = call.symbol_reference as Struct;
215 if (st != null && st.default_construction_method == null && (st.is_boolean_type () || st.is_integer_type () || st.is_floating_type ())) {
216 error = true;
217 Report.error (source_reference, "invocation not supported in this context");
218 return false;
221 if (is_chainup ()) {
222 var cm = context.analyzer.find_current_method () as CreationMethod;
223 if (cm != null) {
224 if (cm.chain_up) {
225 error = true;
226 Report.error (source_reference, "Multiple constructor calls in the same constructor are not permitted");
227 return false;
229 cm.chain_up = true;
232 var struct_creation_expression = new ObjectCreationExpression ((MemberAccess) call, source_reference);
233 struct_creation_expression.struct_creation = true;
234 foreach (Expression arg in get_argument_list ()) {
235 struct_creation_expression.add_argument (arg);
237 struct_creation_expression.target_type = target_type;
238 context.analyzer.replaced_nodes.add (this);
239 parent_node.replace_expression (this, struct_creation_expression);
240 struct_creation_expression.check (context);
241 return true;
242 } else if (call is MemberAccess
243 && call.symbol_reference is CreationMethod) {
244 // constructor chain-up
245 var cm = context.analyzer.find_current_method () as CreationMethod;
246 if (cm == null) {
247 error = true;
248 Report.error (source_reference, "use `new' operator to create new objects");
249 return false;
250 } else if (cm.chain_up) {
251 error = true;
252 Report.error (source_reference, "Multiple constructor calls in the same constructor are not permitted");
253 return false;
255 cm.chain_up = true;
257 var base_cm = (CreationMethod) call.symbol_reference;
258 if (!base_cm.has_construct_function) {
259 error = true;
260 Report.error (source_reference, "chain up to `%s' not supported".printf (base_cm.get_full_name ()));
261 return false;
265 if (mtype != null && mtype.is_invokable ()) {
266 // call ok, expression is invokable
267 } else if (call.symbol_reference is Class) {
268 error = true;
269 Report.error (source_reference, "use `new' operator to create new objects");
270 return false;
271 } else {
272 error = true;
273 Report.error (source_reference, "invocation not supported in this context");
274 return false;
277 var ret_type = mtype.get_return_type ();
278 var params = mtype.get_parameters ();
280 if (mtype is MethodType) {
281 var m = ((MethodType) mtype).method_symbol;
282 if (m != null && m.coroutine) {
283 var ma = (MemberAccess) call;
284 if (!is_yield_expression) {
285 // begin or end call of async method
286 if (ma.member_name != "end") {
287 // begin (possibly implicit)
288 params = m.get_async_begin_parameters ();
289 ret_type = new VoidType ();
290 } else {
291 // end
292 params = m.get_async_end_parameters ();
294 } else if (ma.member_name == "begin" || ma.member_name == "end") {
295 error = true;
296 Report.error (ma.source_reference, "use of `%s' not allowed in yield statement".printf (ma.member_name));
300 if (m != null && m.get_type_parameters ().size > 0) {
301 var ma = (MemberAccess) call;
302 int n_type_params = m.get_type_parameters ().size;
303 int n_type_args = ma.get_type_arguments ().size;
304 if (n_type_args > 0 && n_type_args < n_type_params) {
305 error = true;
306 Report.error (ma.source_reference, "too few type arguments");
307 return false;
308 } else if (n_type_args > 0 && n_type_args > n_type_params) {
309 error = true;
310 Report.error (ma.source_reference, "too many type arguments");
311 return false;
316 Expression last_arg = null;
318 var args = get_argument_list ();
319 Iterator<Expression> arg_it = args.iterator ();
320 foreach (Parameter param in params) {
321 if (param.ellipsis) {
322 break;
325 if (param.params_array) {
326 var array_type = (ArrayType) param.variable_type;
327 while (arg_it.next ()) {
328 Expression arg = arg_it.get ();
330 /* store expected type for callback parameters */
331 arg.target_type = array_type.element_type;
332 arg.target_type.value_owned = array_type.value_owned;
334 break;
337 if (arg_it.next ()) {
338 Expression arg = arg_it.get ();
340 /* store expected type for callback parameters */
341 arg.formal_target_type = param.variable_type;
342 arg.target_type = arg.formal_target_type.get_actual_type (target_object_type, call as MemberAccess, this);
344 last_arg = arg;
348 // concatenate stringified arguments for methods with attribute [Print]
349 if (mtype is MethodType && ((MethodType) mtype).method_symbol.get_attribute ("Print") != null) {
350 var template = new Template (source_reference);
351 foreach (Expression arg in argument_list) {
352 arg.parent_node = null;
353 template.add_expression (arg);
355 argument_list.clear ();
356 add_argument (template);
359 // printf arguments
360 if (mtype is MethodType && ((MethodType) mtype).method_symbol.printf_format) {
361 StringLiteral format_literal = null;
362 if (last_arg != null) {
363 // use last argument as format string
364 format_literal = last_arg as StringLiteral;
365 if (format_literal == null && args.size == params.size - 1) {
366 // insert "%s" to avoid issues with embedded %
367 format_literal = new StringLiteral ("\"%s\"");
368 format_literal.target_type = context.analyzer.string_type.copy ();
369 argument_list.insert (args.size - 1, format_literal);
371 // recreate iterator and skip to right position
372 arg_it = argument_list.iterator ();
373 foreach (Parameter param in params) {
374 if (param.ellipsis) {
375 break;
377 arg_it.next ();
380 } else {
381 // use instance as format string for string.printf (...)
382 var ma = call as MemberAccess;
383 if (ma != null) {
384 format_literal = ma.inner as StringLiteral;
387 if (format_literal != null) {
388 string format = format_literal.eval ();
390 bool unsupported_format = false;
392 weak string format_it = format;
393 unichar c = format_it.get_char ();
394 while (c != '\0') {
395 if (c != '%') {
396 format_it = format_it.next_char ();
397 c = format_it.get_char ();
398 continue;
401 format_it = format_it.next_char ();
402 c = format_it.get_char ();
403 // flags
404 while (c == '#' || c == '0' || c == '-' || c == ' ' || c == '+') {
405 format_it = format_it.next_char ();
406 c = format_it.get_char ();
408 // field width
409 while (c >= '0' && c <= '9') {
410 format_it = format_it.next_char ();
411 c = format_it.get_char ();
413 // precision
414 if (c == '.') {
415 format_it = format_it.next_char ();
416 c = format_it.get_char ();
417 while (c >= '0' && c <= '9') {
418 format_it = format_it.next_char ();
419 c = format_it.get_char ();
422 // length modifier
423 int length = 0;
424 if (c == 'h') {
425 length = -1;
426 format_it = format_it.next_char ();
427 c = format_it.get_char ();
428 if (c == 'h') {
429 length = -2;
430 format_it = format_it.next_char ();
431 c = format_it.get_char ();
433 } else if (c == 'l') {
434 length = 1;
435 format_it = format_it.next_char ();
436 c = format_it.get_char ();
437 } else if (c == 'z') {
438 length = 2;
439 format_it = format_it.next_char ();
440 c = format_it.get_char ();
442 // conversion specifier
443 DataType param_type = null;
444 if (c == 'd' || c == 'i' || c == 'c') {
445 // integer
446 if (length == -2) {
447 param_type = context.analyzer.int8_type;
448 } else if (length == -1) {
449 param_type = context.analyzer.short_type;
450 } else if (length == 0) {
451 param_type = context.analyzer.int_type;
452 } else if (length == 1) {
453 param_type = context.analyzer.long_type;
454 } else if (length == 2) {
455 param_type = context.analyzer.ssize_t_type;
457 } else if (c == 'o' || c == 'u' || c == 'x' || c == 'X') {
458 // unsigned integer
459 if (length == -2) {
460 param_type = context.analyzer.uchar_type;
461 } else if (length == -1) {
462 param_type = context.analyzer.ushort_type;
463 } else if (length == 0) {
464 param_type = context.analyzer.uint_type;
465 } else if (length == 1) {
466 param_type = context.analyzer.ulong_type;
467 } else if (length == 2) {
468 param_type = context.analyzer.size_t_type;
470 } else if (c == 'e' || c == 'E' || c == 'f' || c == 'F'
471 || c == 'g' || c == 'G' || c == 'a' || c == 'A') {
472 // double
473 param_type = context.analyzer.double_type;
474 } else if (c == 's') {
475 // string
476 param_type = context.analyzer.string_type;
477 } else if (c == 'p') {
478 // pointer
479 param_type = new PointerType (new VoidType ());
480 } else if (c == '%') {
481 // literal %
482 } else {
483 unsupported_format = true;
484 break;
486 if (c != '\0') {
487 format_it = format_it.next_char ();
488 c = format_it.get_char ();
490 if (param_type != null) {
491 if (arg_it.next ()) {
492 Expression arg = arg_it.get ();
494 arg.target_type = param_type;
495 } else {
496 Report.error (source_reference, "Too few arguments for specified format");
497 return false;
501 if (!unsupported_format && arg_it.next ()) {
502 Report.error (source_reference, "Too many arguments for specified format");
503 return false;
508 foreach (Expression arg in get_argument_list ()) {
509 arg.check (context);
512 if (ret_type is VoidType) {
513 // void return type
514 if (!(parent_node is ExpressionStatement)
515 && !(parent_node is ForStatement)
516 && !(parent_node is YieldStatement)) {
517 // A void method invocation can be in the initializer or
518 // iterator of a for statement
519 error = true;
520 Report.error (source_reference, "invocation of void method not allowed as expression");
521 return false;
525 formal_value_type = ret_type;
526 value_type = formal_value_type.get_actual_type (target_object_type, call as MemberAccess, this);
528 bool may_throw = false;
530 if (mtype is MethodType) {
531 var m = ((MethodType) mtype).method_symbol;
532 if (is_yield_expression) {
533 if (!m.coroutine) {
534 error = true;
535 Report.error (source_reference, "yield expression requires async method");
537 if (context.analyzer.current_method == null || !context.analyzer.current_method.coroutine) {
538 error = true;
539 Report.error (source_reference, "yield expression not available outside async method");
541 context.analyzer.current_method.yield_count++;
543 if (m != null && m.coroutine && !is_yield_expression && ((MemberAccess) call).member_name != "end") {
544 // .begin call of async method, no error can happen here
545 } else {
546 foreach (DataType error_type in m.get_error_types ()) {
547 may_throw = true;
549 // ensure we can trace back which expression may throw errors of this type
550 var call_error_type = error_type.copy ();
551 call_error_type.source_reference = source_reference;
553 add_error_type (call_error_type);
556 if (m.returns_floating_reference) {
557 value_type.floating_reference = true;
560 var dynamic_sig = m.parent_symbol as DynamicSignal;
561 if (dynamic_sig != null && dynamic_sig.handler != null) {
562 dynamic_sig.return_type = dynamic_sig.handler.value_type.get_return_type ().copy ();
563 bool first = true;
564 foreach (Parameter param in dynamic_sig.handler.value_type.get_parameters ()) {
565 if (first) {
566 // skip sender parameter
567 first = false;
568 } else {
569 dynamic_sig.add_parameter (param.copy ());
572 dynamic_sig.handler.target_type = new DelegateType (dynamic_sig.get_delegate (new ObjectType ((ObjectTypeSymbol) dynamic_sig.parent_symbol), this));
575 if (m != null && m.get_type_parameters ().size > 0) {
576 var ma = (MemberAccess) call;
577 if (ma.get_type_arguments ().size == 0) {
578 // infer type arguments
579 foreach (var type_param in m.get_type_parameters ()) {
580 DataType type_arg = null;
582 // infer type arguments from arguments
583 arg_it = args.iterator ();
584 foreach (Parameter param in params) {
585 if (param.ellipsis || param.params_array) {
586 break;
589 if (arg_it.next ()) {
590 Expression arg = arg_it.get ();
592 var generic_type = param.variable_type as GenericType;
593 if (generic_type != null && generic_type.type_parameter == type_param) {
594 type_arg = arg.value_type.copy ();
595 type_arg.value_owned = true;
596 break;
599 arg.target_type = arg.formal_target_type.get_actual_type (target_object_type, call as MemberAccess, this);
603 // infer type arguments from expected return type
604 if (type_arg == null && target_type != null) {
605 var generic_type = m.return_type as GenericType;
606 if (generic_type != null && generic_type.type_parameter == type_param) {
607 type_arg = target_type.copy ();
608 type_arg.value_owned = true;
612 if (type_arg == null) {
613 error = true;
614 Report.error (ma.source_reference, "cannot infer generic type argument for type parameter `%s'".printf (type_param.get_full_name ()));
615 return false;
618 ma.add_type_argument (type_arg);
621 // recalculate argument target types with new information
622 arg_it = args.iterator ();
623 foreach (Parameter param in params) {
624 if (param.ellipsis || param.params_array) {
625 break;
628 if (arg_it.next ()) {
629 Expression arg = arg_it.get ();
631 arg.target_type = arg.formal_target_type.get_actual_type (target_object_type, call as MemberAccess, this);
635 // recalculate return value type with new information
636 value_type = formal_value_type.get_actual_type (target_object_type, call as MemberAccess, this);
639 } else if (mtype is ObjectType) {
640 // constructor
641 var cl = (Class) ((ObjectType) mtype).type_symbol;
642 var m = cl.default_construction_method;
643 foreach (DataType error_type in m.get_error_types ()) {
644 may_throw = true;
646 // ensure we can trace back which expression may throw errors of this type
647 var call_error_type = error_type.copy ();
648 call_error_type.source_reference = source_reference;
650 add_error_type (call_error_type);
652 } else if (mtype is DelegateType) {
653 var d = ((DelegateType) mtype).delegate_symbol;
654 foreach (DataType error_type in d.get_error_types ()) {
655 may_throw = true;
657 // ensure we can trace back which expression may throw errors of this type
658 var call_error_type = error_type.copy ();
659 call_error_type.source_reference = source_reference;
661 add_error_type (call_error_type);
665 if (!context.analyzer.check_arguments (this, mtype, params, get_argument_list ())) {
666 error = true;
667 return false;
670 if (may_throw) {
671 if (parent_node is LocalVariable || parent_node is ExpressionStatement) {
672 // simple statements, no side effects after method call
673 } else if (!(context.analyzer.current_symbol is Block)) {
674 if (context.profile != Profile.DOVA) {
675 // can't handle errors in field initializers
676 Report.error (source_reference, "Field initializers must not throw errors");
678 } else {
679 // store parent_node as we need to replace the expression in the old parent node later on
680 var old_parent_node = parent_node;
682 var local = new LocalVariable (value_type, get_temp_name (), null, source_reference);
683 // use floating variable to avoid unnecessary (and sometimes impossible) copies
684 local.floating = true;
685 var decl = new DeclarationStatement (local, source_reference);
687 insert_statement (context.analyzer.insert_block, decl);
689 Expression temp_access = new MemberAccess.simple (local.name, source_reference);
690 temp_access.target_type = target_type;
692 // don't set initializer earlier as this changes parent_node and parent_statement
693 local.initializer = this;
694 decl.check (context);
695 temp_access.check (context);
697 // move temp variable to insert block to ensure the
698 // variable is in the same block as the declaration
699 // otherwise there will be scoping issues in the generated code
700 var block = (Block) context.analyzer.current_symbol;
701 block.remove_local_variable (local);
702 context.analyzer.insert_block.add_local_variable (local);
704 old_parent_node.replace_expression (this, temp_access);
708 return !error;
711 public override void emit (CodeGenerator codegen) {
712 var method_type = call.value_type as MethodType;
714 if (method_type != null) {
715 // N_ and NC_ do not have any effect on the C code,
716 // they are only interpreted by xgettext
717 // this means that it is ok to use them in constant initializers
718 // however, we must avoid generating regular method call code
719 // as that may include temporary variables
720 if (method_type.method_symbol.get_full_name () == "GLib.N_") {
721 // first argument is string
722 argument_list[0].emit (codegen);
723 this.target_value = argument_list[0].target_value;
724 return;
725 } else if (method_type.method_symbol.get_full_name () == "GLib.NC_") {
726 // second argument is string
727 argument_list[1].emit (codegen);
728 this.target_value = argument_list[1].target_value;
729 return;
733 if (method_type != null && method_type.method_symbol.parent_symbol is Signal) {
734 var signal_access = ((MemberAccess) call).inner;
735 signal_access.emit (codegen);
736 } else {
737 call.emit (codegen);
740 foreach (Expression expr in argument_list) {
741 expr.emit (codegen);
744 codegen.visit_method_call (this);
746 codegen.visit_expression (this);
749 public override void get_defined_variables (Collection<LocalVariable> collection) {
750 call.get_defined_variables (collection);
752 foreach (Expression arg in argument_list) {
753 arg.get_defined_variables (collection);
757 public override void get_used_variables (Collection<LocalVariable> collection) {
758 call.get_used_variables (collection);
760 foreach (Expression arg in argument_list) {
761 arg.get_used_variables (collection);