travis: update
[m6w6/ext-psi] / src / types / return_exp.c
1 /*******************************************************************************
2 Copyright (c) 2017, Michael Wallner <mike@php.net>.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #else
29 # include "php_config.h"
30 #endif
31 #include "data.h"
32 #include "call.h"
33
34 struct psi_return_exp *psi_return_exp_init(struct psi_decl_var *func,
35 struct psi_plist *args, struct psi_set_exp *set)
36 {
37 struct psi_return_exp *exp = pecalloc(1, sizeof(*exp), 1);
38
39 exp->func = func;
40 exp->args = args;
41 exp->set = set;
42
43 return exp;
44 }
45
46 void psi_return_exp_free(struct psi_return_exp **exp_ptr)
47 {
48 if (*exp_ptr) {
49 struct psi_return_exp *exp = *exp_ptr;
50
51 *exp_ptr = NULL;
52 psi_token_free(&exp->token);
53 if (exp->func) {
54 psi_decl_var_free(&exp->func);
55 }
56 if (exp->args) {
57 psi_plist_free(exp->args);
58 exp->args = NULL;
59 }
60 if (exp->set) {
61 psi_set_exp_free(&exp->set);
62 }
63 free(exp);
64 }
65 }
66
67 void psi_return_exp_dump(struct psi_dump *dump, struct psi_return_exp *exp)
68 {
69 if (exp->func) {
70 psi_decl_var_dump(dump, exp->func);
71 PSI_DUMP(dump, "(");
72 if (exp->args) {
73 size_t i = 0;
74 struct psi_decl_var *arg;
75
76 while (psi_plist_get(exp->args, i++, &arg)) {
77 if (i > 1) {
78 PSI_DUMP(dump, ", ");
79 }
80 psi_decl_var_dump(dump, arg);
81 }
82 }
83 PSI_DUMP(dump, ")");
84 }
85 if (exp->set) {
86 if (exp->func) {
87 PSI_DUMP(dump, " as ");
88 }
89
90 psi_set_exp_dump(dump, exp->set, 1, 1);
91 }
92 }
93
94 void psi_return_exp_exec(struct psi_return_exp *exp, zval *return_value,
95 struct psi_call_frame *frame)
96 {
97 if (exp->set) {
98 void *rpointer = psi_call_frame_get_rpointer(frame);
99
100 psi_set_exp_exec_ex(exp->set, return_value, rpointer, frame);
101 }
102 }
103
104 static inline bool psi_return_exp_validate_decl_args(struct psi_data *data,
105 struct psi_return_exp *exp, struct psi_impl *impl)
106 {
107 size_t i;
108 struct psi_decl_var *call_arg;
109
110 if (exp->args) {
111 if (psi_plist_count(exp->args) != psi_plist_count(impl->decl->args)) {
112 data->error(data, exp->token, PSI_WARNING,
113 "Argument count of return statement of implementation '%s' "
114 "does not match argument count of declaration '%s'",
115 impl->func->name->val, impl->decl->func->var->name->val);
116 return false;
117 }
118
119 for (i = 0; psi_plist_get(exp->args, i, &call_arg); ++i) {
120 psi_plist_get(impl->decl->args, i, &call_arg->arg);
121 }
122 }
123 return true;
124 }
125
126 bool psi_return_exp_validate(struct psi_data *data, struct psi_return_exp *exp,
127 struct psi_validate_scope *scope)
128 {
129 size_t i = 0;
130 struct psi_decl *decl;
131 zend_string *name = psi_return_exp_get_decl_name(exp);
132
133
134 while (psi_plist_get(data->decls, i++, &decl)) {
135 if (zend_string_equals(decl->func->var->name, name)) {
136 scope->impl->decl = decl;
137 if (psi_return_exp_validate_decl_args(data, exp, scope->impl)) {
138 scope->current_set = exp->set;
139 if (psi_set_exp_validate(data, exp->set, scope)) {
140 scope->current_set = NULL;
141 return true;
142 }
143 scope->current_set = NULL;
144 }
145 return false;
146 }
147 }
148
149 data->error(data, exp->token, PSI_WARNING,
150 "Missing declaration '%s' for `return` statement of implementation %s",
151 name->val, scope->impl->func->name->val);
152 return false;
153 }
154
155 zend_string *psi_return_exp_get_decl_name(struct psi_return_exp *exp)
156 {
157 return exp->func ? exp->func->name : exp->set->data.func->var->name;
158 }
159