20
20
#include "zend_exceptions.h"
21
21
#include "zend_type_info.h"
22
22
23
- bool zend_pattern_match_ex (zval * zv , zend_ast * pattern );
23
+ typedef enum {
24
+ PM_ERROR = -1 ,
25
+ PM_MISMATCH = 0 ,
26
+ PM_MATCH = 1 ,
27
+ } pm_result ;
24
28
25
- static bool match_type (zval * zv , zend_ast * type_ast )
29
+ pm_result zend_pattern_match_ex (zval * zv , zend_ast * pattern );
30
+
31
+ static pm_result match_type (zval * zv , zend_ast * type_ast )
26
32
{
27
33
zend_ast * class_name_ast = type_ast -> child [0 ];
28
34
if (class_name_ast ) {
29
35
if (Z_TYPE_P (zv ) != IS_OBJECT ) {
30
- return false ;
36
+ return PM_MISMATCH ;
31
37
}
32
38
33
39
zend_object * obj = Z_OBJ_P (zv );
34
40
zend_string * class_name = zend_ast_get_str (class_name_ast );
35
41
if (!zend_string_equals_ci (obj -> ce -> name , class_name )) {
36
42
zend_class_entry * expected_class = zend_lookup_class_ex (class_name , NULL , ZEND_FETCH_CLASS_NO_AUTOLOAD );
37
43
if (!expected_class || !instanceof_function (Z_OBJ_P (zv )-> ce , expected_class )) {
38
- return false ;
44
+ return PM_MISMATCH ;
39
45
}
40
46
}
41
47
} else {
42
48
zend_type type = ZEND_TYPE_INIT_MASK (type_ast -> attr );
43
49
if (!ZEND_TYPE_CONTAINS_CODE (type , Z_TYPE_P (zv ))) {
44
- return false ;
50
+ return PM_MISMATCH ;
45
51
}
46
52
}
47
53
48
- return true;
49
- }
50
-
51
- static bool pattern_matching_bailout (void )
52
- {
53
- EG (pattern_matching_bailout ) = true;
54
- zend_bailout ();
54
+ return PM_MATCH ;
55
55
}
56
56
57
57
static bool match_zval (zval * lhs , zval * rhs )
@@ -68,26 +68,26 @@ static zend_class_entry *get_class_from_fetch_type(uint32_t fetch_type)
68
68
scope = zend_get_executed_scope ();
69
69
if (UNEXPECTED (!scope )) {
70
70
zend_throw_error (NULL , "%s" , "Cannot access \"self\" when no class scope is active" );
71
- pattern_matching_bailout () ;
71
+ return NULL ;
72
72
}
73
73
return scope ;
74
74
case ZEND_FETCH_CLASS_PARENT :
75
75
scope = zend_get_executed_scope ();
76
76
if (UNEXPECTED (!scope )) {
77
77
zend_throw_error (NULL , "%s" , "Cannot access \"parent\" when no class scope is active" );
78
- pattern_matching_bailout () ;
78
+ return NULL ;
79
79
}
80
80
scope = scope -> parent ;
81
81
if (UNEXPECTED (!scope )) {
82
82
zend_throw_error (NULL , "%s" , "Cannot access \"parent\" when current class scope has no parent" );
83
- pattern_matching_bailout () ;
83
+ return NULL ;
84
84
}
85
85
return scope ;
86
86
case ZEND_FETCH_CLASS_STATIC :
87
87
scope = zend_get_called_scope (EG (current_execute_data ));
88
88
if (UNEXPECTED (!scope )) {
89
89
zend_throw_error (NULL , "%s" , "Cannot access \"static\" when no class scope is active" );
90
- pattern_matching_bailout () ;
90
+ return NULL ;
91
91
}
92
92
return scope ;
93
93
EMPTY_SWITCH_DEFAULT_CASE ();
@@ -96,28 +96,31 @@ static zend_class_entry *get_class_from_fetch_type(uint32_t fetch_type)
96
96
return NULL ;
97
97
}
98
98
99
- static bool match_object (zval * zv , zend_ast * pattern )
99
+ static pm_result match_object (zval * zv , zend_ast * pattern )
100
100
{
101
101
if (Z_TYPE_P (zv ) != IS_OBJECT ) {
102
- return false ;
102
+ return PM_MISMATCH ;
103
103
}
104
104
105
105
zend_object * obj = Z_OBJ_P (zv );
106
106
zend_ast * class_name_ast = pattern -> child [0 ];
107
-
107
+
108
108
if (class_name_ast ) {
109
109
zend_string * class_name = zend_ast_get_str (class_name_ast );
110
110
if (!zend_string_equals_ci (obj -> ce -> name , class_name )) {
111
111
zend_class_entry * expected_class = zend_lookup_class_ex (class_name , NULL , ZEND_FETCH_CLASS_NO_AUTOLOAD );
112
112
if (!expected_class || !instanceof_function (Z_OBJ_P (zv )-> ce , expected_class )) {
113
- return false ;
113
+ return PM_MISMATCH ;
114
114
}
115
115
}
116
116
} else {
117
117
uint32_t fetch_type = pattern -> attr ;
118
118
zend_class_entry * scope = get_class_from_fetch_type (fetch_type );
119
+ if (EG (exception )) {
120
+ return PM_ERROR ;
121
+ }
119
122
if (!instanceof_function (Z_OBJ_P (zv )-> ce , scope )) {
120
- return false ;
123
+ return PM_MISMATCH ;
121
124
}
122
125
}
123
126
@@ -129,40 +132,40 @@ static bool match_object(zval *zv, zend_ast *pattern)
129
132
zend_string * property_name = zend_ast_get_str (property_or_method_call );
130
133
zval property_result_rv ;
131
134
zval * property_result = obj -> handlers -> read_property (obj , property_name , BP_VAR_R , NULL , & property_result_rv );
132
- bool element_matched = zend_pattern_match_ex (property_result , element_pattern );
135
+ pm_result element_matched = zend_pattern_match_ex (property_result , element_pattern );
133
136
if (property_result == & property_result_rv ) {
134
137
zval_ptr_dtor (property_result );
135
138
}
136
- if (! element_matched ) {
137
- return false ;
139
+ if (element_matched != PM_MATCH ) {
140
+ return element_matched ;
138
141
}
139
142
}
140
143
141
- return true ;
144
+ return PM_MATCH ;
142
145
}
143
146
144
- static bool match_range (zval * zv , zend_ast * pattern )
147
+ static pm_result match_range (zval * zv , zend_ast * pattern )
145
148
{
146
149
zval * start = zend_ast_get_zval (pattern -> child [0 ]);
147
150
zval * end = zend_ast_get_zval (pattern -> child [1 ]);
148
151
149
152
if (Z_TYPE_P (zv ) != Z_TYPE_P (start ) && zend_compare (zv , start ) == -1 ) {
150
- return false ;
153
+ return PM_MISMATCH ;
151
154
}
152
155
153
156
int end_check = zend_compare (zv , end );
154
157
if (Z_TYPE_P (zv ) != Z_TYPE_P (end ) || end_check == 1 || (!(pattern -> attr & ZEND_AST_RANGE_INCLUSIVE_END ) && end_check == 0 )) {
155
- return false ;
158
+ return PM_MISMATCH ;
156
159
}
157
160
158
- return true ;
161
+ return PM_MATCH ;
159
162
}
160
163
161
- static bool match_binding (zval * zv , zend_ast * pattern )
164
+ static pm_result match_binding (zval * zv , zend_ast * pattern )
162
165
{
163
166
zend_ast * sub_pattern = pattern -> child [1 ];
164
167
if (sub_pattern && !zend_pattern_match_ex (zv , sub_pattern )) {
165
- return false ;
168
+ return PM_MISMATCH ;
166
169
}
167
170
168
171
// FIXME: Delay to the end of pattern matching
@@ -172,22 +175,22 @@ static bool match_binding(zval *zv, zend_ast *pattern)
172
175
zend_assign_to_variable (cv , zv , IS_CV , EX_USES_STRICT_TYPES ());
173
176
/* Destructor might throw */
174
177
if (EG (exception )) {
175
- pattern_matching_bailout () ;
178
+ return PM_ERROR ;
176
179
}
177
- return true ;
180
+ return PM_MATCH ;
178
181
}
179
182
180
- static bool match_array (zval * zv , zend_ast * pattern )
183
+ static pm_result match_array (zval * zv , zend_ast * pattern )
181
184
{
182
185
if (Z_TYPE_P (zv ) != IS_ARRAY ) {
183
- return false ;
186
+ return PM_MISMATCH ;
184
187
}
185
188
186
189
HashTable * ht = Z_ARRVAL_P (zv );
187
190
zend_ast_list * element_list = zend_ast_get_list (pattern -> child [0 ]);
188
191
189
192
if (!(pattern -> attr & ZEND_ARRAY_PATTERN_NON_EXHAUSTIVE ) && element_list -> children != zend_hash_num_elements (ht )) {
190
- return false ;
193
+ return PM_MISMATCH ;
191
194
}
192
195
193
196
// FIXME: Deal with indexes properly
@@ -211,14 +214,14 @@ static bool match_array(zval *zv, zend_ast *pattern)
211
214
index ++ ;
212
215
}
213
216
if (Z_TYPE_P (element_zv ) == IS_UNDEF || !zend_pattern_match_ex (element_zv , pattern_ast )) {
214
- return false ;
217
+ return PM_MISMATCH ;
215
218
}
216
219
}
217
220
218
- return true ;
221
+ return PM_MATCH ;
219
222
}
220
223
221
- bool zend_pattern_match_ex (zval * zv , zend_ast * pattern )
224
+ pm_result zend_pattern_match_ex (zval * zv , zend_ast * pattern )
222
225
{
223
226
ZVAL_DEREF (zv );
224
227
// FIXME: Do we need DEINDIRECT too?
@@ -231,10 +234,13 @@ bool zend_pattern_match_ex(zval *zv, zend_ast *pattern)
231
234
case ZEND_AST_OBJECT_PATTERN :
232
235
return match_object (zv , pattern );
233
236
case ZEND_AST_WILDCARD_PATTERN :
234
- return true;
235
- case ZEND_AST_OR_PATTERN :
236
- return zend_pattern_match_ex (zv , pattern -> child [0 ])
237
- || zend_pattern_match_ex (zv , pattern -> child [1 ]);
237
+ return PM_MATCH ;
238
+ case ZEND_AST_OR_PATTERN :;
239
+ pm_result lhs = zend_pattern_match_ex (zv , pattern -> child [0 ]);
240
+ if (lhs != PM_MISMATCH ) {
241
+ return lhs ;
242
+ }
243
+ return zend_pattern_match_ex (zv , pattern -> child [1 ]);
238
244
case ZEND_AST_RANGE_PATTERN :
239
245
return match_range (zv , pattern );
240
246
case ZEND_AST_BINDING_PATTERN :
@@ -247,18 +253,5 @@ bool zend_pattern_match_ex(zval *zv, zend_ast *pattern)
247
253
248
254
bool zend_pattern_match (zval * zv , zend_ast * pattern )
249
255
{
250
- bool result ;
251
-
252
- zend_first_try {
253
- result = zend_pattern_match_ex (zv , pattern );
254
- } zend_catch {
255
- if (!EG (pattern_matching_bailout )) {
256
- zend_bailout ();
257
- }
258
- ZEND_ASSERT (EG (exception ));
259
- EG (pattern_matching_bailout ) = false;
260
- return false;
261
- } zend_end_try ();
262
-
263
- return result ;
256
+ return zend_pattern_match_ex (zv , pattern ) == PM_MATCH ;
264
257
}
0 commit comments