123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 |
- /*
- +----------------------------------------------------------------------+
- | Zend Engine |
- +----------------------------------------------------------------------+
- | Copyright (c) 1998-2016 Zend Technologies Ltd. (http://www.zend.com) |
- +----------------------------------------------------------------------+
- | This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.zend.com/license/2_00.txt. |
- | If you did not receive a copy of the Zend license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@zend.com so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Bob Weinand <bwoebi@php.net> |
- | Dmitry Stogov <dmitry@zend.com> |
- +----------------------------------------------------------------------+
- */
- /* $Id$ */
- #include "zend_ast.h"
- #include "zend_API.h"
- #include "zend_operators.h"
- ZEND_API zend_ast *zend_ast_create_constant(zval *zv)
- {
- zend_ast *ast = emalloc(sizeof(zend_ast) + sizeof(zval));
- ast->kind = ZEND_CONST;
- ast->children = 0;
- ast->u.val = (zval*)(ast + 1);
- INIT_PZVAL_COPY(ast->u.val, zv);
- return ast;
- }
- ZEND_API zend_ast* zend_ast_create_unary(uint kind, zend_ast *op0)
- {
- zend_ast *ast = emalloc(sizeof(zend_ast));
- ast->kind = kind;
- ast->children = 1;
- (&ast->u.child)[0] = op0;
- return ast;
- }
- ZEND_API zend_ast* zend_ast_create_binary(uint kind, zend_ast *op0, zend_ast *op1)
- {
- zend_ast *ast = emalloc(sizeof(zend_ast) + sizeof(zend_ast*));
- ast->kind = kind;
- ast->children = 2;
- (&ast->u.child)[0] = op0;
- (&ast->u.child)[1] = op1;
- return ast;
- }
- ZEND_API zend_ast* zend_ast_create_ternary(uint kind, zend_ast *op0, zend_ast *op1, zend_ast *op2)
- {
- zend_ast *ast = emalloc(sizeof(zend_ast) + sizeof(zend_ast*) * 2);
- ast->kind = kind;
- ast->children = 3;
- (&ast->u.child)[0] = op0;
- (&ast->u.child)[1] = op1;
- (&ast->u.child)[2] = op2;
- return ast;
- }
- ZEND_API zend_ast* zend_ast_create_dynamic(uint kind)
- {
- zend_ast *ast = emalloc(sizeof(zend_ast) + sizeof(zend_ast*) * 3); /* use 4 children as deafult */
- ast->kind = kind;
- ast->children = 0;
- return ast;
- }
- ZEND_API void zend_ast_dynamic_add(zend_ast **ast, zend_ast *op)
- {
- if ((*ast)->children >= 4 && (*ast)->children == ((*ast)->children & -(*ast)->children)) {
- *ast = erealloc(*ast, sizeof(zend_ast) + sizeof(zend_ast*) * ((*ast)->children * 2 + 1));
- }
- (&(*ast)->u.child)[(*ast)->children++] = op;
- }
- ZEND_API void zend_ast_dynamic_shrink(zend_ast **ast)
- {
- *ast = erealloc(*ast, sizeof(zend_ast) + sizeof(zend_ast*) * ((*ast)->children - 1));
- }
- ZEND_API int zend_ast_is_ct_constant(zend_ast *ast)
- {
- int i;
- if (ast->kind == ZEND_CONST) {
- return !IS_CONSTANT_TYPE(Z_TYPE_P(ast->u.val));
- } else {
- for (i = 0; i < ast->children; i++) {
- if ((&ast->u.child)[i]) {
- if (!zend_ast_is_ct_constant((&ast->u.child)[i])) {
- return 0;
- }
- }
- }
- return 1;
- }
- }
- ZEND_API void zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *scope TSRMLS_DC)
- {
- zval op1, op2;
- switch (ast->kind) {
- case ZEND_ADD:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- add_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- case ZEND_SUB:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- sub_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- case ZEND_MUL:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- mul_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- case ZEND_POW:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- pow_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- case ZEND_DIV:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- div_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- case ZEND_MOD:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- mod_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- case ZEND_SL:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- shift_left_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- case ZEND_SR:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- shift_right_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- case ZEND_CONCAT:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- concat_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- case ZEND_BW_OR:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- bitwise_or_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- case ZEND_BW_AND:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- bitwise_and_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- case ZEND_BW_XOR:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- bitwise_xor_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- case ZEND_BW_NOT:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- bitwise_not_function(result, &op1 TSRMLS_CC);
- zval_dtor(&op1);
- break;
- case ZEND_BOOL_NOT:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- boolean_not_function(result, &op1 TSRMLS_CC);
- zval_dtor(&op1);
- break;
- case ZEND_BOOL_XOR:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- boolean_xor_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- case ZEND_IS_IDENTICAL:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- is_identical_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- case ZEND_IS_NOT_IDENTICAL:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- is_not_identical_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- case ZEND_IS_EQUAL:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- is_equal_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- case ZEND_IS_NOT_EQUAL:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- is_not_equal_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- case ZEND_IS_SMALLER:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- is_smaller_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- case ZEND_IS_SMALLER_OR_EQUAL:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- is_smaller_or_equal_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- case ZEND_CONST:
- /* class constants may be updated in-place */
- if (scope) {
- if (IS_CONSTANT_TYPE(Z_TYPE_P(ast->u.val))) {
- zval_update_constant_ex(&ast->u.val, 1, scope TSRMLS_CC);
- }
- *result = *ast->u.val;
- zval_copy_ctor(result);
- } else {
- *result = *ast->u.val;
- zval_copy_ctor(result);
- if (IS_CONSTANT_TYPE(Z_TYPE_P(result))) {
- zval_update_constant_ex(&result, 1, scope TSRMLS_CC);
- }
- }
- break;
- case ZEND_BOOL_AND:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- if (zend_is_true(&op1)) {
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- ZVAL_BOOL(result, zend_is_true(&op2));
- zval_dtor(&op2);
- } else {
- ZVAL_BOOL(result, 0);
- }
- zval_dtor(&op1);
- break;
- case ZEND_BOOL_OR:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- if (zend_is_true(&op1)) {
- ZVAL_BOOL(result, 1);
- } else {
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- ZVAL_BOOL(result, zend_is_true(&op2));
- zval_dtor(&op2);
- }
- zval_dtor(&op1);
- break;
- case ZEND_SELECT:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- if (zend_is_true(&op1)) {
- if (!(&ast->u.child)[1]) {
- *result = op1;
- } else {
- zend_ast_evaluate(result, (&ast->u.child)[1], scope TSRMLS_CC);
- zval_dtor(&op1);
- }
- } else {
- zend_ast_evaluate(result, (&ast->u.child)[2], scope TSRMLS_CC);
- zval_dtor(&op1);
- }
- break;
- case ZEND_UNARY_PLUS:
- ZVAL_LONG(&op1, 0);
- zend_ast_evaluate(&op2, (&ast->u.child)[0], scope TSRMLS_CC);
- add_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op2);
- break;
- case ZEND_UNARY_MINUS:
- ZVAL_LONG(&op1, 0);
- zend_ast_evaluate(&op2, (&ast->u.child)[0], scope TSRMLS_CC);
- sub_function(result, &op1, &op2 TSRMLS_CC);
- zval_dtor(&op2);
- break;
- case ZEND_INIT_ARRAY:
- INIT_PZVAL(result);
- array_init(result);
- {
- int i;
- zend_bool has_key;
- for (i = 0; i < ast->children; i+=2) {
- zval *expr;
- MAKE_STD_ZVAL(expr);
- if ((has_key = !!(&ast->u.child)[i])) {
- zend_ast_evaluate(&op1, (&ast->u.child)[i], scope TSRMLS_CC);
- }
- zend_ast_evaluate(expr, (&ast->u.child)[i+1], scope TSRMLS_CC);
- zend_do_add_static_array_element(result, has_key?&op1:NULL, expr);
- }
- }
- break;
- case ZEND_FETCH_DIM_R:
- zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
- zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
- {
- zval *tmp;
- zend_fetch_dimension_by_zval(&tmp, &op1, &op2 TSRMLS_CC);
- ZVAL_ZVAL(result, tmp, 1, 1);
- }
- zval_dtor(&op1);
- zval_dtor(&op2);
- break;
- default:
- zend_error(E_ERROR, "Unsupported constant expression");
- }
- }
- ZEND_API zend_ast *zend_ast_copy(zend_ast *ast)
- {
- if (ast == NULL) {
- return NULL;
- } else if (ast->kind == ZEND_CONST) {
- zend_ast *copy = zend_ast_create_constant(ast->u.val);
- zval_copy_ctor(copy->u.val);
- return copy;
- } else if (ast->children) {
- zend_ast *new = emalloc(sizeof(zend_ast) + sizeof(zend_ast*) * (ast->children - 1));
- int i;
- new->kind = ast->kind;
- new->children = ast->children;
- for (i = 0; i < ast->children; i++) {
- (&new->u.child)[i] = zend_ast_copy((&ast->u.child)[i]);
- }
- return new;
- }
- return zend_ast_create_dynamic(ast->kind);
- }
- ZEND_API void zend_ast_destroy(zend_ast *ast)
- {
- int i;
- if (ast->kind == ZEND_CONST) {
- zval_dtor(ast->u.val);
- } else {
- for (i = 0; i < ast->children; i++) {
- if ((&ast->u.child)[i]) {
- zend_ast_destroy((&ast->u.child)[i]);
- }
- }
- }
- efree(ast);
- }
|