isset(abc());
?>
--EXPECTF--
-Fatal error: Cannot use isset() on the result of a function call (you can use "null !== func()" instead) in %s on line %d
+Fatal error: Cannot use isset() on the result of an expression (you can use "null !== expression" instead) in %s on line %d
return (zend_ast *) ast;
}
+ZEND_API zend_ast *zend_ast_create_zval_ex(zval *zv, zend_ast_attr attr)
+{
+ zend_ast_zval *ast = emalloc(sizeof(zend_ast_zval));
+ ast->kind = ZEND_CONST;
+ ast->attr = attr;
+ ZVAL_COPY_VALUE(&ast->val, zv);
+ return (zend_ast *) ast;
+}
+
ZEND_API zend_ast* zend_ast_create_unary_ex(zend_ast_kind kind, zend_ast_attr attr, zend_ast *op0)
{
zend_ast *ast = emalloc(sizeof(zend_ast));
ZEND_AST_PARAMS,
ZEND_AST_UNPACK,
- ZEND_AST_NAME,
- ZEND_AST_NAME_FQ,
+ ZEND_AST_ASSIGN_OP,
+ ZEND_AST_BINARY_OP,
ZEND_AST_AND,
ZEND_AST_OR,
ZEND_AST_GREATER,
ZEND_AST_GREATER_EQUAL,
- ZEND_AST_CAST_NULL,
- ZEND_AST_CAST_BOOL,
- ZEND_AST_CAST_INT,
- ZEND_AST_CAST_DOUBLE,
- ZEND_AST_CAST_STRING,
- ZEND_AST_CAST_ARRAY,
- ZEND_AST_CAST_OBJECT,
+ ZEND_AST_CAST,
ZEND_AST_CONDITIONAL,
+
+ ZEND_AST_EMPTY,
+ ZEND_AST_ISSET,
+
+ ZEND_AST_SILENCE,
+ ZEND_AST_SHELL_EXEC,
+ ZEND_AST_ARRAY,
+ ZEND_AST_ARRAY_ELEM,
+
+ ZEND_AST_CONST,
+ ZEND_AST_CLASS_CONST,
+ ZEND_AST_RESOLVE_CLASS_NAME,
};
typedef unsigned short zend_ast_kind;
ZEND_API zend_ast *zend_ast_create_constant(zval *zv);
+ZEND_API zend_ast *zend_ast_create_zval_ex(zval *zv, zend_ast_attr attr);
+
ZEND_API zend_ast *zend_ast_create_unary_ex(
zend_ast_kind kind, zend_ast_attr attr, zend_ast *op0);
ZEND_API zend_ast *zend_ast_create_binary_ex(
ZEND_API zend_ast *zend_ast_copy(zend_ast *ast);
ZEND_API void zend_ast_destroy(zend_ast *ast);
+static inline zend_ast *zend_ast_create_zval(zval *zv) {
+ return zend_ast_create_zval_ex(zv, 0);
+}
static inline zend_ast *zend_ast_create_unary(zend_ast_kind kind, zend_ast *op0) {
return zend_ast_create_unary_ex(kind, 0, op0);
}
static inline zend_ast *zend_ast_create_var(zval *name) {
return zend_ast_create_unary(ZEND_AST_VAR, zend_ast_create_constant(name));
}
+static inline zend_ast *zend_ast_create_binary_op(zend_uint opcode, zend_ast *op0, zend_ast *op1) {
+ return zend_ast_create_binary_ex(ZEND_AST_BINARY_OP, opcode, op0, op1);
+}
+static inline zend_ast *zend_ast_create_assign_op(zend_uint opcode, zend_ast *op0, zend_ast *op1) {
+ return zend_ast_create_binary_ex(ZEND_AST_ASSIGN_OP, opcode, op0, op1);
+}
/* Temporary, for porting */
#define AST_COMPILE(res, ast) do { \
}
/* }}} */
+static zend_bool zend_can_write_to_variable(zend_ast *ast);
+
void zend_do_foreach_begin(znode *foreach_token, znode *open_brackets_token, znode *array, znode *as_token, int variable TSRMLS_DC) /* {{{ */
{
zend_op *opline;
open_brackets_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
if (variable) {
// TODO.AST or !zend_can_parse_variable_for_write(array TSRMLS_CC)
- if (zend_is_call(array->u.ast)) {
+ if (zend_is_call(array->u.ast) || !zend_can_write_to_variable(array->u.ast)) {
is_variable = 0;
AST_COMPILE_VAR(array, array->u.ast, BP_VAR_R);
} else {
void zend_compile_assign(znode *result, zend_ast *ast TSRMLS_DC);
static void zend_compile_list_assign(znode *result, zend_ast *list_ast, znode *expr_node TSRMLS_DC);
+zend_op *zend_compile_assign_ref_common(znode *result, zend_ast *target_ast, znode *source_node TSRMLS_DC);
void zend_do_foreach_cont(znode *foreach_token, const znode *open_brackets_token, const znode *as_token, znode *value, znode *key TSRMLS_DC) /* {{{ */
{
zend_ast_destroy(value->u.ast);
} else {
if (assign_by_ref) {
- zend_ast *assign_ast = zend_ast_create_binary(
- ZEND_AST_ASSIGN_REF, value->u.ast, AST_ZNODE(&value_node));
- AST_COMPILE(NULL, assign_ast);
+ zend_compile_assign_ref_common(NULL, value->u.ast, &value_node TSRMLS_CC);
+ zend_ast_destroy(value->u.ast);
} else {
zend_ast *assign_ast = zend_ast_create_binary(
ZEND_AST_ASSIGN, value->u.ast, AST_ZNODE(&value_node));
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = opcode;
- SET_NODE(opline->op1, op1);
+ if (op1 == NULL) {
+ SET_UNUSED(opline->op1);
+ } else {
+ SET_NODE(opline->op1, op1);
+ }
if (op2 == NULL) {
SET_UNUSED(opline->op2);
}
static zend_bool zend_is_variable(zend_ast *ast) {
- return ast->kind == ZEND_AST_VAR || ast->kind == ZEND_AST_DIM || ast->kind == ZEND_AST_PROP
+ return ast->kind == ZEND_AST_VAR || ast->kind == ZEND_AST_DIM
+ || ast->kind == ZEND_AST_PROP || ast->kind == ZEND_AST_STATIC_PROP
|| ast->kind == ZEND_AST_CALL || ast->kind == ZEND_AST_METHOD_CALL
|| ast->kind == ZEND_AST_STATIC_CALL;
}
|| ast->kind == ZEND_AST_STATIC_CALL;
}
+static zend_bool zend_can_write_to_variable(zend_ast *ast) {
+ while (ast->kind == ZEND_AST_DIM || ast->kind == ZEND_AST_PROP) {
+ ast = ast->child[0];
+ }
+
+ return zend_is_variable(ast);
+}
+
static zend_bool zend_is_const_default_class_ref(zend_ast *name_ast) {
zval *name;
int fetch_type;
return fetch_type == ZEND_FETCH_CLASS_DEFAULT;
}
+static zend_bool zend_is_compound_name(zval *name) {
+ return NULL != memchr(Z_STRVAL_P(name), '\\', Z_STRLEN_P(name));
+}
+
+static void zend_handle_numeric_op2(zend_op *opline TSRMLS_DC) {
+ if (opline->op2_type == IS_CONST && Z_TYPE(CONSTANT(opline->op2.constant)) == IS_STRING) {
+ ulong index;
+ int numeric = 0;
+
+ ZEND_HANDLE_NUMERIC_EX(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))+1, index, numeric = 1);
+ if (numeric) {
+ zval_dtor(&CONSTANT(opline->op2.constant));
+ ZVAL_LONG(&CONSTANT(opline->op2.constant), index);
+ }
+ }
+}
+
+static void zend_set_class_name_op1(zend_op *opline, znode *class_node TSRMLS_DC) {
+ if (class_node->op_type == IS_CONST) {
+ opline->op1_type = IS_CONST;
+ opline->op1.constant =
+ zend_add_class_name_literal(CG(active_op_array), &class_node->u.constant TSRMLS_CC);
+ } else {
+ SET_NODE(opline->op1, class_node);
+ }
+}
+
static zend_op *zend_compile_class_ref(znode *result, zend_ast *name_ast TSRMLS_DC) {
znode name_node;
zend_op *opline;
if (name_ast->kind == ZEND_CONST) {
zend_string *name = zval_get_string(zend_ast_get_zval(name_ast));
- if (zend_is_auto_global(name TSRMLS_CC) ||
- (CG(active_op_array)->last != 0 &&
- CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode == ZEND_BEGIN_SILENCE)
- ) {
- // TODO.AST: handle ZEND_BEGIN_SILENCE properly
+ if (zend_is_auto_global(name TSRMLS_CC)) {
STR_RELEASE(name);
return FAILURE;
}
}
}
-static void handle_numeric_op2(zend_op *opline TSRMLS_DC) {
- if (opline->op2_type == IS_CONST && Z_TYPE(CONSTANT(opline->op2.constant)) == IS_STRING) {
- ulong index;
- int numeric = 0;
-
- ZEND_HANDLE_NUMERIC_EX(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))+1, index, numeric = 1);
- if (numeric) {
- zval_dtor(&CONSTANT(opline->op2.constant));
- ZVAL_LONG(&CONSTANT(opline->op2.constant), index);
- }
- }
-}
-
static void zend_separate_if_call_and_write(znode *node, zend_ast *ast, int type TSRMLS_DC) {
if (type != BP_VAR_R && type != BP_VAR_IS && zend_is_call(ast)) {
zend_op *opline = emit_op(NULL, ZEND_SEPARATE, node, NULL TSRMLS_CC);
zend_separate_if_call_and_write(&var_node, var_ast, type TSRMLS_CC);
opline = emit_op(result, ZEND_FETCH_DIM_R, &var_node, &dim_node TSRMLS_CC);
- handle_numeric_op2(opline TSRMLS_CC);
+ zend_handle_numeric_op2(opline TSRMLS_CC);
return opline;
}
zend_adjust_for_fetch_type(opline, type);
}
-void zend_compile_static_prop(znode *result, zend_ast *ast, int type TSRMLS_DC) {
+zend_op *zend_compile_static_prop_common(znode *result, zend_ast *ast, int type TSRMLS_DC) {
zend_ast *class_ast = ast->child[0];
zend_ast *prop_ast = ast->child[1];
zend_compile_expr(&prop_node, prop_ast TSRMLS_CC);
opline = emit_op(result, ZEND_FETCH_R, &prop_node, NULL TSRMLS_CC);
- zend_adjust_for_fetch_type(opline, type);
if (opline->op1_type == IS_CONST) {
GET_POLYMORPHIC_CACHE_SLOT(opline->op1.constant);
}
SET_NODE(opline->op2, &class_node);
}
opline->extended_value |= ZEND_FETCH_STATIC_MEMBER;
+
+ return opline;
+}
+
+void zend_compile_static_prop(znode *result, zend_ast *ast, zend_uint type TSRMLS_DC) {
+ zend_op *opline = zend_compile_static_prop_common(result, ast, type TSRMLS_CC);
+ zend_adjust_for_fetch_type(opline, type);
}
static zend_uchar get_list_fetch_opcode(zend_uchar op_type) {
void zend_compile_compound_assign(znode *result, zend_ast *ast TSRMLS_DC) {
zend_ast *var_ast = ast->child[0];
zend_ast *expr_ast = ast->child[1];
+ zend_uint opcode = ast->attr;
znode var_node, expr_node;
zend_op *opline;
switch (var_ast->kind) {
case ZEND_AST_VAR:
zend_compile_var(&var_node, var_ast, BP_VAR_RW TSRMLS_CC);
- emit_op(result, ast->kind, &var_node, &expr_node TSRMLS_CC);
+ emit_op(result, opcode, &var_node, &expr_node TSRMLS_CC);
return;
case ZEND_AST_DIM:
opline = zend_compile_dim_common(result, var_ast, BP_VAR_RW TSRMLS_CC);
- opline->opcode = ast->kind;
+ opline->opcode = opcode;
opline->extended_value = ZEND_ASSIGN_DIM;
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
return;
case ZEND_AST_PROP:
opline = zend_compile_prop_common(result, var_ast, BP_VAR_RW TSRMLS_CC);
- opline->opcode = ast->kind;
+ opline->opcode = opcode;
opline->extended_value = ZEND_ASSIGN_OBJ;
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
}
zend_bool zend_compile_function_name(znode *name_node, zend_ast *name_ast TSRMLS_DC) {
- zend_bool check_namespace;
- char *is_compound;
-
- zval *name = &name_node->u.constant;
- ZVAL_COPY(name, zend_ast_get_zval(name_ast->child[0]));
- name_node->op_type = IS_CONST;
-
- check_namespace = name_ast->kind == ZEND_AST_NAME;
- is_compound = memchr(Z_STRVAL_P(name), '\\', Z_STRLEN_P(name));
+ zend_bool check_namespace = name_ast->attr;
+ zend_bool is_compound = zend_is_compound_name(zend_ast_get_zval(name_ast));
+ zend_compile_expr(name_node, name_ast TSRMLS_CC);
zend_resolve_function_name(name_node, &check_namespace TSRMLS_CC);
return check_namespace && Z_TYPE(CG(current_namespace)) != IS_UNDEF && !is_compound;
znode name_node;
- if (name_ast->kind != ZEND_AST_NAME && name_ast->kind != ZEND_AST_NAME_FQ) {
+ if (name_ast->kind != ZEND_CONST) {
zend_compile_expr(&name_node, name_ast TSRMLS_CC);
zend_compile_dynamic_call(result, &name_node, params_ast TSRMLS_CC);
return;
opline->result.num = CG(context).nested_calls;
opline->extended_value = extended_value;
- if (class_node.op_type == IS_CONST) {
- opline->op1_type = IS_CONST;
- opline->op1.constant =
- zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC);
- } else {
- SET_NODE(opline->op1, &class_node);
- }
+ zend_set_class_name_op1(opline, &class_node TSRMLS_CC);
if (method_node.op_type == IS_CONST) {
opline->op2_type = IS_CONST;
zend_op *opline;
switch (var_ast->kind) {
case ZEND_AST_VAR:
- if (zend_try_compile_cv(&var_node, ast TSRMLS_CC) == SUCCESS) {
+ if (zend_try_compile_cv(&var_node, var_ast TSRMLS_CC) == SUCCESS) {
opline = emit_op(NULL, ZEND_UNSET_VAR, &var_node, NULL TSRMLS_CC);
opline->extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET;
} else {
opline = zend_compile_prop_common(NULL, var_ast, BP_VAR_UNSET TSRMLS_CC);
opline->opcode = ZEND_UNSET_OBJ;
return;
+ case ZEND_AST_STATIC_PROP:
+ opline = zend_compile_static_prop_common(NULL, var_ast, BP_VAR_UNSET TSRMLS_CC);
+ opline->opcode = ZEND_UNSET_VAR;
+ return;
EMPTY_SWITCH_DEFAULT_CASE()
}
}
void zend_compile_binary_op(znode *result, zend_ast *ast TSRMLS_DC) {
zend_ast *left_ast = ast->child[0];
zend_ast *right_ast = ast->child[1];
+ zend_uint opcode = ast->attr;
znode left_node, right_node;
zend_compile_expr(&left_node, left_ast TSRMLS_CC);
zend_compile_expr(&right_node, right_ast TSRMLS_CC);
- emit_op_tmp(result, ast->kind, &left_node, &right_node TSRMLS_CC);
+ emit_op_tmp(result, opcode, &left_node, &right_node TSRMLS_CC);
}
/* We do not use zend_compile_binary_op for this because we want to retain the left-to-right
zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
opline = emit_op(result, ZEND_CAST, &expr_node, NULL TSRMLS_CC);
- switch (ast->kind) {
- case ZEND_AST_CAST_NULL: opline->extended_value = IS_NULL; break;
- case ZEND_AST_CAST_BOOL: opline->extended_value = _IS_BOOL; break;
- case ZEND_AST_CAST_INT: opline->extended_value = IS_LONG; break;
- case ZEND_AST_CAST_DOUBLE: opline->extended_value = IS_DOUBLE; break;
- case ZEND_AST_CAST_STRING: opline->extended_value = IS_STRING; break;
- case ZEND_AST_CAST_ARRAY: opline->extended_value = IS_ARRAY; break;
- case ZEND_AST_CAST_OBJECT: opline->extended_value = IS_OBJECT; break;
- EMPTY_SWITCH_DEFAULT_CASE()
- }
+ opline->extended_value = ast->attr;
}
static void zend_compile_shorthand_conditional(znode *result, zend_ast *ast TSRMLS_DC) {
emit_op_tmp(result, ZEND_INSTANCEOF, &obj_node, &class_node TSRMLS_CC);
}
+void zend_compile_include_or_eval(znode *result, zend_ast *ast TSRMLS_DC) {
+ zend_ast *expr_ast = ast->child[0];
+ znode expr_node;
+ zend_op *opline;
+
+ zend_do_extended_fcall_begin(TSRMLS_C);
+ zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
+
+ opline = emit_op(result, ZEND_INCLUDE_OR_EVAL, &expr_node, NULL TSRMLS_CC);
+ opline->extended_value = ast->attr;
+
+ zend_do_extended_fcall_end(TSRMLS_C);
+}
+
+void zend_compile_isset_or_empty(znode *result, zend_ast *ast TSRMLS_DC) {
+ zend_ast *var_ast = ast->child[0];
+
+ znode var_node;
+ zend_op *opline;
+
+ ZEND_ASSERT(ast->kind == ZEND_AST_ISSET || ast->kind == ZEND_AST_EMPTY);
+
+ if (!zend_is_variable(var_ast) || zend_is_call(var_ast)) {
+ if (ast->kind == ZEND_AST_EMPTY) {
+ /* empty(expr) can be transformed to !expr */
+ zend_ast *not_ast = zend_ast_create_unary(ZEND_BOOL_NOT, var_ast);
+ zend_compile_expr(result, not_ast TSRMLS_CC);
+ efree(not_ast);
+ return;
+ } else {
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Cannot use isset() on the result of an expression "
+ "(you can use \"null !== expression\" instead)");
+ }
+ }
+
+ switch (var_ast->kind) {
+ case ZEND_AST_VAR:
+ if (zend_try_compile_cv(&var_node, var_ast TSRMLS_CC) == SUCCESS) {
+ opline = emit_op(result, ZEND_ISSET_ISEMPTY_VAR, &var_node, NULL TSRMLS_CC);
+ opline->extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET;
+ } else {
+ opline = zend_compile_simple_var_no_cv(result, var_ast, BP_VAR_IS TSRMLS_CC);
+ opline->opcode = ZEND_ISSET_ISEMPTY_VAR;
+ }
+ break;
+ case ZEND_AST_DIM:
+ opline = zend_compile_dim_common(result, var_ast, BP_VAR_IS TSRMLS_CC);
+ opline->opcode = ZEND_ISSET_ISEMPTY_DIM_OBJ;
+ break;
+ case ZEND_AST_PROP:
+ opline = zend_compile_prop_common(result, var_ast, BP_VAR_IS TSRMLS_CC);
+ opline->opcode = ZEND_ISSET_ISEMPTY_PROP_OBJ;
+ break;
+ case ZEND_AST_STATIC_PROP:
+ opline = zend_compile_static_prop_common(result, var_ast, BP_VAR_IS TSRMLS_CC);
+ opline->opcode = ZEND_ISSET_ISEMPTY_VAR;
+ break;
+ EMPTY_SWITCH_DEFAULT_CASE()
+ }
+
+ opline->result_type = IS_TMP_VAR;
+ opline->extended_value |= ast->kind == ZEND_AST_ISSET ? ZEND_ISSET : ZEND_ISEMPTY;
+}
+
+void zend_compile_silence(znode *result, zend_ast *ast TSRMLS_DC) {
+ zend_ast *expr_ast = ast->child[0];
+ znode silence_node;
+
+ emit_op_tmp(&silence_node, ZEND_BEGIN_SILENCE, NULL, NULL TSRMLS_CC);
+
+ if (expr_ast->kind == ZEND_AST_VAR) {
+ /* For @$var we need to force a FETCH instruction, otherwise the CV access will
+ * happen outside the silenced section. */
+ zend_compile_simple_var_no_cv(result, expr_ast, BP_VAR_R TSRMLS_CC);
+ } else {
+ zend_compile_expr(result, expr_ast TSRMLS_CC);
+ }
+
+ emit_op(NULL, ZEND_END_SILENCE, &silence_node, NULL TSRMLS_CC);
+}
+
+void zend_compile_shell_exec(znode *result, zend_ast *ast TSRMLS_DC) {
+ zend_ast *expr_ast = ast->child[0];
+
+ zval fn_name;
+ zend_ast *name_ast, *params_ast, *call_ast;
+
+ ZVAL_STRING(&fn_name, "shell_exec");
+ name_ast = zend_ast_create_zval(&fn_name);
+ params_ast = zend_ast_create_dynamic(ZEND_AST_PARAMS);
+ zend_ast_dynamic_add(¶ms_ast, expr_ast);
+ call_ast = zend_ast_create_binary(ZEND_AST_CALL, name_ast, params_ast);
+
+ zend_compile_expr(result, call_ast TSRMLS_CC);
+
+ efree(call_ast);
+ efree(params_ast);
+ zend_ast_destroy(name_ast);
+}
+
+int zend_try_ct_compile_array(zval *array, zend_ast *ast TSRMLS_DC) {
+ zend_uint i;
+
+ ZVAL_UNDEF(array);
+ for (i = 0; i < ast->children; ++i) {
+ zend_ast *elem_ast = ast->child[i];
+ zend_ast *value_ast = elem_ast->child[0];
+ zend_ast *key_ast = elem_ast->child[1];
+ zend_bool by_ref = elem_ast->attr;
+
+ znode key_node, value_node;
+ zval *key = &key_node.u.constant, *value = &value_node.u.constant;
+
+ if (by_ref) {
+ goto failure;
+ }
+
+ if (FAILURE == zend_compile_expr_maybe_ct(&value_node, value_ast, 1 TSRMLS_CC)) {
+ goto failure;
+ }
+
+ if (key_ast) {
+ if (FAILURE == zend_compile_expr_maybe_ct(&key_node, key_ast, 1 TSRMLS_CC)) {
+ zval_ptr_dtor(value);
+ goto failure;
+ }
+ }
+
+ if (Z_TYPE_P(array) == IS_UNDEF) {
+ array_init_size(array, ast->children);
+ }
+
+ if (key_ast) {
+ switch (Z_TYPE_P(key)) {
+ case IS_LONG:
+ zend_hash_index_update(Z_ARRVAL_P(array), Z_LVAL_P(key), value);
+ break;
+ case IS_STRING:
+ zend_symtable_update(Z_ARRVAL_P(array), Z_STR_P(key), value);
+ break;
+ case IS_DOUBLE:
+ zend_hash_index_update(Z_ARRVAL_P(array),
+ zend_dval_to_lval(Z_DVAL_P(key)), value);
+ break;
+ case IS_FALSE:
+ zend_hash_index_update(Z_ARRVAL_P(array), 0, value);
+ break;
+ case IS_TRUE:
+ zend_hash_index_update(Z_ARRVAL_P(array), 1, value);
+ break;
+ case IS_NULL:
+ zend_hash_update(Z_ARRVAL_P(array), STR_EMPTY_ALLOC(), value);
+ break;
+ default:
+ zend_error(E_COMPILE_ERROR, "Illegal offset type");
+ break;
+ }
+ zval_ptr_dtor(key);
+ } else {
+ zend_hash_next_index_insert(Z_ARRVAL_P(array), value);
+ }
+ }
+
+ if (!ast->children) {
+ array_init(array);
+ }
+
+ zend_make_immutable_array(array TSRMLS_CC);
+ return SUCCESS;
+
+failure:
+ zval_dtor(array);
+ return FAILURE;
+}
+
+int zend_compile_array_maybe_ct(znode *result, zend_ast *ast, zend_bool ct_required TSRMLS_DC) {
+ zend_op *opline;
+ zend_uint i, opnum_init;
+ zend_bool packed = 1;
+
+ zval array;
+
+ if (SUCCESS == zend_try_ct_compile_array(&array, ast TSRMLS_CC)) {
+ result->op_type = IS_CONST;
+ ZVAL_COPY_VALUE(&result->u.constant, &array);
+ return SUCCESS;
+ } else if (ct_required) {
+ return FAILURE;
+ }
+
+ opnum_init = get_next_op_number(CG(active_op_array));
+
+ for (i = 0; i < ast->children; ++i) {
+ zend_ast *elem_ast = ast->child[i];
+ zend_ast *value_ast = elem_ast->child[0];
+ zend_ast *key_ast = elem_ast->child[1];
+ zend_bool by_ref = elem_ast->attr;
+
+ znode value_node, key_node, *key_node_ptr = NULL;
+
+ if (key_ast) {
+ zend_compile_expr(&key_node, key_ast TSRMLS_CC);
+ key_node_ptr = &key_node;
+ }
+
+ if (by_ref) {
+ zend_ensure_writable_variable(value_ast);
+ zend_compile_var(&value_node, value_ast, BP_VAR_W TSRMLS_CC);
+ } else {
+ zend_compile_expr(&value_node, value_ast TSRMLS_CC);
+ }
+
+ if (i == 0) {
+ opline = emit_op_tmp(result, ZEND_INIT_ARRAY, &value_node, key_node_ptr TSRMLS_CC);
+ opline->extended_value = ast->children << ZEND_ARRAY_SIZE_SHIFT;
+ } else {
+ opline = emit_op(NULL, ZEND_ADD_ARRAY_ELEMENT, &value_node, key_node_ptr TSRMLS_CC);
+ SET_NODE(opline->result, result);
+ }
+ opline->extended_value |= by_ref;
+
+ if (key_ast) {
+ if (key_node.op_type == IS_CONST && Z_TYPE(key_node.u.constant) == IS_STRING) {
+ zend_handle_numeric_op2(opline TSRMLS_CC);
+ packed = 0;
+ }
+ }
+ }
+
+ /* Handle empty array */
+ if (!ast->children) {
+ emit_op_tmp(result, ZEND_INIT_ARRAY, NULL, NULL TSRMLS_CC);
+ }
+
+ /* Add a flag to INIT_ARRAY if we know this array cannot be packed */
+ if (!packed) {
+ opline = &CG(active_op_array)->opcodes[opnum_init];
+ opline->extended_value |= ZEND_ARRAY_NOT_PACKED;
+ }
+
+ return FAILURE;
+}
+
+void zend_compile_const(znode *result, zend_ast *ast TSRMLS_DC) {
+ zend_ast *name_ast = ast->child[0];
+ zend_bool check_namespace = name_ast->attr;
+
+ zend_bool is_compound = zend_is_compound_name(zend_ast_get_zval(name_ast));
+ znode name_node;
+ zend_op *opline;
+
+ zend_compile_expr(&name_node, name_ast TSRMLS_CC);
+ zend_resolve_const_name(&name_node, &check_namespace TSRMLS_CC);
+
+ if (zend_constant_ct_subst(result, &name_node.u.constant, 1 TSRMLS_CC)) {
+ return;
+ }
+
+ opline = emit_op_tmp(result, ZEND_FETCH_CONSTANT, NULL, NULL TSRMLS_CC);
+ opline->op2_type = IS_CONST;
+
+ if (is_compound) {
+ /* the name is unambiguous */
+ opline->op2.constant = zend_add_const_name_literal(
+ CG(active_op_array), &name_node.u.constant, 0 TSRMLS_CC);
+ } else {
+ opline->extended_value = IS_CONSTANT_UNQUALIFIED;
+ if (Z_TYPE(CG(current_namespace)) != IS_UNDEF) {
+ opline->extended_value |= IS_CONSTANT_IN_NAMESPACE;
+ opline->op2.constant = zend_add_const_name_literal(
+ CG(active_op_array), &name_node.u.constant, 1 TSRMLS_CC);
+ } else {
+ opline->op2.constant = zend_add_const_name_literal(
+ CG(active_op_array), &name_node.u.constant, 0 TSRMLS_CC);
+ }
+ }
+ GET_CACHE_SLOT(opline->op2.constant);
+}
+
+void zend_compile_class_const(znode *result, zend_ast *ast TSRMLS_DC) {
+ zend_ast *class_ast = ast->child[0];
+ zend_ast *const_ast = ast->child[1];
+
+ znode class_node, const_node;
+ zend_op *opline;
+
+ if (zend_is_const_default_class_ref(class_ast)) {
+ zend_compile_expr(&class_node, class_ast TSRMLS_CC);
+ zend_resolve_class_name(&class_node TSRMLS_CC);
+ } else {
+ zend_compile_class_ref(&class_node, class_ast TSRMLS_CC);
+ }
+
+ zend_compile_expr(&const_node, const_ast TSRMLS_CC);
+
+ opline = emit_op_tmp(result, ZEND_FETCH_CONSTANT, NULL, &const_node TSRMLS_CC);
+
+ zend_set_class_name_op1(opline, &class_node TSRMLS_CC);
+
+ if (opline->op1_type == IS_CONST) {
+ GET_CACHE_SLOT(opline->op2.constant);
+ } else {
+ GET_POLYMORPHIC_CACHE_SLOT(opline->op2.constant);
+ }
+}
+
+void zend_compile_resolve_class_name(znode *result, zend_ast *ast TSRMLS_DC) {
+ zend_ast *name_ast = ast->child[0];
+ zval *name = zend_ast_get_zval(name_ast);
+ int fetch_type = zend_get_class_fetch_type(Z_STRVAL_P(name), Z_STRLEN_P(name));
+
+ switch (fetch_type) {
+ case ZEND_FETCH_CLASS_SELF:
+ if (!CG(active_class_entry)) {
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Cannot access self::class when no class scope is active");
+ }
+ result->op_type = IS_CONST;
+ ZVAL_STR(&result->u.constant, STR_COPY(CG(active_class_entry)->name));
+ break;
+ case ZEND_FETCH_CLASS_STATIC:
+ case ZEND_FETCH_CLASS_PARENT:
+ if (!CG(active_class_entry)) {
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Cannot access %s::class when no class scope is active",
+ fetch_type == ZEND_FETCH_CLASS_STATIC ? "static" : "parent");
+ } else {
+ zval class_str_zv;
+ zend_ast *class_str_ast, *class_const_ast;
+
+ ZVAL_STRING(&class_str_zv, "class");
+ class_str_ast = zend_ast_create_zval(&class_str_zv);
+ class_const_ast = zend_ast_create_binary(
+ ZEND_AST_CLASS_CONST, name_ast, class_str_ast);
+
+ zend_compile_expr(result, class_const_ast TSRMLS_CC);
+
+ zend_ast_destroy(class_str_ast);
+ efree(class_const_ast);
+ }
+ break;
+ case ZEND_FETCH_CLASS_DEFAULT:
+ zend_compile_expr(result, name_ast TSRMLS_CC);
+ zend_resolve_class_name(result TSRMLS_CC);
+ break;
+ EMPTY_SWITCH_DEFAULT_CASE()
+ }
+}
+
void zend_compile_stmt(zend_ast *ast TSRMLS_DC) {
switch (ast->kind) {
case ZEND_AST_GLOBAL:
case ZEND_CLONE:
zend_compile_clone(result, ast TSRMLS_CC);
return;
- case ZEND_ASSIGN_ADD:
- case ZEND_ASSIGN_SUB:
- case ZEND_ASSIGN_MUL:
- case ZEND_ASSIGN_POW:
- case ZEND_ASSIGN_DIV:
- case ZEND_ASSIGN_CONCAT:
- case ZEND_ASSIGN_MOD:
- case ZEND_ASSIGN_BW_AND:
- case ZEND_ASSIGN_BW_OR:
- case ZEND_ASSIGN_BW_XOR:
- case ZEND_ASSIGN_SL:
- case ZEND_ASSIGN_SR:
+ case ZEND_AST_ASSIGN_OP:
zend_compile_compound_assign(result, ast TSRMLS_CC);
return;
- case ZEND_BOOL_XOR:
- case ZEND_BW_OR:
- case ZEND_BW_AND:
- case ZEND_BW_XOR:
- case ZEND_CONCAT:
- case ZEND_ADD:
- case ZEND_SUB:
- case ZEND_MUL:
- case ZEND_POW:
- case ZEND_DIV:
- case ZEND_MOD:
- case ZEND_SL:
- case ZEND_SR:
- case ZEND_IS_IDENTICAL:
- case ZEND_IS_NOT_IDENTICAL:
- case ZEND_IS_EQUAL:
- case ZEND_IS_NOT_EQUAL:
- case ZEND_IS_SMALLER:
- case ZEND_IS_SMALLER_OR_EQUAL:
+ case ZEND_AST_BINARY_OP:
zend_compile_binary_op(result, ast TSRMLS_CC);
return;
case ZEND_AST_GREATER:
case ZEND_PRE_DEC:
zend_compile_pre_incdec(result, ast TSRMLS_CC);
return;
- case ZEND_AST_CAST_NULL:
- case ZEND_AST_CAST_BOOL:
- case ZEND_AST_CAST_INT:
- case ZEND_AST_CAST_DOUBLE:
- case ZEND_AST_CAST_STRING:
- case ZEND_AST_CAST_ARRAY:
- case ZEND_AST_CAST_OBJECT:
+ case ZEND_AST_CAST:
zend_compile_cast(result, ast TSRMLS_CC);
return;
case ZEND_AST_CONDITIONAL:
case ZEND_INSTANCEOF:
zend_compile_instanceof(result, ast TSRMLS_CC);
return;
+ case ZEND_INCLUDE_OR_EVAL:
+ zend_compile_include_or_eval(result, ast TSRMLS_CC);
+ return;
+ case ZEND_AST_ISSET:
+ case ZEND_AST_EMPTY:
+ zend_compile_isset_or_empty(result, ast TSRMLS_CC);
+ return;
+ case ZEND_AST_SILENCE:
+ zend_compile_silence(result, ast TSRMLS_CC);
+ return;
+ case ZEND_AST_SHELL_EXEC:
+ zend_compile_shell_exec(result, ast TSRMLS_CC);
+ return;
+ case ZEND_AST_ARRAY:
+ zend_compile_array_maybe_ct(result, ast, 0 TSRMLS_CC);
+ return;
+ case ZEND_AST_CONST:
+ zend_compile_const(result, ast TSRMLS_CC);
+ return;
+ case ZEND_AST_CLASS_CONST:
+ zend_compile_class_const(result, ast TSRMLS_CC);
+ return;
+ case ZEND_AST_RESOLVE_CLASS_NAME:
+ zend_compile_resolve_class_name(result, ast TSRMLS_CC);
+ return;
default:
ZEND_ASSERT(0 /* not supported */);
}
}
+int zend_compile_expr_maybe_ct(znode *result, zend_ast *ast, zend_bool ct_required TSRMLS_DC) {
+ switch (ast->kind) {
+ case ZEND_CONST:
+ ZVAL_COPY(&result->u.constant, zend_ast_get_zval(ast));
+ result->op_type = IS_CONST;
+ return SUCCESS;
+ case ZEND_AST_ARRAY:
+ return zend_compile_array_maybe_ct(result, ast, ct_required TSRMLS_CC);
+ default:
+ if (!ct_required) {
+ zend_compile_expr(result, ast TSRMLS_CC);
+ }
+ return FAILURE;
+ }
+}
+
void zend_compile_var(znode *result, zend_ast *ast, int type TSRMLS_DC) {
switch (ast->kind) {
case ZEND_AST_VAR:
zend_compile_static_call(result, ast, type TSRMLS_CC);
return;
default:
- // TODO.AST check writable
+ if (type == BP_VAR_W || type == BP_VAR_REF
+ || type == BP_VAR_RW || type == BP_VAR_UNSET
+ ) {
+ /* For BC reasons =& new Foo is allowed */
+ if (type != BP_VAR_REF || ast->kind != ZEND_NEW) {
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Cannot use temporary expression in write context");
+ }
+ }
+
zend_compile_expr(result, ast TSRMLS_CC);
return;
}
void zend_ensure_writable_variable(const zend_ast *ast);
void zend_compile_stmt(zend_ast *ast TSRMLS_DC);
void zend_compile_expr(znode *node, zend_ast *ast TSRMLS_DC);
+int zend_compile_expr_maybe_ct(znode *node, zend_ast *ast, zend_bool ct_required TSRMLS_DC);
void zend_compile_var(znode *node, zend_ast *ast, int type TSRMLS_DC);
typedef struct _zend_execute_data zend_execute_data;
unticked_statement:
'{' inner_statement_list '}'
- | T_IF parenthesis_expr { zend_do_if_cond(&$2, &$1 TSRMLS_CC); } statement { zend_do_if_after_statement(&$1, 1 TSRMLS_CC); } elseif_list else_single { zend_do_if_end(TSRMLS_C); }
- | T_IF parenthesis_expr ':' { zend_do_if_cond(&$2, &$1 TSRMLS_CC); } inner_statement_list { zend_do_if_after_statement(&$1, 1 TSRMLS_CC); } new_elseif_list new_else_single T_ENDIF ';' { zend_do_if_end(TSRMLS_C); }
- | T_WHILE { $1.u.op.opline_num = get_next_op_number(CG(active_op_array)); } parenthesis_expr { zend_do_while_cond(&$3, &$$ TSRMLS_CC); } while_statement { zend_do_while_end(&$1, &$4 TSRMLS_CC); }
- | T_DO { $1.u.op.opline_num = get_next_op_number(CG(active_op_array)); zend_do_do_while_begin(TSRMLS_C); } statement T_WHILE { $4.u.op.opline_num = get_next_op_number(CG(active_op_array)); } parenthesis_expr ';' { zend_do_do_while_end(&$1, &$4, &$6 TSRMLS_CC); }
+ | T_IF parenthesis_expr { AC($2); zend_do_if_cond(&$2, &$1 TSRMLS_CC); } statement { zend_do_if_after_statement(&$1, 1 TSRMLS_CC); } elseif_list else_single { zend_do_if_end(TSRMLS_C); }
+ | T_IF parenthesis_expr ':' { AC($2); zend_do_if_cond(&$2, &$1 TSRMLS_CC); } inner_statement_list { zend_do_if_after_statement(&$1, 1 TSRMLS_CC); } new_elseif_list new_else_single T_ENDIF ';' { zend_do_if_end(TSRMLS_C); }
+ | T_WHILE { $1.u.op.opline_num = get_next_op_number(CG(active_op_array)); } parenthesis_expr { AC($3); zend_do_while_cond(&$3, &$$ TSRMLS_CC); } while_statement { zend_do_while_end(&$1, &$4 TSRMLS_CC); }
+ | T_DO { $1.u.op.opline_num = get_next_op_number(CG(active_op_array)); zend_do_do_while_begin(TSRMLS_C); } statement T_WHILE { $4.u.op.opline_num = get_next_op_number(CG(active_op_array)); } parenthesis_expr ';' { AC($6); zend_do_do_while_end(&$1, &$4, &$6 TSRMLS_CC); }
| T_FOR
'('
for_expr
for_expr
')' { zend_do_free(&$9 TSRMLS_CC); zend_do_for_before_statement(&$4, &$7 TSRMLS_CC); }
for_statement { zend_do_for_end(&$7 TSRMLS_CC); }
- | T_SWITCH parenthesis_expr { zend_do_switch_cond(&$2 TSRMLS_CC); } switch_case_list { zend_do_switch_end(&$4 TSRMLS_CC); }
+ | T_SWITCH parenthesis_expr { AC($2); zend_do_switch_cond(&$2 TSRMLS_CC); } switch_case_list { zend_do_switch_end(&$4 TSRMLS_CC); }
| T_BREAK ';' { zend_do_brk_cont(ZEND_BRK, NULL TSRMLS_CC); }
| T_BREAK expr ';' { AC($2); zend_do_brk_cont(ZEND_BRK, &$2 TSRMLS_CC); }
| T_CONTINUE ';' { zend_do_brk_cont(ZEND_CONT, NULL TSRMLS_CC); }
elseif_list:
/* empty */
- | elseif_list T_ELSEIF parenthesis_expr { zend_do_if_cond(&$3, &$2 TSRMLS_CC); } statement { zend_do_if_after_statement(&$2, 0 TSRMLS_CC); }
+ | elseif_list T_ELSEIF parenthesis_expr { AC($3); zend_do_if_cond(&$3, &$2 TSRMLS_CC); } statement { zend_do_if_after_statement(&$2, 0 TSRMLS_CC); }
;
new_elseif_list:
/* empty */
- | new_elseif_list T_ELSEIF parenthesis_expr ':' { zend_do_if_cond(&$3, &$2 TSRMLS_CC); } inner_statement_list { zend_do_if_after_statement(&$2, 0 TSRMLS_CC); }
+ | new_elseif_list T_ELSEIF parenthesis_expr ':' { AC($3); zend_do_if_cond(&$3, &$2 TSRMLS_CC); } inner_statement_list { zend_do_if_after_statement(&$2, 0 TSRMLS_CC); }
;
function_call_parameter:
expr_without_variable { $$.u.ast = $1.u.ast; }
| variable { $$.u.ast = $1.u.ast; }
- | '&' w_variable { /* ERROR */ ZEND_ASSERT(0); }
+ /*| '&' variable { ZEND_ASSERT(0); } */
| T_ELLIPSIS expr { $$.u.ast = zend_ast_create_unary(ZEND_AST_UNPACK, $2.u.ast); }
;
zend_ast_create_binary(ZEND_NEW, $5.u.ast, $6.u.ast)); }
| T_CLONE expr { $$.u.ast = zend_ast_create_unary(ZEND_CLONE, $2.u.ast); }
| variable T_PLUS_EQUAL expr
- { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_ADD, $1.u.ast, $3.u.ast); }
+ { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_ADD, $1.u.ast, $3.u.ast); }
| variable T_MINUS_EQUAL expr
- { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_SUB, $1.u.ast, $3.u.ast); }
+ { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_SUB, $1.u.ast, $3.u.ast); }
| variable T_MUL_EQUAL expr
- { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_MUL, $1.u.ast, $3.u.ast); }
+ { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_MUL, $1.u.ast, $3.u.ast); }
| variable T_POW_EQUAL expr
- { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_POW, $1.u.ast, $3.u.ast); }
+ { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_POW, $1.u.ast, $3.u.ast); }
| variable T_DIV_EQUAL expr
- { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_DIV, $1.u.ast, $3.u.ast); }
+ { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_DIV, $1.u.ast, $3.u.ast); }
| variable T_CONCAT_EQUAL expr
- { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_CONCAT, $1.u.ast, $3.u.ast); }
+ { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_CONCAT, $1.u.ast, $3.u.ast); }
| variable T_MOD_EQUAL expr
- { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_MOD, $1.u.ast, $3.u.ast); }
+ { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_MOD, $1.u.ast, $3.u.ast); }
| variable T_AND_EQUAL expr
- { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_BW_AND, $1.u.ast, $3.u.ast); }
+ { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_BW_AND, $1.u.ast, $3.u.ast); }
| variable T_OR_EQUAL expr
- { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_BW_OR, $1.u.ast, $3.u.ast); }
+ { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_BW_OR, $1.u.ast, $3.u.ast); }
| variable T_XOR_EQUAL expr
- { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_BW_XOR, $1.u.ast, $3.u.ast); }
+ { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_BW_XOR, $1.u.ast, $3.u.ast); }
| variable T_SL_EQUAL expr
- { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_SL, $1.u.ast, $3.u.ast); }
+ { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_SL, $1.u.ast, $3.u.ast); }
| variable T_SR_EQUAL expr
- { $$.u.ast = zend_ast_create_binary(ZEND_ASSIGN_SR, $1.u.ast, $3.u.ast); }
+ { $$.u.ast = zend_ast_create_assign_op(ZEND_ASSIGN_SR, $1.u.ast, $3.u.ast); }
| variable T_INC { $$.u.ast = zend_ast_create_unary(ZEND_POST_INC, $1.u.ast); }
| T_INC variable { $$.u.ast = zend_ast_create_unary(ZEND_PRE_INC, $2.u.ast); }
| variable T_DEC { $$.u.ast = zend_ast_create_unary(ZEND_POST_DEC, $1.u.ast); }
{ $$.u.ast = zend_ast_create_binary(ZEND_AST_AND, $1.u.ast, $3.u.ast); }
| expr T_LOGICAL_XOR expr
{ $$.u.ast = zend_ast_create_binary(ZEND_BOOL_XOR, $1.u.ast, $3.u.ast); }
- | expr '|' expr { $$.u.ast = zend_ast_create_binary(ZEND_BW_OR, $1.u.ast, $3.u.ast); }
- | expr '&' expr { $$.u.ast = zend_ast_create_binary(ZEND_BW_AND, $1.u.ast, $3.u.ast); }
- | expr '^' expr { $$.u.ast = zend_ast_create_binary(ZEND_BW_XOR, $1.u.ast, $3.u.ast); }
- | expr '.' expr { $$.u.ast = zend_ast_create_binary(ZEND_CONCAT, $1.u.ast, $3.u.ast); }
- | expr '+' expr { $$.u.ast = zend_ast_create_binary(ZEND_ADD, $1.u.ast, $3.u.ast); }
- | expr '-' expr { $$.u.ast = zend_ast_create_binary(ZEND_SUB, $1.u.ast, $3.u.ast); }
- | expr '*' expr { $$.u.ast = zend_ast_create_binary(ZEND_MUL, $1.u.ast, $3.u.ast); }
- | expr T_POW expr { $$.u.ast = zend_ast_create_binary(ZEND_POW, $1.u.ast, $3.u.ast); }
- | expr '/' expr { $$.u.ast = zend_ast_create_binary(ZEND_DIV, $1.u.ast, $3.u.ast); }
- | expr '%' expr { $$.u.ast = zend_ast_create_binary(ZEND_MOD, $1.u.ast, $3.u.ast); }
- | expr T_SL expr { $$.u.ast = zend_ast_create_binary(ZEND_SL, $1.u.ast, $3.u.ast); }
- | expr T_SR expr { $$.u.ast = zend_ast_create_binary(ZEND_SR, $1.u.ast, $3.u.ast); }
+ | expr '|' expr { $$.u.ast = zend_ast_create_binary_op(ZEND_BW_OR, $1.u.ast, $3.u.ast); }
+ | expr '&' expr { $$.u.ast = zend_ast_create_binary_op(ZEND_BW_AND, $1.u.ast, $3.u.ast); }
+ | expr '^' expr { $$.u.ast = zend_ast_create_binary_op(ZEND_BW_XOR, $1.u.ast, $3.u.ast); }
+ | expr '.' expr { $$.u.ast = zend_ast_create_binary_op(ZEND_CONCAT, $1.u.ast, $3.u.ast); }
+ | expr '+' expr { $$.u.ast = zend_ast_create_binary_op(ZEND_ADD, $1.u.ast, $3.u.ast); }
+ | expr '-' expr { $$.u.ast = zend_ast_create_binary_op(ZEND_SUB, $1.u.ast, $3.u.ast); }
+ | expr '*' expr { $$.u.ast = zend_ast_create_binary_op(ZEND_MUL, $1.u.ast, $3.u.ast); }
+ | expr T_POW expr { $$.u.ast = zend_ast_create_binary_op(ZEND_POW, $1.u.ast, $3.u.ast); }
+ | expr '/' expr { $$.u.ast = zend_ast_create_binary_op(ZEND_DIV, $1.u.ast, $3.u.ast); }
+ | expr '%' expr { $$.u.ast = zend_ast_create_binary_op(ZEND_MOD, $1.u.ast, $3.u.ast); }
+ | expr T_SL expr { $$.u.ast = zend_ast_create_binary_op(ZEND_SL, $1.u.ast, $3.u.ast); }
+ | expr T_SR expr { $$.u.ast = zend_ast_create_binary_op(ZEND_SR, $1.u.ast, $3.u.ast); }
| '+' expr %prec T_INC { $$.u.ast = zend_ast_create_unary(ZEND_UNARY_PLUS, $2.u.ast); }
| '-' expr %prec T_INC { $$.u.ast = zend_ast_create_unary(ZEND_UNARY_MINUS, $2.u.ast); }
| '!' expr { $$.u.ast = zend_ast_create_unary(ZEND_BOOL_NOT, $2.u.ast); }
| '~' expr { $$.u.ast = zend_ast_create_unary(ZEND_BW_NOT, $2.u.ast); }
| expr T_IS_IDENTICAL expr
- { $$.u.ast = zend_ast_create_binary(ZEND_IS_IDENTICAL, $1.u.ast, $3.u.ast); }
+ { $$.u.ast = zend_ast_create_binary_op(ZEND_IS_IDENTICAL, $1.u.ast, $3.u.ast); }
| expr T_IS_NOT_IDENTICAL expr
- { $$.u.ast = zend_ast_create_binary(ZEND_IS_NOT_IDENTICAL, $1.u.ast, $3.u.ast); }
+ { $$.u.ast = zend_ast_create_binary_op(ZEND_IS_NOT_IDENTICAL, $1.u.ast, $3.u.ast); }
| expr T_IS_EQUAL expr
- { $$.u.ast = zend_ast_create_binary(ZEND_IS_EQUAL, $1.u.ast, $3.u.ast); }
+ { $$.u.ast = zend_ast_create_binary_op(ZEND_IS_EQUAL, $1.u.ast, $3.u.ast); }
| expr T_IS_NOT_EQUAL expr
- { $$.u.ast = zend_ast_create_binary(ZEND_IS_NOT_EQUAL, $1.u.ast, $3.u.ast); }
+ { $$.u.ast = zend_ast_create_binary_op(ZEND_IS_NOT_EQUAL, $1.u.ast, $3.u.ast); }
| expr '<' expr
- { $$.u.ast = zend_ast_create_binary(ZEND_IS_SMALLER, $1.u.ast, $3.u.ast); }
+ { $$.u.ast = zend_ast_create_binary_op(ZEND_IS_SMALLER, $1.u.ast, $3.u.ast); }
| expr T_IS_SMALLER_OR_EQUAL expr
- { $$.u.ast = zend_ast_create_binary(ZEND_IS_SMALLER_OR_EQUAL, $1.u.ast, $3.u.ast); }
+ { $$.u.ast = zend_ast_create_binary_op(ZEND_IS_SMALLER_OR_EQUAL, $1.u.ast, $3.u.ast); }
| expr '>' expr
{ $$.u.ast = zend_ast_create_binary(ZEND_AST_GREATER, $1.u.ast, $3.u.ast); }
| expr T_IS_GREATER_OR_EQUAL expr
{ $$.u.ast = zend_ast_create_binary(ZEND_AST_GREATER_EQUAL, $1.u.ast, $3.u.ast); }
| expr T_INSTANCEOF class_name_reference
{ $$.u.ast = zend_ast_create_binary(ZEND_INSTANCEOF, $1.u.ast, $3.u.ast); }
- | parenthesis_expr { $$.u.ast = AST_ZNODE(&$1); }
+ | parenthesis_expr { $$.u.ast = $1.u.ast; }
| new_expr { $$.u.ast = $1.u.ast; }
| expr '?' expr ':' expr
{ $$.u.ast = zend_ast_create_ternary(
ZEND_AST_CONDITIONAL, $1.u.ast, $3.u.ast, $5.u.ast); }
| expr '?' ':' expr
{ $$.u.ast = zend_ast_create_ternary(ZEND_AST_CONDITIONAL, $1.u.ast, NULL, $4.u.ast); }
- | internal_functions_in_yacc { $$.u.ast = AST_ZNODE(&$1); }
- | T_INT_CAST expr { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_INT, $2.u.ast); }
- | T_DOUBLE_CAST expr { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_DOUBLE, $2.u.ast); }
- | T_STRING_CAST expr { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_STRING, $2.u.ast); }
- | T_ARRAY_CAST expr { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_ARRAY, $2.u.ast); }
- | T_OBJECT_CAST expr { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_OBJECT, $2.u.ast); }
- | T_BOOL_CAST expr { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_BOOL, $2.u.ast); }
- | T_UNSET_CAST expr { $$.u.ast = zend_ast_create_unary(ZEND_AST_CAST_NULL, $2.u.ast); }
- | T_EXIT exit_expr { $$.u.ast = zend_ast_create_unary(ZEND_EXIT, $2.u.ast); }
- | '@' { zend_do_begin_silence(&$1 TSRMLS_CC); } expr { AC($3); zend_do_end_silence(&$1 TSRMLS_CC); $$ = $3; AZ($$); }
- | scalar { $$.u.ast = AST_ZNODE(&$1); }
- | '`' backticks_expr '`' { zend_do_shell_exec(&$$, &$2 TSRMLS_CC); AZ($$); }
+ | internal_functions_in_yacc { $$.u.ast = $1.u.ast; }
+ | T_INT_CAST expr
+ { $$.u.ast = zend_ast_create_unary_ex(ZEND_AST_CAST, IS_LONG, $2.u.ast); }
+ | T_DOUBLE_CAST expr
+ { $$.u.ast = zend_ast_create_unary_ex(ZEND_AST_CAST, IS_DOUBLE, $2.u.ast); }
+ | T_STRING_CAST expr
+ { $$.u.ast = zend_ast_create_unary_ex(ZEND_AST_CAST, IS_STRING, $2.u.ast); }
+ | T_ARRAY_CAST expr
+ { $$.u.ast = zend_ast_create_unary_ex(ZEND_AST_CAST, IS_ARRAY, $2.u.ast); }
+ | T_OBJECT_CAST expr
+ { $$.u.ast = zend_ast_create_unary_ex(ZEND_AST_CAST, IS_OBJECT, $2.u.ast); }
+ | T_BOOL_CAST expr
+ { $$.u.ast = zend_ast_create_unary_ex(ZEND_AST_CAST, _IS_BOOL, $2.u.ast); }
+ | T_UNSET_CAST expr
+ { $$.u.ast = zend_ast_create_unary_ex(ZEND_AST_CAST, IS_NULL, $2.u.ast); }
+ | T_EXIT exit_expr { $$.u.ast = zend_ast_create_unary(ZEND_EXIT, $2.u.ast); }
+ | '@' expr { $$.u.ast = zend_ast_create_unary(ZEND_AST_SILENCE, $2.u.ast); }
+ | scalar { $$.u.ast = $1.u.ast; }
+ | '`' backticks_expr '`' { $$.u.ast = zend_ast_create_unary(ZEND_AST_SHELL_EXEC, $2.u.ast); }
| T_PRINT expr { $$.u.ast = zend_ast_create_unary(ZEND_PRINT, $2.u.ast); }
| T_YIELD { $$.u.ast = zend_ast_create_binary(ZEND_YIELD, NULL, NULL); }
| T_YIELD expr { $$.u.ast = zend_ast_create_binary(ZEND_YIELD, $2.u.ast, NULL); }
{ $$.u.ast = zend_ast_create_binary(ZEND_YIELD, $4.u.ast, $2.u.ast); }
| function is_reference { zend_do_begin_lambda_function_declaration(&$$, &$1, $2.op_type, 0 TSRMLS_CC); }
'(' parameter_list ')' lexical_vars
- '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); $$ = $3; AZ($$); }
+ '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); $$.u.ast = AST_ZNODE(&$3); }
| T_STATIC function is_reference { zend_do_begin_lambda_function_declaration(&$$, &$2, $3.op_type, 1 TSRMLS_CC); }
'(' parameter_list ')' lexical_vars
- '{' inner_statement_list '}' { zend_do_end_function_declaration(&$2 TSRMLS_CC); $$ = $4; AZ($$); }
+ '{' inner_statement_list '}' { zend_do_end_function_declaration(&$2 TSRMLS_CC); $$.u.ast = AST_ZNODE(&$4); }
;
function:
function_call:
namespace_name function_call_parameter_list
{ $$.u.ast = zend_ast_create_binary(ZEND_AST_CALL,
- zend_ast_create_unary(ZEND_AST_NAME, AST_ZVAL(&$1)), $2.u.ast); }
+ zend_ast_create_zval_ex(&$1.u.constant, 1), $2.u.ast); }
| T_NAMESPACE T_NS_SEPARATOR namespace_name function_call_parameter_list
{ ZVAL_EMPTY_STRING(&$1.u.constant);
zend_do_build_namespace_name(&$1, &$1, &$3 TSRMLS_CC);
- $$.u.ast = zend_ast_create_binary(ZEND_AST_CALL,
- zend_ast_create_unary(ZEND_AST_NAME_FQ, AST_ZVAL(&$1)), $4.u.ast); }
+ $$.u.ast = zend_ast_create_binary(ZEND_AST_CALL, AST_ZVAL(&$1), $4.u.ast); }
| T_NS_SEPARATOR namespace_name function_call_parameter_list
- { $$.u.ast = zend_ast_create_binary(ZEND_AST_CALL,
- zend_ast_create_unary(ZEND_AST_NAME_FQ, AST_ZVAL(&$2)), $3.u.ast); }
+ { $$.u.ast = zend_ast_create_binary(ZEND_AST_CALL, AST_ZVAL(&$2), $3.u.ast); }
| class_name T_PAAMAYIM_NEKUDOTAYIM member_name function_call_parameter_list
{ $$.u.ast = zend_ast_create_ternary(ZEND_AST_STATIC_CALL,
AST_ZVAL(&$1), $3.u.ast, $4.u.ast); }
| variable_class_name T_PAAMAYIM_NEKUDOTAYIM member_name function_call_parameter_list
{ $$.u.ast = zend_ast_create_ternary(ZEND_AST_STATIC_CALL,
- AST_ZNODE(&$1), $3.u.ast, $4.u.ast); }
+ $1.u.ast, $3.u.ast, $4.u.ast); }
| callable_expr function_call_parameter_list
{ $$.u.ast = zend_ast_create_binary(ZEND_AST_CALL, $1.u.ast, $2.u.ast); }
;
exit_expr:
/* empty */ { $$.u.ast = NULL; }
| '(' ')' { $$.u.ast = NULL; }
- | parenthesis_expr { $$.u.ast = AST_ZNODE(&$1); }
+ | parenthesis_expr { $$.u.ast = $1.u.ast; }
;
backticks_expr:
- /* empty */ { ZVAL_EMPTY_STRING(&$$.u.constant); $$.op_type = IS_CONST; }
- | T_ENCAPSED_AND_WHITESPACE { $$ = $1; }
- | encaps_list { $$ = $1; }
+ /* empty */
+ { zval empty_str; ZVAL_EMPTY_STRING(&empty_str);
+ $$.u.ast = zend_ast_create_constant(&empty_str); }
+ | T_ENCAPSED_AND_WHITESPACE { $$.u.ast = AST_ZVAL(&$1); }
+ | encaps_list { $$.u.ast = AST_ZNODE(&$1); }
;
dereferencable_scalar:
- T_ARRAY '(' array_pair_list ')' { $$ = $3; }
- | '[' array_pair_list ']' { $$ = $2; }
- | T_CONSTANT_ENCAPSED_STRING { $$ = $1; }
+ T_ARRAY '(' array_pair_list ')' { $$.u.ast = $3.u.ast; }
+ | '[' array_pair_list ']' { $$.u.ast = $2.u.ast; }
+ | T_CONSTANT_ENCAPSED_STRING { $$.u.ast = AST_ZVAL(&$1); }
;
common_scalar:
- T_LNUMBER { $$ = $1; }
- | T_DNUMBER { $$ = $1; }
- | T_LINE { $$ = $1; }
- | T_FILE { $$ = $1; }
- | T_DIR { $$ = $1; }
- | T_TRAIT_C { $$ = $1; }
- | T_METHOD_C { $$ = $1; }
- | T_FUNC_C { $$ = $1; }
- | T_NS_C { $$ = $1; }
- | T_START_HEREDOC T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC { $$ = $2; }
- | T_START_HEREDOC T_END_HEREDOC { ZVAL_EMPTY_STRING(&$$.u.constant); $$.op_type = IS_CONST; }
+ T_LNUMBER { $$.u.ast = AST_ZVAL(&$1); }
+ | T_DNUMBER { $$.u.ast = AST_ZVAL(&$1); }
+ | T_LINE { $$.u.ast = AST_ZVAL(&$1); }
+ | T_FILE { $$.u.ast = AST_ZVAL(&$1); }
+ | T_DIR { $$.u.ast = AST_ZVAL(&$1); }
+ | T_TRAIT_C { $$.u.ast = AST_ZVAL(&$1); }
+ | T_METHOD_C { $$.u.ast = AST_ZVAL(&$1); }
+ | T_FUNC_C { $$.u.ast = AST_ZVAL(&$1); }
+ | T_NS_C { $$.u.ast = AST_ZVAL(&$1); }
+ | T_START_HEREDOC T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC { $$.u.ast = AST_ZVAL(&$2); }
+ | T_START_HEREDOC T_END_HEREDOC
+ { zval empty_str; ZVAL_EMPTY_STRING(&empty_str);
+ $$.u.ast = zend_ast_create_constant(&empty_str); }
;
static_class_constant:
;
static_scalar_base:
- common_scalar { $$ = $1; }
- | T_CONSTANT_ENCAPSED_STRING { $$ = $1; }
+ T_CONSTANT_ENCAPSED_STRING { $$ = $1; }
| T_CLASS_C { $$ = $1; }
| static_class_name_scalar { $$ = $1; }
| static_class_constant { $$ = $1; }
static_scalar_value:
static_scalar_base { $$.u.ast = zend_ast_create_constant(&$1.u.constant); }
+ | common_scalar { $$.u.ast = $1.u.ast; }
| T_ARRAY '(' static_array_pair_list ')' { $$ = $3; }
| '[' static_array_pair_list ']' { $$ = $2; }
| static_operation { $$ = $1; }
scalar:
- T_STRING_VARNAME { $$ = $1; }
- | class_name_scalar { $$ = $1; }
- | class_constant { $$ = $1; }
- | namespace_name { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_RT, 1 TSRMLS_CC); }
- | T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); $3 = $$; zend_do_fetch_constant(&$$, NULL, &$3, ZEND_RT, 0 TSRMLS_CC); }
- | T_NS_SEPARATOR namespace_name { zval tmp; ZVAL_NEW_STR(&tmp, STR_ALLOC(Z_STRLEN($2.u.constant)+1, 0)); Z_STRVAL(tmp)[0] = '\\'; memcpy(Z_STRVAL(tmp) + 1, Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); if (Z_DELREF($2.u.constant) == 0) {efree(Z_STR($2.u.constant));} Z_STR($2.u.constant) = Z_STR(tmp); zend_do_fetch_constant(&$$, NULL, &$2, ZEND_RT, 0 TSRMLS_CC); }
- | common_scalar { $$ = $1; }
- | '"' encaps_list '"' { $$ = $2; }
- | T_START_HEREDOC encaps_list T_END_HEREDOC { $$ = $2; }
- | T_CLASS_C { if (Z_TYPE($1.u.constant) == IS_CONSTANT) {zend_do_fetch_constant(&$$, NULL, &$1, ZEND_RT, 1 TSRMLS_CC);} else {$$ = $1;} }
- | dereferencable_scalar { $$ = $1; }
+ T_STRING_VARNAME { $$ = $1; AZ($$); }
+ | class_name_scalar { $$.u.ast = $1.u.ast; }
+ | class_constant { $$.u.ast = $1.u.ast; }
+ | namespace_name
+ { $$.u.ast = zend_ast_create_unary(
+ ZEND_AST_CONST, zend_ast_create_zval_ex(&$1.u.constant, 1)); }
+ | T_NAMESPACE T_NS_SEPARATOR namespace_name
+ { ZVAL_EMPTY_STRING(&$1.u.constant);
+ zend_do_build_namespace_name(&$1, &$1, &$3 TSRMLS_CC);
+ $$.u.ast = zend_ast_create_unary(ZEND_AST_CONST, AST_ZVAL(&$1)); }
+ | T_NS_SEPARATOR namespace_name
+ { zval tmp; ZVAL_NEW_STR(&tmp, STR_ALLOC(Z_STRLEN($2.u.constant)+1, 0)); Z_STRVAL(tmp)[0] = '\\'; memcpy(Z_STRVAL(tmp) + 1, Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1);
+ if (Z_DELREF($2.u.constant) == 0) { efree(Z_STR($2.u.constant)); }
+ Z_STR($2.u.constant) = Z_STR(tmp);
+ $$.u.ast = zend_ast_create_unary(ZEND_AST_CONST, AST_ZVAL(&$2)); }
+ | common_scalar { $$.u.ast = $1.u.ast; }
+ | '"' encaps_list '"' { $$ = $2; AZ($$); }
+ | T_START_HEREDOC encaps_list T_END_HEREDOC { $$ = $2; AZ($$); }
+ | T_CLASS_C { if (Z_TYPE($1.u.constant) == IS_CONSTANT) {zend_do_fetch_constant(&$$, NULL, &$1, ZEND_RT, 1 TSRMLS_CC); AZ($$); } else { $$.u.ast = AST_ZVAL(&$1); } }
+ | dereferencable_scalar { $$.u.ast = $1.u.ast; }
;
;
parenthesis_expr:
- '(' expr ')' { AST_COMPILE(&$$, $2.u.ast); }
-;
-
-w_variable:
- variable { zend_ensure_writable_variable($1.u.ast); AST_COMPILE_VAR(&$$, $1.u.ast, BP_VAR_W); }
+ '(' expr ')' { $$.u.ast = $2.u.ast; }
;
variable_class_name:
- dereferencable { zend_compile_expr(&$$, $1.u.ast TSRMLS_CC); zend_ast_destroy($1.u.ast); }
+ dereferencable { $$.u.ast = $1.u.ast; }
;
dereferencable:
variable { $$.u.ast = $1.u.ast; }
| '(' expr ')' { $$.u.ast = $2.u.ast; }
- | dereferencable_scalar { $$.u.ast = AST_ZNODE(&$1); }
+ | dereferencable_scalar { $$.u.ast = $1.u.ast; }
;
callable_expr:
callable_variable { $$.u.ast = $1.u.ast; }
| '(' expr ')' { $$.u.ast = $2.u.ast; }
- | dereferencable_scalar { $$.u.ast = AST_ZNODE(&$1); }
+ | dereferencable_scalar { $$.u.ast = $1.u.ast; }
;
callable_variable:
class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable
{ $$.u.ast = zend_ast_create_binary(ZEND_AST_STATIC_PROP, AST_ZVAL(&$1), $3.u.ast); }
| variable_class_name T_PAAMAYIM_NEKUDOTAYIM simple_variable
- { $$.u.ast = zend_ast_create_binary(ZEND_AST_STATIC_PROP, AST_ZNODE(&$1), $3.u.ast); }
+ { $$.u.ast = zend_ast_create_binary(ZEND_AST_STATIC_PROP, $1.u.ast, $3.u.ast); }
;
new_variable:
array_pair_list:
- /* empty */ { zend_do_init_array(&$$, NULL, NULL, 0 TSRMLS_CC); zend_do_end_array(&$$, &$$ TSRMLS_CC); }
- | non_empty_array_pair_list possible_comma { zend_do_end_array(&$$, &$1 TSRMLS_CC); }
+ /* empty */ { $$.u.ast = zend_ast_create_dynamic(ZEND_AST_ARRAY); }
+ | non_empty_array_pair_list possible_comma { $$.u.ast = $1.u.ast; }
;
non_empty_array_pair_list:
- non_empty_array_pair_list ',' expr T_DOUBLE_ARROW expr { AC($3); AC($5); zend_do_add_array_element(&$$, &$5, &$3, 0 TSRMLS_CC); }
- | non_empty_array_pair_list ',' expr { AC($3); zend_do_add_array_element(&$$, &$3, NULL, 0 TSRMLS_CC); }
- | expr T_DOUBLE_ARROW expr { AC($1); AC($3); zend_do_init_array(&$$, &$3, &$1, 0 TSRMLS_CC); }
- | expr { AC($1); zend_do_init_array(&$$, &$1, NULL, 0 TSRMLS_CC); }
- | non_empty_array_pair_list ',' expr T_DOUBLE_ARROW '&' w_variable { AC($3); zend_do_add_array_element(&$$, &$6, &$3, 1 TSRMLS_CC); }
- | non_empty_array_pair_list ',' '&' w_variable { zend_do_add_array_element(&$$, &$4, NULL, 1 TSRMLS_CC); }
- | expr T_DOUBLE_ARROW '&' w_variable { AC($1); zend_do_init_array(&$$, &$4, &$1, 1 TSRMLS_CC); }
- | '&' w_variable { zend_do_init_array(&$$, &$2, NULL, 1 TSRMLS_CC); }
+ non_empty_array_pair_list ',' array_pair
+ { zend_ast_dynamic_add(&$1.u.ast, $3.u.ast); $$.u.ast = $1.u.ast; }
+ | array_pair
+ { $$.u.ast = zend_ast_create_dynamic(ZEND_AST_ARRAY);
+ zend_ast_dynamic_add(&$$.u.ast, $1.u.ast); }
+;
+
+array_pair:
+ expr T_DOUBLE_ARROW expr
+ { $$.u.ast = zend_ast_create_binary(ZEND_AST_ARRAY_ELEM, $3.u.ast, $1.u.ast); }
+ | expr { $$.u.ast = zend_ast_create_binary(ZEND_AST_ARRAY_ELEM, $1.u.ast, NULL); }
+ | expr T_DOUBLE_ARROW '&' variable
+ { $$.u.ast = zend_ast_create_binary_ex(ZEND_AST_ARRAY_ELEM, 1, $4.u.ast, $1.u.ast); }
+ | '&' variable
+ { $$.u.ast = zend_ast_create_binary_ex(ZEND_AST_ARRAY_ELEM, 1, $2.u.ast, NULL); }
;
encaps_list:
internal_functions_in_yacc:
- T_ISSET '(' isset_variables ')' { $$ = $3; }
- | T_EMPTY '(' variable ')' { zend_do_isset_or_isempty(ZEND_ISEMPTY, &$$, &$3 TSRMLS_CC); }
- | T_EMPTY '(' expr_without_variable ')' { AC($3); zend_do_unary_op(ZEND_BOOL_NOT, &$$, &$3 TSRMLS_CC); }
- | T_INCLUDE expr { AC($2); zend_do_include_or_eval(ZEND_INCLUDE, &$$, &$2 TSRMLS_CC); }
- | T_INCLUDE_ONCE expr { AC($2); zend_do_include_or_eval(ZEND_INCLUDE_ONCE, &$$, &$2 TSRMLS_CC); }
- | T_EVAL '(' expr ')' { AC($3); zend_do_include_or_eval(ZEND_EVAL, &$$, &$3 TSRMLS_CC); }
- | T_REQUIRE expr { AC($2); zend_do_include_or_eval(ZEND_REQUIRE, &$$, &$2 TSRMLS_CC); }
- | T_REQUIRE_ONCE expr { AC($2); zend_do_include_or_eval(ZEND_REQUIRE_ONCE, &$$, &$2 TSRMLS_CC); }
+ T_ISSET '(' isset_variables ')' { $$.u.ast = $3.u.ast; }
+ | T_EMPTY '(' expr ')' { $$.u.ast = zend_ast_create_unary(ZEND_AST_EMPTY, $3.u.ast); }
+ | T_INCLUDE expr
+ { $$.u.ast = zend_ast_create_unary_ex(ZEND_INCLUDE_OR_EVAL, ZEND_INCLUDE, $2.u.ast); }
+ | T_INCLUDE_ONCE expr
+ { $$.u.ast = zend_ast_create_unary_ex(
+ ZEND_INCLUDE_OR_EVAL, ZEND_INCLUDE_ONCE, $2.u.ast); }
+ | T_EVAL '(' expr ')'
+ { $$.u.ast = zend_ast_create_unary_ex(ZEND_INCLUDE_OR_EVAL, ZEND_EVAL, $3.u.ast); }
+ | T_REQUIRE expr
+ { $$.u.ast = zend_ast_create_unary_ex(ZEND_INCLUDE_OR_EVAL, ZEND_REQUIRE, $2.u.ast); }
+ | T_REQUIRE_ONCE expr
+ { $$.u.ast = zend_ast_create_unary_ex(
+ ZEND_INCLUDE_OR_EVAL, ZEND_REQUIRE_ONCE, $2.u.ast); }
;
isset_variables:
- isset_variable { $$ = $1; }
- | isset_variables ',' { zend_do_boolean_and_begin(&$1, &$2 TSRMLS_CC); } isset_variable { zend_do_boolean_and_end(&$$, &$1, &$4, &$2 TSRMLS_CC); }
+ isset_variable { $$.u.ast = $1.u.ast; }
+ | isset_variables ',' isset_variable
+ { $$.u.ast = zend_ast_create_binary(ZEND_AST_AND, $1.u.ast, $3.u.ast); }
;
isset_variable:
- variable { zend_do_isset_or_isempty(ZEND_ISSET, &$$, &$1 TSRMLS_CC); }
- | expr_without_variable { zend_error_noreturn(E_COMPILE_ERROR, "Cannot use isset() on the result of an expression (you can use \"null !== expression\" instead)"); }
+ expr { $$.u.ast = zend_ast_create_unary(ZEND_AST_ISSET, $1.u.ast); }
;
class_constant:
- class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_RT, 0 TSRMLS_CC); }
- | variable_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_RT, 0 TSRMLS_CC); }
+ class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING
+ { $$.u.ast = zend_ast_create_binary(
+ ZEND_AST_CLASS_CONST, AST_ZVAL(&$1), AST_ZVAL(&$3)); }
+ | variable_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING
+ { $$.u.ast = zend_ast_create_binary(
+ ZEND_AST_CLASS_CONST, $1.u.ast, AST_ZVAL(&$3)); }
;
static_class_name_scalar:
;
class_name_scalar:
- class_name T_PAAMAYIM_NEKUDOTAYIM T_CLASS { zend_do_resolve_class_name(&$$, &$1, 0 TSRMLS_CC); }
+ class_name T_PAAMAYIM_NEKUDOTAYIM T_CLASS
+ { $$.u.ast = zend_ast_create_unary(ZEND_AST_RESOLVE_CLASS_NAME, AST_ZVAL(&$1)); }
;
%%
switch (opcode) {
case ZEND_BW_NOT:
return (unary_op_type) bitwise_not_function;
- break;
case ZEND_BOOL_NOT:
return (unary_op_type) boolean_not_function;
- break;
default:
return (unary_op_type) NULL;
- break;
}
}
case ZEND_ADD:
case ZEND_ASSIGN_ADD:
return (binary_op_type) add_function;
- break;
case ZEND_SUB:
case ZEND_ASSIGN_SUB:
return (binary_op_type) sub_function;
- break;
case ZEND_MUL:
case ZEND_ASSIGN_MUL:
return (binary_op_type) mul_function;
- break;
case ZEND_POW:
return (binary_op_type) pow_function;
- break;
case ZEND_DIV:
case ZEND_ASSIGN_DIV:
return (binary_op_type) div_function;
- break;
case ZEND_MOD:
case ZEND_ASSIGN_MOD:
return (binary_op_type) mod_function;
- break;
case ZEND_SL:
case ZEND_ASSIGN_SL:
return (binary_op_type) shift_left_function;
- break;
case ZEND_SR:
case ZEND_ASSIGN_SR:
return (binary_op_type) shift_right_function;
- break;
case ZEND_CONCAT:
case ZEND_ASSIGN_CONCAT:
return (binary_op_type) concat_function;
- break;
case ZEND_IS_IDENTICAL:
return (binary_op_type) is_identical_function;
- break;
case ZEND_IS_NOT_IDENTICAL:
return (binary_op_type) is_not_identical_function;
- break;
case ZEND_IS_EQUAL:
return (binary_op_type) is_equal_function;
- break;
case ZEND_IS_NOT_EQUAL:
return (binary_op_type) is_not_equal_function;
- break;
case ZEND_IS_SMALLER:
return (binary_op_type) is_smaller_function;
- break;
case ZEND_IS_SMALLER_OR_EQUAL:
return (binary_op_type) is_smaller_or_equal_function;
- break;
case ZEND_BW_OR:
case ZEND_ASSIGN_BW_OR:
return (binary_op_type) bitwise_or_function;
- break;
case ZEND_BW_AND:
case ZEND_ASSIGN_BW_AND:
return (binary_op_type) bitwise_and_function;
- break;
case ZEND_BW_XOR:
case ZEND_ASSIGN_BW_XOR:
return (binary_op_type) bitwise_xor_function;
- break;
case ZEND_BOOL_XOR:
return (binary_op_type) boolean_xor_function;
- break;
default:
return (binary_op_type) NULL;
- break;
}
}