2020#include "zend_exceptions.h"
2121#include "zend_type_info.h"
2222
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 ;
2428
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 )
2632{
2733 zend_ast * class_name_ast = type_ast -> child [0 ];
2834 if (class_name_ast ) {
2935 if (Z_TYPE_P (zv ) != IS_OBJECT ) {
30- return false ;
36+ return PM_MISMATCH ;
3137 }
3238
3339 zend_object * obj = Z_OBJ_P (zv );
3440 zend_string * class_name = zend_ast_get_str (class_name_ast );
3541 if (!zend_string_equals_ci (obj -> ce -> name , class_name )) {
3642 zend_class_entry * expected_class = zend_lookup_class_ex (class_name , NULL , ZEND_FETCH_CLASS_NO_AUTOLOAD );
3743 if (!expected_class || !instanceof_function (Z_OBJ_P (zv )-> ce , expected_class )) {
38- return false ;
44+ return PM_MISMATCH ;
3945 }
4046 }
4147 } else {
4248 zend_type type = ZEND_TYPE_INIT_MASK (type_ast -> attr );
4349 if (!ZEND_TYPE_CONTAINS_CODE (type , Z_TYPE_P (zv ))) {
44- return false ;
50+ return PM_MISMATCH ;
4551 }
4652 }
4753
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 ;
5555}
5656
5757static bool match_zval (zval * lhs , zval * rhs )
@@ -68,26 +68,26 @@ static zend_class_entry *get_class_from_fetch_type(uint32_t fetch_type)
6868 scope = zend_get_executed_scope ();
6969 if (UNEXPECTED (!scope )) {
7070 zend_throw_error (NULL , "%s" , "Cannot access \"self\" when no class scope is active" );
71- pattern_matching_bailout () ;
71+ return NULL ;
7272 }
7373 return scope ;
7474 case ZEND_FETCH_CLASS_PARENT :
7575 scope = zend_get_executed_scope ();
7676 if (UNEXPECTED (!scope )) {
7777 zend_throw_error (NULL , "%s" , "Cannot access \"parent\" when no class scope is active" );
78- pattern_matching_bailout () ;
78+ return NULL ;
7979 }
8080 scope = scope -> parent ;
8181 if (UNEXPECTED (!scope )) {
8282 zend_throw_error (NULL , "%s" , "Cannot access \"parent\" when current class scope has no parent" );
83- pattern_matching_bailout () ;
83+ return NULL ;
8484 }
8585 return scope ;
8686 case ZEND_FETCH_CLASS_STATIC :
8787 scope = zend_get_called_scope (EG (current_execute_data ));
8888 if (UNEXPECTED (!scope )) {
8989 zend_throw_error (NULL , "%s" , "Cannot access \"static\" when no class scope is active" );
90- pattern_matching_bailout () ;
90+ return NULL ;
9191 }
9292 return scope ;
9393 EMPTY_SWITCH_DEFAULT_CASE ();
@@ -96,28 +96,31 @@ static zend_class_entry *get_class_from_fetch_type(uint32_t fetch_type)
9696 return NULL ;
9797}
9898
99- static bool match_object (zval * zv , zend_ast * pattern )
99+ static pm_result match_object (zval * zv , zend_ast * pattern )
100100{
101101 if (Z_TYPE_P (zv ) != IS_OBJECT ) {
102- return false ;
102+ return PM_MISMATCH ;
103103 }
104104
105105 zend_object * obj = Z_OBJ_P (zv );
106106 zend_ast * class_name_ast = pattern -> child [0 ];
107-
107+
108108 if (class_name_ast ) {
109109 zend_string * class_name = zend_ast_get_str (class_name_ast );
110110 if (!zend_string_equals_ci (obj -> ce -> name , class_name )) {
111111 zend_class_entry * expected_class = zend_lookup_class_ex (class_name , NULL , ZEND_FETCH_CLASS_NO_AUTOLOAD );
112112 if (!expected_class || !instanceof_function (Z_OBJ_P (zv )-> ce , expected_class )) {
113- return false ;
113+ return PM_MISMATCH ;
114114 }
115115 }
116116 } else {
117117 uint32_t fetch_type = pattern -> attr ;
118118 zend_class_entry * scope = get_class_from_fetch_type (fetch_type );
119+ if (EG (exception )) {
120+ return PM_ERROR ;
121+ }
119122 if (!instanceof_function (Z_OBJ_P (zv )-> ce , scope )) {
120- return false ;
123+ return PM_MISMATCH ;
121124 }
122125 }
123126
@@ -129,40 +132,40 @@ static bool match_object(zval *zv, zend_ast *pattern)
129132 zend_string * property_name = zend_ast_get_str (property_or_method_call );
130133 zval property_result_rv ;
131134 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 );
133136 if (property_result == & property_result_rv ) {
134137 zval_ptr_dtor (property_result );
135138 }
136- if (! element_matched ) {
137- return false ;
139+ if (element_matched != PM_MATCH ) {
140+ return element_matched ;
138141 }
139142 }
140143
141- return true ;
144+ return PM_MATCH ;
142145}
143146
144- static bool match_range (zval * zv , zend_ast * pattern )
147+ static pm_result match_range (zval * zv , zend_ast * pattern )
145148{
146149 zval * start = zend_ast_get_zval (pattern -> child [0 ]);
147150 zval * end = zend_ast_get_zval (pattern -> child [1 ]);
148151
149152 if (Z_TYPE_P (zv ) != Z_TYPE_P (start ) && zend_compare (zv , start ) == -1 ) {
150- return false ;
153+ return PM_MISMATCH ;
151154 }
152155
153156 int end_check = zend_compare (zv , end );
154157 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 ;
156159 }
157160
158- return true ;
161+ return PM_MATCH ;
159162}
160163
161- static bool match_binding (zval * zv , zend_ast * pattern )
164+ static pm_result match_binding (zval * zv , zend_ast * pattern )
162165{
163166 zend_ast * sub_pattern = pattern -> child [1 ];
164167 if (sub_pattern && !zend_pattern_match_ex (zv , sub_pattern )) {
165- return false ;
168+ return PM_MISMATCH ;
166169 }
167170
168171 // FIXME: Delay to the end of pattern matching
@@ -172,22 +175,22 @@ static bool match_binding(zval *zv, zend_ast *pattern)
172175 zend_assign_to_variable (cv , zv , IS_CV , EX_USES_STRICT_TYPES ());
173176 /* Destructor might throw */
174177 if (EG (exception )) {
175- pattern_matching_bailout () ;
178+ return PM_ERROR ;
176179 }
177- return true ;
180+ return PM_MATCH ;
178181}
179182
180- static bool match_array (zval * zv , zend_ast * pattern )
183+ static pm_result match_array (zval * zv , zend_ast * pattern )
181184{
182185 if (Z_TYPE_P (zv ) != IS_ARRAY ) {
183- return false ;
186+ return PM_MISMATCH ;
184187 }
185188
186189 HashTable * ht = Z_ARRVAL_P (zv );
187190 zend_ast_list * element_list = zend_ast_get_list (pattern -> child [0 ]);
188191
189192 if (!(pattern -> attr & ZEND_ARRAY_PATTERN_NON_EXHAUSTIVE ) && element_list -> children != zend_hash_num_elements (ht )) {
190- return false ;
193+ return PM_MISMATCH ;
191194 }
192195
193196 // FIXME: Deal with indexes properly
@@ -211,14 +214,14 @@ static bool match_array(zval *zv, zend_ast *pattern)
211214 index ++ ;
212215 }
213216 if (Z_TYPE_P (element_zv ) == IS_UNDEF || !zend_pattern_match_ex (element_zv , pattern_ast )) {
214- return false ;
217+ return PM_MISMATCH ;
215218 }
216219 }
217220
218- return true ;
221+ return PM_MATCH ;
219222}
220223
221- bool zend_pattern_match_ex (zval * zv , zend_ast * pattern )
224+ pm_result zend_pattern_match_ex (zval * zv , zend_ast * pattern )
222225{
223226 ZVAL_DEREF (zv );
224227 // FIXME: Do we need DEINDIRECT too?
@@ -231,10 +234,13 @@ bool zend_pattern_match_ex(zval *zv, zend_ast *pattern)
231234 case ZEND_AST_OBJECT_PATTERN :
232235 return match_object (zv , pattern );
233236 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 ]);
238244 case ZEND_AST_RANGE_PATTERN :
239245 return match_range (zv , pattern );
240246 case ZEND_AST_BINDING_PATTERN :
@@ -247,18 +253,5 @@ bool zend_pattern_match_ex(zval *zv, zend_ast *pattern)
247253
248254bool zend_pattern_match (zval * zv , zend_ast * pattern )
249255{
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 ;
264257}
0 commit comments