diff options
| author | Ilija Tovilo <ilija.tovilo@me.com> | 2020-04-09 22:36:37 +0200 |
|---|---|---|
| committer | Ilija Tovilo <ilija.tovilo@me.com> | 2020-07-09 23:52:17 +0200 |
| commit | 9fa1d1330138ac424f990ff03e62721120aaaec3 (patch) | |
| tree | ca3550c82b86ccf844745fbe80c77134ed5cbef4 /ext | |
| parent | c60d0dc2f41f1d4817414e37a39ae87c5677e31a (diff) | |
| download | php-git-9fa1d1330138ac424f990ff03e62721120aaaec3.tar.gz | |
Implement match expression
RFC: https://wiki.php.net/rfc/match_expression_v2
Closes GH-5371.
Diffstat (limited to 'ext')
| -rw-r--r-- | ext/opcache/Optimizer/block_pass.c | 11 | ||||
| -rw-r--r-- | ext/opcache/Optimizer/dce.c | 5 | ||||
| -rw-r--r-- | ext/opcache/Optimizer/dfa_pass.c | 46 | ||||
| -rw-r--r-- | ext/opcache/Optimizer/pass1.c | 2 | ||||
| -rw-r--r-- | ext/opcache/Optimizer/sccp.c | 41 | ||||
| -rw-r--r-- | ext/opcache/Optimizer/zend_cfg.c | 16 | ||||
| -rw-r--r-- | ext/opcache/Optimizer/zend_dump.c | 6 | ||||
| -rw-r--r-- | ext/opcache/Optimizer/zend_inference.c | 4 | ||||
| -rw-r--r-- | ext/opcache/Optimizer/zend_optimizer.c | 25 | ||||
| -rw-r--r-- | ext/opcache/jit/zend_jit.c | 6 | ||||
| -rw-r--r-- | ext/opcache/jit/zend_jit_trace.c | 3 | ||||
| -rw-r--r-- | ext/opcache/jit/zend_jit_x86.dasc | 7 | ||||
| -rw-r--r-- | ext/opcache/tests/match/001.phpt | 71 | ||||
| -rw-r--r-- | ext/opcache/tests/match/002.phpt | 57 | ||||
| -rw-r--r-- | ext/opcache/tests/match/003.phpt | 74 | ||||
| -rw-r--r-- | ext/opcache/tests/match/004.phpt | 93 | ||||
| -rw-r--r-- | ext/opcache/zend_file_cache.c | 1 | ||||
| -rw-r--r-- | ext/opcache/zend_persist.c | 1 | ||||
| -rw-r--r-- | ext/standard/tests/file/fnmatch_variation.phpt | 10 | ||||
| -rw-r--r-- | ext/tokenizer/tokenizer_data.c | 22 |
20 files changed, 424 insertions, 77 deletions
diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 59429082f7..aee3931f05 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -115,6 +115,10 @@ static int get_const_switch_target(zend_cfg *cfg, zend_op_array *op_array, zend_ /* fallback to next block */ return block->successors[block->successors_count - 1]; } + if (opline->opcode == ZEND_MATCH && Z_TYPE_P(val) != IS_LONG && Z_TYPE_P(val) != IS_STRING) { + /* always jump to the default arm */ + return block->successors[block->successors_count - 1]; + } if (Z_TYPE_P(val) == IS_LONG) { zv = zend_hash_index_find(jumptable, Z_LVAL_P(val)); } else { @@ -123,7 +127,7 @@ static int get_const_switch_target(zend_cfg *cfg, zend_op_array *op_array, zend_ } if (!zv) { /* default */ - return block->successors[block->successors_count - 2]; + return block->successors[block->successors_count - (opline->opcode == ZEND_MATCH ? 1 : 2)]; } return cfg->map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(zv))]; } @@ -369,6 +373,7 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array case ZEND_SWITCH_LONG: case ZEND_SWITCH_STRING: + case ZEND_MATCH: if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { /* SWITCH variable will be deleted later by FREE, so we can't optimize it */ Tsource[VAR_NUM(opline->op1.var)] = NULL; @@ -387,6 +392,7 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array break; case ZEND_CASE: + case ZEND_CASE_STRICT: case ZEND_COPY_TMP: if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { /* Variable will be deleted later by FREE, so we can't optimize it */ @@ -1046,11 +1052,12 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_op break; case ZEND_SWITCH_LONG: case ZEND_SWITCH_STRING: + case ZEND_MATCH: { HashTable *jumptable = Z_ARRVAL(ZEND_OP2_LITERAL(opline)); zval *zv; uint32_t s = 0; - ZEND_ASSERT(b->successors_count == 2 + zend_hash_num_elements(jumptable)); + ZEND_ASSERT(b->successors_count == (opline->opcode == ZEND_MATCH ? 1 : 2) + zend_hash_num_elements(jumptable)); ZEND_HASH_FOREACH_VAL(jumptable, zv) { Z_LVAL_P(zv) = ZEND_OPLINE_TO_OFFSET(opline, new_opcodes + blocks[b->successors[s++]].start); diff --git a/ext/opcache/Optimizer/dce.c b/ext/opcache/Optimizer/dce.c index 43f2ef71a2..9f533ea167 100644 --- a/ext/opcache/Optimizer/dce.c +++ b/ext/opcache/Optimizer/dce.c @@ -106,6 +106,7 @@ static inline zend_bool may_have_side_effects( case ZEND_IS_SMALLER: case ZEND_IS_SMALLER_OR_EQUAL: case ZEND_CASE: + case ZEND_CASE_STRICT: case ZEND_CAST: case ZEND_ROPE_INIT: case ZEND_ROPE_ADD: @@ -146,6 +147,7 @@ static inline zend_bool may_have_side_effects( case ZEND_ECHO: case ZEND_INCLUDE_OR_EVAL: case ZEND_THROW: + case ZEND_MATCH_ERROR: case ZEND_EXT_STMT: case ZEND_EXT_FCALL_BEGIN: case ZEND_EXT_FCALL_END: @@ -391,7 +393,8 @@ static zend_bool dce_instr(context *ctx, zend_op *opline, zend_ssa_op *ssa_op) { if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))&& !is_var_dead(ctx, ssa_op->op1_use)) { if (!try_remove_var_def(ctx, ssa_op->op1_use, ssa_op->op1_use_chain, opline)) { if (ssa->var_info[ssa_op->op1_use].type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF) - && opline->opcode != ZEND_CASE) { + && opline->opcode != ZEND_CASE + && opline->opcode != ZEND_CASE_STRICT) { free_var = ssa_op->op1_use; free_var_type = opline->op1_type; } diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c index a8bff00557..0b69323980 100644 --- a/ext/opcache/Optimizer/dfa_pass.c +++ b/ext/opcache/Optimizer/dfa_pass.c @@ -641,6 +641,7 @@ static void zend_ssa_replace_control_link(zend_op_array *op_array, zend_ssa *ssa break; case ZEND_SWITCH_LONG: case ZEND_SWITCH_STRING: + case ZEND_MATCH: { HashTable *jumptable = Z_ARRVAL(ZEND_OP2_LITERAL(opline)); zval *zv; @@ -895,48 +896,29 @@ optimize_jmpnz: break; } case ZEND_SWITCH_LONG: - if (opline->op1_type == IS_CONST) { - zval *zv = CT_CONSTANT_EX(op_array, opline->op1.constant); - if (Z_TYPE_P(zv) != IS_LONG) { - removed_ops++; - MAKE_NOP(opline); - opline->extended_value = 0; - take_successor_ex(ssa, block_num, block, block->successors[0]); - goto optimize_nop; - } else { - HashTable *jmptable = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, opline->op2.constant)); - zval *jmp_zv = zend_hash_index_find(jmptable, Z_LVAL_P(zv)); - uint32_t target; - - if (jmp_zv) { - target = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(jmp_zv)); - } else { - target = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value); - } - opline->opcode = ZEND_JMP; - opline->extended_value = 0; - SET_UNUSED(opline->op1); - ZEND_SET_OP_JMP_ADDR(opline, opline->op1, op_array->opcodes + target); - SET_UNUSED(opline->op2); - take_successor_ex(ssa, block_num, block, ssa->cfg.map[target]); - goto optimize_jmp; - } - } - break; case ZEND_SWITCH_STRING: + case ZEND_MATCH: if (opline->op1_type == IS_CONST) { zval *zv = CT_CONSTANT_EX(op_array, opline->op1.constant); - if (Z_TYPE_P(zv) != IS_STRING) { + zend_uchar type = Z_TYPE_P(zv); + zend_bool correct_type = + (opline->opcode == ZEND_SWITCH_LONG && type == IS_LONG) + || (opline->opcode == ZEND_SWITCH_STRING && type == IS_STRING) + || (opline->opcode == ZEND_MATCH && (type == IS_LONG || type == IS_STRING)); + + if (!correct_type) { removed_ops++; MAKE_NOP(opline); opline->extended_value = 0; - take_successor_ex(ssa, block_num, block, block->successors[0]); + take_successor_ex(ssa, block_num, block, block->successors[block->successors_count - 1]); goto optimize_nop; } else { HashTable *jmptable = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, opline->op2.constant)); - zval *jmp_zv = zend_hash_find(jmptable, Z_STR_P(zv)); - uint32_t target; + zval *jmp_zv = type == IS_LONG + ? zend_hash_index_find(jmptable, Z_LVAL_P(zv)) + : zend_hash_find(jmptable, Z_STR_P(zv)); + uint32_t target; if (jmp_zv) { target = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(jmp_zv)); } else { diff --git a/ext/opcache/Optimizer/pass1.c b/ext/opcache/Optimizer/pass1.c index 3beb1788a3..fee0e1eac3 100644 --- a/ext/opcache/Optimizer/pass1.c +++ b/ext/opcache/Optimizer/pass1.c @@ -82,6 +82,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx) case ZEND_BOOL_XOR: case ZEND_SPACESHIP: case ZEND_CASE: + case ZEND_CASE_STRICT: if (opline->op1_type == IS_CONST && opline->op2_type == IS_CONST) { /* binary operation with constant operands */ @@ -663,6 +664,7 @@ constant_binary_op: case ZEND_GENERATOR_RETURN: case ZEND_EXIT: case ZEND_THROW: + case ZEND_MATCH_ERROR: case ZEND_CATCH: case ZEND_FAST_CALL: case ZEND_FAST_RET: diff --git a/ext/opcache/Optimizer/sccp.c b/ext/opcache/Optimizer/sccp.c index c51b5c3ee2..ee8ccc34a7 100644 --- a/ext/opcache/Optimizer/sccp.c +++ b/ext/opcache/Optimizer/sccp.c @@ -300,10 +300,15 @@ static zend_bool try_replace_op1( switch (opline->opcode) { case ZEND_CASE: opline->opcode = ZEND_IS_EQUAL; - /* break missing intentionally */ + goto replace_op1_simple; + case ZEND_CASE_STRICT: + opline->opcode = ZEND_IS_IDENTICAL; + goto replace_op1_simple; case ZEND_FETCH_LIST_R: case ZEND_SWITCH_STRING: case ZEND_SWITCH_LONG: + case ZEND_MATCH: +replace_op1_simple: if (Z_TYPE(zv) == IS_STRING) { zend_string_hash_val(Z_STR(zv)); } @@ -1460,6 +1465,7 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o case ZEND_BW_XOR: case ZEND_BOOL_XOR: case ZEND_CASE: + case ZEND_CASE_STRICT: SKIP_IF_TOP(op1); SKIP_IF_TOP(op2); @@ -1986,11 +1992,23 @@ static void sccp_mark_feasible_successors( s = zend_hash_num_elements(Z_ARR_P(op1)) != 0; break; case ZEND_SWITCH_LONG: - if (Z_TYPE_P(op1) == IS_LONG) { + case ZEND_SWITCH_STRING: + case ZEND_MATCH: + { + zend_bool strict_comparison = opline->opcode == ZEND_MATCH; + zend_uchar type = Z_TYPE_P(op1); + zend_bool correct_type = + (opline->opcode == ZEND_SWITCH_LONG && type == IS_LONG) + || (opline->opcode == ZEND_SWITCH_STRING && type == IS_STRING) + || (opline->opcode == ZEND_MATCH && (type == IS_LONG || type == IS_STRING)); + + if (correct_type) { zend_op_array *op_array = scdf->op_array; zend_ssa *ssa = scdf->ssa; HashTable *jmptable = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, opline->op2.constant)); - zval *jmp_zv = zend_hash_index_find(jmptable, Z_LVAL_P(op1)); + zval *jmp_zv = type == IS_LONG + ? zend_hash_index_find(jmptable, Z_LVAL_P(op1)) + : zend_hash_find(jmptable, Z_STR_P(op1)); int target; if (jmp_zv) { @@ -2000,27 +2018,16 @@ static void sccp_mark_feasible_successors( } scdf_mark_edge_feasible(scdf, block_num, target); return; - } - s = 0; - break; - case ZEND_SWITCH_STRING: - if (Z_TYPE_P(op1) == IS_STRING) { + } else if (strict_comparison) { zend_op_array *op_array = scdf->op_array; zend_ssa *ssa = scdf->ssa; - HashTable *jmptable = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, opline->op2.constant)); - zval *jmp_zv = zend_hash_find(jmptable, Z_STR_P(op1)); - int target; - - if (jmp_zv) { - target = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(jmp_zv))]; - } else { - target = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]; - } + int target = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]; scdf_mark_edge_feasible(scdf, block_num, target); return; } s = 0; break; + } default: for (s = 0; s < block->successors_count; s++) { scdf_mark_edge_feasible(scdf, block_num, block->successors[s]); diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c index 6ac5781e09..d80edda3e1 100644 --- a/ext/opcache/Optimizer/zend_cfg.c +++ b/ext/opcache/Optimizer/zend_cfg.c @@ -73,7 +73,11 @@ static void zend_mark_reachable(zend_op *opcodes, zend_cfg *cfg, zend_basic_bloc succ->flags |= ZEND_BB_FOLLOW; } } else { - ZEND_ASSERT(opcode == ZEND_SWITCH_LONG || opcode == ZEND_SWITCH_STRING); + ZEND_ASSERT( + opcode == ZEND_SWITCH_LONG + || opcode == ZEND_SWITCH_STRING + || opcode == ZEND_MATCH + ); if (i == b->successors_count - 1) { succ->flags |= ZEND_BB_FOLLOW | ZEND_BB_TARGET; } else { @@ -296,6 +300,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b case ZEND_RETURN_BY_REF: case ZEND_GENERATOR_RETURN: case ZEND_EXIT: + case ZEND_MATCH_ERROR: if (i + 1 < op_array->last) { BB_START(i + 1); } @@ -391,6 +396,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b break; case ZEND_SWITCH_LONG: case ZEND_SWITCH_STRING: + case ZEND_MATCH: { HashTable *jumptable = Z_ARRVAL_P(CRT_CONSTANT(opline->op2)); zval *zv; @@ -507,6 +513,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b case ZEND_GENERATOR_RETURN: case ZEND_EXIT: case ZEND_THROW: + case ZEND_MATCH_ERROR: break; case ZEND_JMP: block->successors_count = 1; @@ -557,12 +564,13 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b break; case ZEND_SWITCH_LONG: case ZEND_SWITCH_STRING: + case ZEND_MATCH: { HashTable *jumptable = Z_ARRVAL_P(CRT_CONSTANT(opline->op2)); zval *zv; uint32_t s = 0; - block->successors_count = 2 + zend_hash_num_elements(jumptable); + block->successors_count = (opline->opcode == ZEND_MATCH ? 1 : 2) + zend_hash_num_elements(jumptable); block->successors = zend_arena_calloc(arena, block->successors_count, sizeof(int)); ZEND_HASH_FOREACH_VAL(jumptable, zv) { @@ -570,7 +578,9 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b } ZEND_HASH_FOREACH_END(); block->successors[s++] = block_map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)]; - block->successors[s++] = j + 1; + if (opline->opcode != ZEND_MATCH) { + block->successors[s++] = j + 1; + } break; } default: diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c index dfd939f332..ce23c4d473 100644 --- a/ext/opcache/Optimizer/zend_dump.c +++ b/ext/opcache/Optimizer/zend_dump.c @@ -615,7 +615,11 @@ void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *b, cons if (opline->op2_type == IS_CONST) { zval *op = CRT_CONSTANT(opline->op2); - if (opline->opcode == ZEND_SWITCH_LONG || opline->opcode == ZEND_SWITCH_STRING) { + if ( + opline->opcode == ZEND_SWITCH_LONG + || opline->opcode == ZEND_SWITCH_STRING + || opline->opcode == ZEND_MATCH + ) { HashTable *jumptable = Z_ARRVAL_P(op); zend_string *key; zend_ulong num_key; diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index c4189975d5..00708ca11b 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -2413,6 +2413,7 @@ static zend_always_inline int _zend_update_type_info( case ZEND_JMPZ_EX: case ZEND_JMPNZ_EX: case ZEND_CASE: + case ZEND_CASE_STRICT: case ZEND_BOOL: case ZEND_ISSET_ISEMPTY_CV: case ZEND_ISSET_ISEMPTY_VAR: @@ -4312,6 +4313,7 @@ int zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op, const ze if (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)) { switch (opline->opcode) { case ZEND_CASE: + case ZEND_CASE_STRICT: case ZEND_FE_FETCH_R: case ZEND_FE_FETCH_RW: case ZEND_FETCH_LIST_R: @@ -4380,12 +4382,14 @@ int zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op, const ze case ZEND_COALESCE: case ZEND_SWITCH_LONG: case ZEND_SWITCH_STRING: + case ZEND_MATCH: case ZEND_ISSET_ISEMPTY_VAR: case ZEND_ISSET_ISEMPTY_CV: case ZEND_FUNC_NUM_ARGS: case ZEND_FUNC_GET_ARGS: case ZEND_COPY_TMP: case ZEND_CHECK_FUNC_ARG: + case ZEND_CASE_STRICT: return 0; case ZEND_INIT_FCALL: /* can't throw, because call is resolved at compile time */ diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 8456c46078..78b5893b2f 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -293,6 +293,7 @@ int zend_optimizer_update_op1_const(zend_op_array *op_array, * zend_optimizer_replace_by_const() supports this. */ return 0; case ZEND_CASE: + case ZEND_CASE_STRICT: case ZEND_FETCH_LIST_R: case ZEND_COPY_TMP: case ZEND_FETCH_CLASS_NAME: @@ -558,7 +559,7 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array, break; /* In most cases IS_TMP_VAR operand may be used only once. * The operands are usually destroyed by the opcode handler. - * ZEND_CASE and ZEND_FETCH_LIST_R are exceptions, they keeps operand + * ZEND_CASE[_STRICT] and ZEND_FETCH_LIST_R are exceptions, they keeps operand * unchanged, and allows its reuse. these instructions * usually terminated by ZEND_FREE that finally kills the value. */ @@ -587,17 +588,25 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array, } case ZEND_SWITCH_LONG: case ZEND_SWITCH_STRING: - case ZEND_CASE: { + case ZEND_MATCH: + case ZEND_CASE: + case ZEND_CASE_STRICT: { zend_op *end = op_array->opcodes + op_array->last; while (opline < end) { if (opline->op1_type == type && opline->op1.var == var) { - if (opline->opcode == ZEND_CASE - || opline->opcode == ZEND_SWITCH_LONG - || opline->opcode == ZEND_SWITCH_STRING) { + if ( + opline->opcode == ZEND_CASE + || opline->opcode == ZEND_CASE_STRICT + || opline->opcode == ZEND_SWITCH_LONG + || opline->opcode == ZEND_SWITCH_STRING + || opline->opcode == ZEND_MATCH + ) { zval v; if (opline->opcode == ZEND_CASE) { opline->opcode = ZEND_IS_EQUAL; + } else if (opline->opcode == ZEND_CASE_STRICT) { + opline->opcode = ZEND_IS_IDENTICAL; } ZVAL_COPY(&v, val); if (Z_TYPE(v) == IS_STRING) { @@ -687,6 +696,7 @@ void zend_optimizer_migrate_jump(zend_op_array *op_array, zend_op *new_opline, z break; case ZEND_SWITCH_LONG: case ZEND_SWITCH_STRING: + case ZEND_MATCH: { HashTable *jumptable = Z_ARRVAL(ZEND_OP2_LITERAL(opline)); zval *zv; @@ -731,6 +741,7 @@ void zend_optimizer_shift_jump(zend_op_array *op_array, zend_op *opline, uint32_ break; case ZEND_SWITCH_LONG: case ZEND_SWITCH_STRING: + case ZEND_MATCH: { HashTable *jumptable = Z_ARRVAL(ZEND_OP2_LITERAL(opline)); zval *zv; @@ -1105,6 +1116,7 @@ static void zend_redo_pass_two(zend_op_array *op_array) case ZEND_FE_FETCH_RW: case ZEND_SWITCH_LONG: case ZEND_SWITCH_STRING: + case ZEND_MATCH: /* relative extended_value don't have to be changed */ break; #endif @@ -1115,6 +1127,7 @@ static void zend_redo_pass_two(zend_op_array *op_array) case ZEND_IS_SMALLER: case ZEND_IS_SMALLER_OR_EQUAL: case ZEND_CASE: + case ZEND_CASE_STRICT: case ZEND_ISSET_ISEMPTY_CV: case ZEND_ISSET_ISEMPTY_VAR: case ZEND_ISSET_ISEMPTY_DIM_OBJ: @@ -1225,6 +1238,7 @@ static void zend_redo_pass_two_ex(zend_op_array *op_array, zend_ssa *ssa) case ZEND_FE_FETCH_RW: case ZEND_SWITCH_LONG: case ZEND_SWITCH_STRING: + case ZEND_MATCH: /* relative extended_value don't have to be changed */ break; #endif @@ -1235,6 +1249,7 @@ static void zend_redo_pass_two_ex(zend_op_array *op_array, zend_ssa *ssa) case ZEND_IS_SMALLER: case ZEND_IS_SMALLER_OR_EQUAL: case ZEND_CASE: + case ZEND_CASE_STRICT: case ZEND_ISSET_ISEMPTY_CV: case ZEND_ISSET_ISEMPTY_VAR: case ZEND_ISSET_ISEMPTY_DIM_OBJ: diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 8c46cf9676..d0c1178d69 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -2120,7 +2120,8 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op && ssa->cfg.blocks[b].start != 0 && (op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_NOP || op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_SWITCH_LONG - || op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_SWITCH_STRING)) { + || op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_SWITCH_STRING + || op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_MATCH)) { if (!zend_jit_reset_opline(&dasm_state, op_array->opcodes + ssa->cfg.blocks[b].start) || !zend_jit_set_valid_ip(&dasm_state, op_array->opcodes + ssa->cfg.blocks[b].start)) { goto jit_failure; @@ -2851,6 +2852,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op goto done; case ZEND_SWITCH_LONG: case ZEND_SWITCH_STRING: + case ZEND_MATCH: if (!zend_jit_switch(&dasm_state, opline, op_array, ssa)) { goto jit_failure; } @@ -2898,6 +2900,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op case ZEND_OP_DATA: case ZEND_SWITCH_LONG: case ZEND_SWITCH_STRING: + case ZEND_MATCH: break; case ZEND_JMP: if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) { @@ -2920,6 +2923,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op case ZEND_RETURN_BY_REF: case ZEND_RETURN: case ZEND_EXIT: + case ZEND_MATCH_ERROR: /* switch through trampoline */ case ZEND_YIELD: case ZEND_YIELD_FROM: diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 8bbd3debee..278b3e6151 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -279,6 +279,7 @@ static int zend_jit_trace_may_exit(const zend_op_array *op_array, const zend_op case ZEND_FE_FETCH_RW: case ZEND_SWITCH_LONG: case ZEND_SWITCH_STRING: + case ZEND_MATCH: /* branch opcodes */ return 1; case ZEND_NEW: @@ -296,6 +297,7 @@ static int zend_jit_trace_may_exit(const zend_op_array *op_array, const zend_op case ZEND_YIELD: case ZEND_YIELD_FROM: case ZEND_INCLUDE_OR_EVAL: + case ZEND_MATCH_ERROR: /* unsupported */ return 1; case ZEND_DO_FCALL: @@ -3943,6 +3945,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par #if 0 case ZEND_SWITCH_LONG: case ZEND_SWITCH_STRING: + case ZEND_MATCH: if (!zend_jit_switch(&dasm_state, opline, op_array, op_array_ssa)) { goto jit_failure; } diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index cfd3b0f4cb..46145a83bb 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -11377,6 +11377,13 @@ static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_o { HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2)); + // TODO: Implement for match instructions + if (opline->opcode == ZEND_MATCH) { + // Since the match expression doesn't have a IS_IDENTICAL/JMPNZ chain + // we can't skip the jumptable and thus can't JIT the function + return 0; + } + if (opline->op1_type == IS_CONST) { zval *zv = RT_CONSTANT(opline, opline->op1); zval *jump_zv; diff --git a/ext/opcache/tests/match/001.phpt b/ext/opcache/tests/match/001.phpt new file mode 100644 index 0000000000..0f6c4f0707 --- /dev/null +++ b/ext/opcache/tests/match/001.phpt @@ -0,0 +1,71 @@ +--TEST-- +Match expression string jump table +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.opt_debug_level=0x20000 +--SKIPIF-- +<?php require_once(__DIR__ . '/../skipif.inc'); ?> +--FILE-- +<?php + +function test($char) { + return match ($char) { + 'a' => 'a', + 'b', 'c' => 'b, c', + 'd' => 'd', + 'e', 'f' => 'e, f', + 'g' => 'g', + 'h', 'i' => 'h, i', + }; +} + +foreach (range('a', 'i') as $char) { + var_dump(test($char)); +} + +--EXPECTF-- +$_main: + ; (lines=15, args=0, vars=1, tmps=2) + ; (after optimizer) + ; %s +0000 INIT_FCALL 2 %d string("range") +0001 SEND_VAL string("a") 1 +0002 SEND_VAL string("i") 2 +0003 V2 = DO_ICALL +0004 V1 = FE_RESET_R V2 0013 +0005 FE_FETCH_R V1 CV0($char) 0013 +0006 INIT_FCALL 1 %d string("var_dump") +0007 INIT_FCALL 1 %d string("test") +0008 SEND_VAR CV0($char) 1 +0009 V2 = DO_UCALL +0010 SEND_VAR V2 1 +0011 DO_ICALL +0012 JMP 0005 +0013 FE_FREE V1 +0014 RETURN int(1) +LIVE RANGES: + 1: 0005 - 0013 (loop) + +test: + ; (lines=9, args=1, vars=1, tmps=0) + ; (after optimizer) + ; %s +0000 CV0($char) = RECV 1 +0001 MATCH CV0($char) "a": 0002, "b": 0003, "c": 0003, "d": 0004, "e": 0005, "f": 0005, "g": 0006, "h": 0007, "i": 0007, default: 0008 +0002 RETURN string("a") +0003 RETURN string("b, c") +0004 RETURN string("d") +0005 RETURN string("e, f") +0006 RETURN string("g") +0007 RETURN string("h, i") +0008 MATCH_ERROR CV0($char) +string(1) "a" +string(4) "b, c" +string(4) "b, c" +string(1) "d" +string(4) "e, f" +string(4) "e, f" +string(1) "g" +string(4) "h, i" +string(4) "h, i" diff --git a/ext/opcache/tests/match/002.phpt b/ext/opcache/tests/match/002.phpt new file mode 100644 index 0000000000..22f29eeb8b --- /dev/null +++ b/ext/opcache/tests/match/002.phpt @@ -0,0 +1,57 @@ +--TEST-- +Test match jump table optimizer +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.opt_debug_level=0x20000 +--SKIPIF-- +<?php require_once(__DIR__ . '/../skipif.inc'); ?> +--FILE-- +<?php + +function test() { + $x = '2'; + echo match($x) { + 1, 2, 3, 4, 5 => throw new RuntimeException(), + default => "No match\n", + }; +} +test(); + +function test2() { + $x = 2; + echo match($x) { + '1', '2', '3', '4', '5' => throw new RuntimeException(), + default => "No match\n", + }; +} +test2(); + +--EXPECTF-- +$_main: + ; (lines=5, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %s +0000 INIT_FCALL 0 %d string("test") +0001 DO_UCALL +0002 INIT_FCALL 0 %d string("test2") +0003 DO_UCALL +0004 RETURN int(1) + +test: + ; (lines=2, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %s +0000 ECHO string("No match +") +0001 RETURN null + +test2: + ; (lines=2, args=0, vars=0, tmps=0) + ; (after optimizer) + ; %s +0000 ECHO string("No match +") +0001 RETURN null +No match +No match diff --git a/ext/opcache/tests/match/003.phpt b/ext/opcache/tests/match/003.phpt new file mode 100644 index 0000000000..f7f8896073 --- /dev/null +++ b/ext/opcache/tests/match/003.phpt @@ -0,0 +1,74 @@ +--TEST-- +Match expression long jump table +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.opt_debug_level=0x20000 +--SKIPIF-- +<?php require_once(__DIR__ . '/../skipif.inc'); ?> +--FILE-- +<?php + +function test($char) { + return match ($char) { + 1 => '1', + 2, 3 => '2, 3', + 4 => '4', + 5, 6 => '5, 6', + 7 => '7', + 8, 9 => '8, 9', + default => 'default' + }; +} + +foreach (range(0, 10) as $char) { + var_dump(test($char)); +} + +--EXPECTF-- +$_main: + ; (lines=15, args=0, vars=1, tmps=2) + ; (after optimizer) + ; %s +0000 INIT_FCALL 2 %d string("range") +0001 SEND_VAL int(0) 1 +0002 SEND_VAL int(10) 2 +0003 V2 = DO_ICALL +0004 V1 = FE_RESET_R V2 0013 +0005 FE_FETCH_R V1 CV0($char) 0013 +0006 INIT_FCALL 1 %d string("var_dump") +0007 INIT_FCALL 1 %d string("test") +0008 SEND_VAR CV0($char) 1 +0009 V2 = DO_UCALL +0010 SEND_VAR V2 1 +0011 DO_ICALL +0012 JMP 0005 +0013 FE_FREE V1 +0014 RETURN int(1) +LIVE RANGES: + 1: 0005 - 0013 (loop) + +test: + ; (lines=9, args=1, vars=1, tmps=0) + ; (after optimizer) + ; %s +0000 CV0($char) = RECV 1 +0001 MATCH CV0($char) 1: 0002, 2: 0003, 3: 0003, 4: 0004, 5: 0005, 6: 0005, 7: 0006, 8: 0007, 9: 0007, default: 0008 +0002 RETURN string("1") +0003 RETURN string("2, 3") +0004 RETURN string("4") +0005 RETURN string("5, 6") +0006 RETURN string("7") +0007 RETURN string("8, 9") +0008 RETURN string("default") +string(7) "default" +string(1) "1" +string(4) "2, 3" +string(4) "2, 3" +string(1) "4" +string(4) "5, 6" +string(4) "5, 6" +string(1) "7" +string(4) "8, 9" +string(4) "8, 9" +string(7) "default" diff --git a/ext/opcache/tests/match/004.phpt b/ext/opcache/tests/match/004.phpt new file mode 100644 index 0000000000..f84a0b832d --- /dev/null +++ b/ext/opcache/tests/match/004.phpt @@ -0,0 +1,93 @@ +--TEST-- +Match expression mixed jump table +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.opt_debug_level=0x20000 +--SKIPIF-- +<?php require_once(__DIR__ . '/../skipif.inc'); ?> +--FILE-- +<?php + +function test($value) { + return match ($value) { + 1 => '1 int', + '1' => '1 string', + 2 => '2 int', + '2' => '2 string', + 3 => '3 int', + '3' => '3 string', + 4 => '4 int', + '4' => '4 string', + 5 => '5 int', + '5' => '5 string', + default => 'default', + }; +} + +foreach (range(0, 6) as $number) { + var_dump(test($number)); + var_dump(test((string) $number)); +} + +--EXPECTF-- +$_main: + ; (lines=22, args=0, vars=1, tmps=2) + ; (after optimizer) + ; %s.php:1-24 +0000 INIT_FCALL 2 %d string("range") +0001 SEND_VAL int(0) 1 +0002 SEND_VAL int(6) 2 +0003 V2 = DO_ICALL +0004 V1 = FE_RESET_R V2 0020 +0005 FE_FETCH_R V1 CV0($number) 0020 +0006 INIT_FCALL 1 %d string("var_dump") +0007 INIT_FCALL 1 %d string("test") +0008 SEND_VAR CV0($number) 1 +0009 V2 = DO_UCALL +0010 SEND_VAR V2 1 +0011 DO_ICALL +0012 INIT_FCALL 1 %d string("var_dump") +0013 INIT_FCALL 1 %d string("test") +0014 T2 = CAST (string) CV0($number) +0015 SEND_VAL T2 1 +0016 V2 = DO_UCALL +0017 SEND_VAR V2 1 +0018 DO_ICALL +0019 JMP 0005 +0020 FE_FREE V1 +0021 RETURN int(1) +LIVE RANGES: + 1: 0005 - 0020 (loop) + +test: + ; (lines=13, args=1, vars=1, tmps=0) + ; (after optimizer) + ; %s.php:3-17 +0000 CV0($value) = RECV 1 +0001 MATCH CV0($value) 1: 0002, "1": 0003, 2: 0004, "2": 0005, 3: 0006, "3": 0007, 4: 0008, "4": 0009, 5: 0010, "5": 0011, default: 0012 +0002 RETURN string("1 int") +0003 RETURN string("1 string") +0004 RETURN string("2 int") +0005 RETURN string("2 string") +0006 RETURN string("3 int") +0007 RETURN string("3 string") +0008 RETURN string("4 int") +0009 RETURN string("4 string") +0010 RETURN string("5 int") +0011 RETURN string("5 string") +0012 RETURN string("default") +string(7) "default" +string(7) "default" +string(5) "1 int" +string(8) "1 string" +string(5) "2 int" +string(8) "2 string" +string(5) "3 int" +string(8) "3 string" +string(5) "4 int" +string(8) "4 string" +string(5) "5 int" +string(8) "5 string" +string(7) "default" +string(7) "default" diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index 15ade4ce3c..379f3fa9a1 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -547,6 +547,7 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra case ZEND_FE_FETCH_RW: case ZEND_SWITCH_LONG: case ZEND_SWITCH_STRING: + case ZEND_MATCH: /* relative extended_value don't have to be changed */ break; } diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index ae997b9a60..e6b5194bfe 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -549,6 +549,7 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc case ZEND_FE_FETCH_RW: case ZEND_SWITCH_LONG: case ZEND_SWITCH_STRING: + case ZEND_MATCH: /* relative extended_value don't have to be changed */ break; } diff --git a/ext/standard/tests/file/fnmatch_variation.phpt b/ext/standard/tests/file/fnmatch_variation.phpt index e7ad222444..4ca81ed94f 100644 --- a/ext/standard/tests/file/fnmatch_variation.phpt +++ b/ext/standard/tests/file/fnmatch_variation.phpt @@ -74,7 +74,7 @@ unlink($file_name); echo "\n*** Testing fnmatch() with other types other than files ***"; /* defining a common function */ -function match( $pattern, $string ) { +function match_( $pattern, $string ) { for( $i = 0; $i<count($pattern); $i++ ) { echo "-- Iteration $i --\n"; for( $j = 0; $j<count($string); $j++ ) { @@ -96,7 +96,7 @@ $int_arr = array( 0xF, 0xF0000 ); -match($int_arr, $int_arr); +match_($int_arr, $int_arr); echo "\n--- With Strings ---\n"; $str_arr = array( @@ -109,7 +109,7 @@ $str_arr = array( /* binary input */ b"string" ); -match($str_arr, $str_arr); +match_($str_arr, $str_arr); echo "\n--- With booleans ---\n"; $bool_arr = array( @@ -123,7 +123,7 @@ $bool_arr = array( "", "string" ); -match($bool_arr, $bool_arr); +match_($bool_arr, $bool_arr); echo "\n--- With NULL ---\n"; $null_arr = array( @@ -134,7 +134,7 @@ $null_arr = array( "string", 0 ); -match($null_arr, $null_arr); +match_($null_arr, $null_arr); echo "\n*** Done ***\n"; ?> diff --git a/ext/tokenizer/tokenizer_data.c b/ext/tokenizer/tokenizer_data.c index 9c7df93207..14630cdd40 100644 --- a/ext/tokenizer/tokenizer_data.c +++ b/ext/tokenizer/tokenizer_data.c @@ -84,8 +84,6 @@ void tokenizer_register_constants(INIT_FUNC_ARGS) { REGISTER_LONG_CONSTANT("T_STRING_VARNAME", T_STRING_VARNAME, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_NUM_STRING", T_NUM_STRING, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_EVAL", T_EVAL, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("T_INC", T_INC, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("T_DEC", T_DEC, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_NEW", T_NEW, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_EXIT", T_EXIT, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_IF", T_IF, CONST_CS | CONST_PERSISTENT); @@ -105,6 +103,7 @@ void tokenizer_register_constants(INIT_FUNC_ARGS) { REGISTER_LONG_CONSTANT("T_ENDSWITCH", T_ENDSWITCH, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_CASE", T_CASE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_DEFAULT", T_DEFAULT, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("T_MATCH", T_MATCH, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_BREAK", T_BREAK, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_CONTINUE", T_CONTINUE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_GOTO", T_GOTO, CONST_CS | CONST_PERSISTENT); @@ -134,7 +133,7 @@ void tokenizer_register_constants(INIT_FUNC_ARGS) { REGISTER_LONG_CONSTANT("T_INTERFACE", T_INTERFACE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_EXTENDS", T_EXTENDS, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_IMPLEMENTS", T_IMPLEMENTS, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("T_OBJECT_OPERATOR", T_OBJECT_OPERATOR, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("T_NAMESPACE", T_NAMESPACE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_LIST", T_LIST, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_ARRAY", T_ARRAY, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_CALLABLE", T_CALLABLE, CONST_CS | CONST_PERSISTENT); @@ -145,6 +144,10 @@ void tokenizer_register_constants(INIT_FUNC_ARGS) { REGISTER_LONG_CONSTANT("T_TRAIT_C", T_TRAIT_C, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_METHOD_C", T_METHOD_C, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_FUNC_C", T_FUNC_C, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("T_NS_C", T_NS_C, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("T_INC", T_INC, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("T_DEC", T_DEC, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("T_OBJECT_OPERATOR", T_OBJECT_OPERATOR, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_COMMENT", T_COMMENT, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_DOC_COMMENT", T_DOC_COMMENT, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_OPEN_TAG", T_OPEN_TAG, CONST_CS | CONST_PERSISTENT); @@ -156,8 +159,6 @@ void tokenizer_register_constants(INIT_FUNC_ARGS) { REGISTER_LONG_CONSTANT("T_DOLLAR_OPEN_CURLY_BRACES", T_DOLLAR_OPEN_CURLY_BRACES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_CURLY_OPEN", T_CURLY_OPEN, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_PAAMAYIM_NEKUDOTAYIM", T_PAAMAYIM_NEKUDOTAYIM, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("T_NAMESPACE", T_NAMESPACE, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("T_NS_C", T_NS_C, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_NS_SEPARATOR", T_NS_SEPARATOR, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_ELLIPSIS", T_ELLIPSIS, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("T_BAD_CHARACTER", T_BAD_CHARACTER, CONST_CS | CONST_PERSISTENT); @@ -227,8 +228,6 @@ char *get_token_type_name(int token_type) case T_STRING_VARNAME: return "T_STRING_VARNAME"; case T_NUM_STRING: return "T_NUM_STRING"; case T_EVAL: return "T_EVAL"; - case T_INC: return "T_INC"; - case T_DEC: return "T_DEC"; case T_NEW: return "T_NEW"; case T_EXIT: return "T_EXIT"; case T_IF: return "T_IF"; @@ -248,6 +247,7 @@ char *get_token_type_name(int token_type) case T_ENDSWITCH: return "T_ENDSWITCH"; case T_CASE: return "T_CASE"; case T_DEFAULT: return "T_DEFAULT"; + case T_MATCH: return "T_MATCH"; case T_BREAK: return "T_BREAK"; case T_CONTINUE: return "T_CONTINUE"; case T_GOTO: return "T_GOTO"; @@ -277,7 +277,7 @@ char *get_token_type_name(int token_type) case T_INTERFACE: return "T_INTERFACE"; case T_EXTENDS: return "T_EXTENDS"; case T_IMPLEMENTS: return "T_IMPLEMENTS"; - case T_OBJECT_OPERATOR: return "T_OBJECT_OPERATOR"; + case T_NAMESPACE: return "T_NAMESPACE"; case T_LIST: return "T_LIST"; case T_ARRAY: return "T_ARRAY"; case T_CALLABLE: return "T_CALLABLE"; @@ -288,6 +288,10 @@ char *get_token_type_name(int token_type) case T_TRAIT_C: return "T_TRAIT_C"; case T_METHOD_C: return "T_METHOD_C"; case T_FUNC_C: return "T_FUNC_C"; + case T_NS_C: return "T_NS_C"; + case T_INC: return "T_INC"; + case T_DEC: return "T_DEC"; + case T_OBJECT_OPERATOR: return "T_OBJECT_OPERATOR"; case T_COMMENT: return "T_COMMENT"; case T_DOC_COMMENT: return "T_DOC_COMMENT"; case T_OPEN_TAG: return "T_OPEN_TAG"; @@ -299,8 +303,6 @@ char *get_token_type_name(int token_type) case T_DOLLAR_OPEN_CURLY_BRACES: return "T_DOLLAR_OPEN_CURLY_BRACES"; case T_CURLY_OPEN: return "T_CURLY_OPEN"; case T_PAAMAYIM_NEKUDOTAYIM: return "T_DOUBLE_COLON"; - case T_NAMESPACE: return "T_NAMESPACE"; - case T_NS_C: return "T_NS_C"; case T_NS_SEPARATOR: return "T_NS_SEPARATOR"; case T_ELLIPSIS: return "T_ELLIPSIS"; case T_BAD_CHARACTER: return "T_BAD_CHARACTER"; |
