diff options
Diffstat (limited to 'Zend/zend_ast.c')
-rw-r--r-- | Zend/zend_ast.c | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c new file mode 100644 index 0000000000..cf595b4d58 --- /dev/null +++ b/Zend/zend_ast.c @@ -0,0 +1,329 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2014 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 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_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: + *result = *ast->u.val; + zval_copy_ctor(result); + if (IS_CONSTANT_TYPE(Z_TYPE_P(result))) { + zval_update_constant_ex(&result, (void *) 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; + 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 { + switch (ast->children) { + case 1: + return zend_ast_create_unary( + ast->kind, + zend_ast_copy((&ast->u.child)[0])); + case 2: + return zend_ast_create_binary( + ast->kind, + zend_ast_copy((&ast->u.child)[0]), + zend_ast_copy((&ast->u.child)[1])); + case 3: + return zend_ast_create_ternary( + ast->kind, + zend_ast_copy((&ast->u.child)[0]), + zend_ast_copy((&ast->u.child)[1]), + zend_ast_copy((&ast->u.child)[2])); + } + } + return NULL; +} + +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); +} |