php-src/Zend/zend_ast.c

330 lines
10 KiB
C
Raw Normal View History

/*
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
2014-01-03 11:08:10 +08:00
| 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> |
2013-11-07 02:21:07 +08:00
| Dmitry Stogov <dmitry@zend.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#include "zend_ast.h"
2013-11-07 02:21:07 +08:00
#include "zend_API.h"
#include "zend_operators.h"
2013-11-07 14:22:49 +08:00
ZEND_API zend_ast *zend_ast_create_constant(zval *zv)
2013-11-07 02:21:07 +08:00
{
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;
}
2013-11-07 14:22:49 +08:00
ZEND_API zend_ast* zend_ast_create_unary(uint kind, zend_ast *op0)
2013-11-07 02:21:07 +08:00
{
zend_ast *ast = emalloc(sizeof(zend_ast));
ast->kind = kind;
ast->children = 1;
(&ast->u.child)[0] = op0;
return ast;
}
2013-11-07 14:22:49 +08:00
ZEND_API zend_ast* zend_ast_create_binary(uint kind, zend_ast *op0, zend_ast *op1)
2013-11-07 02:21:07 +08:00
{
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;
}
2013-11-07 14:22:49 +08:00
ZEND_API zend_ast* zend_ast_create_ternary(uint kind, zend_ast *op0, zend_ast *op1, zend_ast *op2)
2013-11-07 02:21:07 +08:00
{
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;
}
2013-11-07 02:21:07 +08:00
ZEND_API int zend_ast_is_ct_constant(zend_ast *ast)
{
int i;
2013-11-07 02:21:07 +08:00
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])) {
2013-11-07 02:21:07 +08:00
return 0;
}
}
}
2013-11-07 02:21:07 +08:00
return 1;
}
2013-11-07 02:21:07 +08:00
}
ZEND_API void zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *scope TSRMLS_DC)
2013-11-07 02:21:07 +08:00
{
zval op1, op2;
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
bitwise_or_function(result, &op1, &op2 TSRMLS_CC);
zval_dtor(&op1);
zval_dtor(&op2);
break;
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
bitwise_and_function(result, &op1, &op2 TSRMLS_CC);
zval_dtor(&op1);
zval_dtor(&op2);
break;
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
bitwise_xor_function(result, &op1, &op2 TSRMLS_CC);
zval_dtor(&op1);
zval_dtor(&op2);
break;
2013-11-07 02:21:07 +08:00
case ZEND_BW_NOT:
zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
}
break;
case ZEND_BOOL_AND:
zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
2013-11-07 02:21:07 +08:00
if (zend_is_true(&op1)) {
zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
if (zend_is_true(&op1)) {
ZVAL_BOOL(result, 1);
} else {
zend_ast_evaluate(&op2, (&ast->u.child)[1], scope TSRMLS_CC);
2013-11-07 02:21:07 +08:00
ZVAL_BOOL(result, zend_is_true(&op2));
zval_dtor(&op2);
}
zval_dtor(&op1);
break;
2013-11-07 14:22:49 +08:00
case ZEND_SELECT:
zend_ast_evaluate(&op1, (&ast->u.child)[0], scope TSRMLS_CC);
2013-11-07 02:21:07 +08:00
if (zend_is_true(&op1)) {
if (!(&ast->u.child)[1]) {
2013-11-07 02:21:07 +08:00
*result = op1;
} else {
zend_ast_evaluate(result, (&ast->u.child)[1], scope TSRMLS_CC);
2013-11-07 02:21:07 +08:00
zval_dtor(&op1);
}
} else {
zend_ast_evaluate(result, (&ast->u.child)[2], scope TSRMLS_CC);
2013-11-07 02:21:07 +08:00
zval_dtor(&op1);
}
break;
case ZEND_UNARY_PLUS:
ZVAL_LONG(&op1, 0);
zend_ast_evaluate(&op2, (&ast->u.child)[0], scope TSRMLS_CC);
2013-11-07 02:21:07 +08:00
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);
2013-11-07 02:21:07 +08:00
sub_function(result, &op1, &op2 TSRMLS_CC);
zval_dtor(&op2);
break;
default:
zend_error(E_ERROR, "Unsupported constant expression");
}
2013-11-07 02:21:07 +08:00
}
2013-11-07 02:21:07 +08:00
ZEND_API zend_ast *zend_ast_copy(zend_ast *ast)
{
if (ast == NULL) {
return NULL;
2013-11-07 02:21:07 +08:00
} else if (ast->kind == ZEND_CONST) {
zend_ast *copy = zend_ast_create_constant(ast->u.val);
zval_copy_ctor(copy->u.val);
return copy;
2013-11-07 02:21:07 +08:00
} else {
switch (ast->children) {
case 1:
2013-11-07 14:22:49 +08:00
return zend_ast_create_unary(
2013-11-07 02:21:07 +08:00
ast->kind,
zend_ast_copy((&ast->u.child)[0]));
2013-11-07 02:21:07 +08:00
case 2:
2013-11-07 14:22:49 +08:00
return zend_ast_create_binary(
2013-11-07 02:21:07 +08:00
ast->kind,
zend_ast_copy((&ast->u.child)[0]),
zend_ast_copy((&ast->u.child)[1]));
2013-11-07 02:21:07 +08:00
case 3:
2013-11-07 14:22:49 +08:00
return zend_ast_create_ternary(
2013-11-07 02:21:07 +08:00
ast->kind,
zend_ast_copy((&ast->u.child)[0]),
zend_ast_copy((&ast->u.child)[1]),
zend_ast_copy((&ast->u.child)[2]));
}
}
2013-11-07 02:21:07 +08:00
return NULL;
}
2013-11-07 02:21:07 +08:00
ZEND_API void zend_ast_destroy(zend_ast *ast)
{
int i;
2013-11-07 02:21:07 +08:00
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]);
2013-11-07 02:21:07 +08:00
}
}
}
efree(ast);
}