}
/* }}} */
-void zend_do_early_binding(TSRMLS_D) /* {{{ */
+void zend_compile_foreach(zend_ast *ast TSRMLS_DC) /* {{{ */
{
- zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
- HashTable *table;
+ zend_ast *expr_ast = ast->child[0];
+ zend_ast *value_ast = ast->child[1];
+ zend_ast *key_ast = ast->child[2];
+ zend_ast *stmt_ast = ast->child[3];
+ zend_bool by_ref = value_ast->kind == ZEND_AST_REF;
+ zend_bool is_variable = zend_is_variable(expr_ast) && !zend_is_call(expr_ast)
+ && zend_can_write_to_variable(expr_ast);
- while (opline->opcode == ZEND_TICKS && opline > CG(active_op_array)->opcodes) {
- opline--;
- }
+ znode expr_node, reset_node, value_node, key_node, dummy_node;
+ zend_op *opline;
+ uint32_t opnum_reset, opnum_fetch;
- switch (opline->opcode) {
- case ZEND_DECLARE_FUNCTION:
- if (do_bind_function(CG(active_op_array), opline, CG(function_table), 1) == FAILURE) {
- return;
- }
- table = CG(function_table);
- break;
- case ZEND_DECLARE_CLASS:
- if (do_bind_class(CG(active_op_array), opline, CG(class_table), 1 TSRMLS_CC) == NULL) {
- return;
- }
- table = CG(class_table);
- break;
- case ZEND_DECLARE_INHERITED_CLASS:
- {
- zend_op *fetch_class_opline = opline-1;
- zval *parent_name;
- zend_class_entry **pce;
+ if (key_ast) {
+ if (key_ast->kind == ZEND_AST_REF) {
+ zend_error_noreturn(E_COMPILE_ERROR, "Key element cannot be a reference");
+ }
+ if (key_ast->kind == ZEND_AST_LIST) {
+ zend_error_noreturn(E_COMPILE_ERROR, "Cannot use list as key element");
+ }
+ }
- parent_name = &CONSTANT(fetch_class_opline->op2.constant);
- if ((zend_lookup_class(Z_STRVAL_P(parent_name), Z_STRLEN_P(parent_name), &pce TSRMLS_CC) == FAILURE) ||
- ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES) &&
- ((*pce)->type == ZEND_INTERNAL_CLASS))) {
- if (CG(compiler_options) & ZEND_COMPILE_DELAYED_BINDING) {
- zend_uint *opline_num = &CG(active_op_array)->early_binding;
+ if (by_ref) {
+ value_ast = value_ast->child[0];
+ }
- while (*opline_num != -1) {
- opline_num = &CG(active_op_array)->opcodes[*opline_num].result.opline_num;
- }
- *opline_num = opline - CG(active_op_array)->opcodes;
- opline->opcode = ZEND_DECLARE_INHERITED_CLASS_DELAYED;
- opline->result_type = IS_UNUSED;
- opline->result.opline_num = -1;
- }
- return;
- }
- if (do_bind_inherited_class(CG(active_op_array), opline, CG(class_table), *pce, 1 TSRMLS_CC) == NULL) {
- return;
- }
- /* clear unnecessary ZEND_FETCH_CLASS opcode */
- zend_del_literal(CG(active_op_array), fetch_class_opline->op2.constant);
- MAKE_NOP(fetch_class_opline);
+ if (by_ref && is_variable) {
+ zend_compile_var(&expr_node, expr_ast, BP_VAR_W TSRMLS_CC);
+ } else {
+ zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
+ }
- table = CG(class_table);
- break;
- }
- case ZEND_VERIFY_ABSTRACT_CLASS:
- case ZEND_ADD_INTERFACE:
- case ZEND_ADD_TRAIT:
- case ZEND_BIND_TRAITS:
- /* We currently don't early-bind classes that implement interfaces */
- /* Classes with traits are handled exactly the same, no early-bind here */
- return;
- default:
- zend_error_noreturn(E_COMPILE_ERROR, "Invalid binding type");
- return;
++ if (by_ref) {
++ zend_separate_if_call_and_write(&expr_node, expr_ast, BP_VAR_W TSRMLS_CC);
+ }
+
- zend_hash_quick_del(table, Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant)), Z_HASH_P(&CONSTANT(opline->op1.constant)));
- zend_del_literal(CG(active_op_array), opline->op1.constant);
- zend_del_literal(CG(active_op_array), opline->op2.constant);
- MAKE_NOP(opline);
-}
-/* }}} */
+ opnum_reset = get_next_op_number(CG(active_op_array));
+ opline = zend_emit_op(&reset_node, ZEND_FE_RESET, &expr_node, NULL TSRMLS_CC);
+ if (by_ref && is_variable) {
+ opline->extended_value = ZEND_FE_FETCH_BYREF;
+ }
-ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array TSRMLS_DC) /* {{{ */
-{
- if (op_array->early_binding != -1) {
- zend_bool orig_in_compilation = CG(in_compilation);
- zend_uint opline_num = op_array->early_binding;
- zend_class_entry **pce;
+ zend_stack_push(&CG(loop_var_stack), &reset_node);
- CG(in_compilation) = 1;
- while (opline_num != -1) {
- if (zend_lookup_class(Z_STRVAL_P(op_array->opcodes[opline_num-1].op2.zv), Z_STRLEN_P(op_array->opcodes[opline_num-1].op2.zv), &pce TSRMLS_CC) == SUCCESS) {
- do_bind_inherited_class(op_array, &op_array->opcodes[opline_num], EG(class_table), *pce, 0 TSRMLS_CC);
- }
- opline_num = op_array->opcodes[opline_num].result.opline_num;
- }
- CG(in_compilation) = orig_in_compilation;
+ opnum_fetch = get_next_op_number(CG(active_op_array));
+ opline = zend_emit_op(&value_node, ZEND_FE_FETCH, &reset_node, NULL TSRMLS_CC);
+ if (by_ref) {
+ opline->extended_value |= ZEND_FE_FETCH_BYREF;
+ }
+ if (key_ast) {
+ opline->extended_value |= ZEND_FE_FETCH_WITH_KEY;
}
-}
-/* }}} */
-void zend_do_boolean_or_begin(znode *expr1, znode *op_token TSRMLS_DC) /* {{{ */
-{
- int next_op_number = get_next_op_number(CG(active_op_array));
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+ opline = zend_emit_op(NULL, ZEND_OP_DATA, NULL, NULL TSRMLS_CC);
+
+ /* Allocate enough space to keep HashPointer on VM stack */
+ opline->op1_type = IS_TMP_VAR;
+ opline->op1.var = get_temporary_variable(CG(active_op_array));
+ if (sizeof(HashPointer) > sizeof(zval)) {
+ /* Make sure 1 zval is enough for HashPointer (2 must be enough) */
+ get_temporary_variable(CG(active_op_array));
+ }
- opline->opcode = ZEND_JMPNZ_EX;
- if (expr1->op_type == IS_TMP_VAR) {
- SET_NODE(opline->result, expr1);
+ if (key_ast) {
+ zend_make_tmp_result(&key_node, opline TSRMLS_CC);
+ }
+
+ if (value_ast->attr == ZEND_AST_LIST) {
+ zend_compile_list_assign(&dummy_node, value_ast, &value_node TSRMLS_CC);
+ zend_do_free(&dummy_node TSRMLS_CC);
+ } else if (by_ref) {
+ zend_emit_assign_ref_znode(value_ast, &value_node TSRMLS_CC);
} else {
- opline->result.var = get_temporary_variable(CG(active_op_array));
- opline->result_type = IS_TMP_VAR;
+ zend_emit_assign_znode(value_ast, &value_node TSRMLS_CC);
}
- SET_NODE(opline->op1, expr1);
- SET_UNUSED(opline->op2);
- op_token->u.op.opline_num = next_op_number;
+ if (key_ast) {
+ zend_emit_assign_znode(key_ast, &key_node TSRMLS_CC);
+ }
- GET_NODE(expr1, opline->result);
-}
-/* }}} */
+ zend_begin_loop(TSRMLS_C);
-void zend_do_boolean_or_end(znode *result, const znode *expr1, const znode *expr2, znode *op_token TSRMLS_DC) /* {{{ */
-{
- zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+ zend_compile_stmt(stmt_ast TSRMLS_CC);
- *result = *expr1; /* we saved the original result in expr1 */
- opline->opcode = ZEND_BOOL;
- SET_NODE(opline->result, result);
- SET_NODE(opline->op1, expr2);
- SET_UNUSED(opline->op2);
+ zend_emit_jump(opnum_fetch TSRMLS_CC);
+
+ opline = &CG(active_op_array)->opcodes[opnum_reset];
+ opline->op2.opline_num = get_next_op_number(CG(active_op_array));
+
+ opline = &CG(active_op_array)->opcodes[opnum_fetch];
+ opline->op2.opline_num = get_next_op_number(CG(active_op_array));
+
+ zend_end_loop(opnum_fetch, 1 TSRMLS_CC);
- CG(active_op_array)->opcodes[op_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array));
+ generate_free_loop_var(&reset_node TSRMLS_CC);
+ zend_stack_del_top(&CG(loop_var_stack));
}
/* }}} */