php-src/Zend/zend_ast.c

431 lines
12 KiB
C
Raw Normal View History

/*
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
2014-01-03 03:08:10 +00: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-06 18:21:07 +00:00
| Dmitry Stogov <dmitry@zend.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#include "zend_ast.h"
2013-11-06 18:21:07 +00:00
#include "zend_API.h"
#include "zend_operators.h"
2014-07-28 12:51:08 +00:00
static inline void *zend_ast_alloc(size_t size TSRMLS_DC) {
return zend_arena_alloc(&CG(ast_arena), size);
}
static inline void *zend_ast_realloc(void *old, size_t old_size, size_t new_size TSRMLS_DC) {
void *new = zend_ast_alloc(new_size TSRMLS_CC);
memcpy(new, old, old_size);
return new;
}
ZEND_API zend_ast *zend_ast_create_znode(znode *node) {
TSRMLS_FETCH();
2014-07-28 12:51:08 +00:00
zend_ast_znode *ast = zend_ast_alloc(sizeof(zend_ast_znode) TSRMLS_CC);
2014-06-07 11:06:53 +00:00
ast->kind = ZEND_AST_ZNODE;
ast->attr = 0;
ast->lineno = CG(zend_lineno);
2014-06-07 11:06:53 +00:00
ast->node = *node;
return (zend_ast *) ast;
}
2014-07-28 12:51:08 +00:00
ZEND_API zend_ast *zend_ast_create_zval_ex(zval *zv, zend_ast_attr attr) {
TSRMLS_FETCH();
2014-07-28 12:51:08 +00:00
zend_ast_zval *ast = zend_ast_alloc(sizeof(zend_ast_zval) TSRMLS_CC);
2014-06-28 16:03:26 +00:00
ast->kind = ZEND_AST_ZVAL;
2014-06-19 11:57:29 +00:00
ast->attr = attr;
ZVAL_COPY_VALUE(&ast->val, zv);
ast->val.u2.lineno = CG(zend_lineno);
2014-06-19 11:57:29 +00:00
return (zend_ast *) ast;
}
ZEND_API zend_ast *zend_ast_create_decl(
2014-07-28 12:51:08 +00:00
zend_ast_kind kind, zend_uint flags, zend_uint start_lineno, zend_string *doc_comment,
zend_string *name, zend_ast *child0, zend_ast *child1, zend_ast *child2
) {
TSRMLS_FETCH();
2014-07-28 12:51:08 +00:00
zend_ast_decl *ast = zend_ast_alloc(sizeof(zend_ast_decl) TSRMLS_CC);
ast->kind = kind;
2014-07-18 13:47:46 +00:00
ast->attr = 0;
ast->start_lineno = start_lineno;
2014-07-28 12:51:08 +00:00
ast->end_lineno = CG(zend_lineno);
2014-07-18 13:47:46 +00:00
ast->flags = flags;
2014-07-28 12:51:08 +00:00
ast->lex_pos = LANG_SCNG(yy_text);
2014-07-18 13:23:16 +00:00
ast->doc_comment = doc_comment;
ast->name = name;
ast->child[0] = child0;
ast->child[1] = child1;
ast->child[2] = child2;
return (zend_ast *) ast;
}
static zend_ast *zend_ast_create_from_va_list(
zend_uint children, zend_ast_kind kind, zend_ast_attr attr, va_list va
) {
2014-07-16 21:27:27 +00:00
TSRMLS_FETCH();
zend_uint i;
2014-07-12 15:10:10 +00:00
zend_ast *ast;
2014-07-28 12:51:08 +00:00
ast = zend_ast_alloc(sizeof(zend_ast) + (children - 1) * sizeof(zend_ast *) TSRMLS_CC);
ast->kind = kind;
ast->attr = attr;
ast->lineno = UINT_MAX;
for (i = 0; i < children; ++i) {
ast->child[i] = va_arg(va, zend_ast *);
if (ast->child[i] != NULL) {
zend_uint lineno = zend_ast_get_lineno(ast->child[i]);
if (lineno < ast->lineno) {
ast->lineno = lineno;
}
2014-07-12 15:10:10 +00:00
}
}
2014-07-16 21:27:27 +00:00
if (ast->lineno == UINT_MAX) {
2014-07-12 15:10:10 +00:00
ast->lineno = CG(zend_lineno);
2014-07-16 21:27:27 +00:00
}
2014-07-12 15:10:10 +00:00
return ast;
}
ZEND_API zend_ast *zend_ast_create_ex(
zend_uint children, zend_ast_kind kind, zend_ast_attr attr, ...
) {
va_list va;
zend_ast *ast;
va_start(va, attr);
ast = zend_ast_create_from_va_list(children, kind, attr, va);
va_end(va);
return ast;
}
ZEND_API zend_ast *zend_ast_create(
zend_uint children, zend_ast_kind kind, ...
) {
va_list va;
zend_ast *ast;
va_start(va, kind);
ast = zend_ast_create_from_va_list(children, kind, 0, va);
va_end(va);
return ast;
}
2014-07-28 12:51:08 +00:00
size_t zend_ast_list_size(zend_uint children) {
return sizeof(zend_ast_list) + sizeof(zend_ast *) * (children - 1);
}
ZEND_API zend_ast_list *zend_ast_create_list(zend_uint init_children, zend_ast_kind kind, ...) {
TSRMLS_FETCH();
2014-07-28 12:51:08 +00:00
zend_ast_list *list = zend_ast_alloc(zend_ast_list_size(4) TSRMLS_CC);
list->kind = kind;
list->attr = 0;
list->lineno = CG(zend_lineno);
list->children = 0;
{
va_list va;
zend_uint i;
va_start(va, kind);
for (i = 0; i < init_children; ++i) {
list = zend_ast_list_add(list, va_arg(va, zend_ast *));
}
va_end(va);
}
return list;
}
2014-06-06 20:35:21 +00:00
static inline zend_bool is_power_of_two(unsigned short n) {
return n == (n & -n);
}
ZEND_API zend_ast_list *zend_ast_list_add(zend_ast_list *list, zend_ast *op) {
if (list->children >= 4 && is_power_of_two(list->children)) {
TSRMLS_FETCH();
2014-07-28 12:51:08 +00:00
list = zend_ast_realloc(list,
zend_ast_list_size(list->children), zend_ast_list_size(list->children * 2) TSRMLS_CC);
}
list->child[list->children++] = op;
return list;
2013-11-06 18:21:07 +00:00
}
static void zend_ast_add_array_element(zval *result, zval *offset, zval *expr TSRMLS_DC)
{
switch (Z_TYPE_P(offset)) {
case IS_UNDEF:
zend_hash_next_index_insert(Z_ARRVAL_P(result), expr);
break;
case IS_STRING:
zend_symtable_update(Z_ARRVAL_P(result), Z_STR_P(offset), expr);
//???
zval_dtor(offset);
break;
case IS_NULL:
zend_symtable_update(Z_ARRVAL_P(result), STR_EMPTY_ALLOC(), expr);
break;
case IS_LONG:
zend_hash_index_update(Z_ARRVAL_P(result), Z_LVAL_P(offset), expr);
break;
case IS_FALSE:
zend_hash_index_update(Z_ARRVAL_P(result), 0, expr);
break;
case IS_TRUE:
zend_hash_index_update(Z_ARRVAL_P(result), 1, expr);
break;
case IS_DOUBLE:
zend_hash_index_update(Z_ARRVAL_P(result), zend_dval_to_lval(Z_DVAL_P(offset)), expr);
break;
default:
zend_error(E_ERROR, "Illegal offset type");
break;
}
}
ZEND_API void zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *scope TSRMLS_DC)
2013-11-06 18:21:07 +00:00
{
zval op1, op2;
2013-11-06 18:21:07 +00:00
switch (ast->kind) {
case ZEND_AST_BINARY_OP:
{
binary_op_type op = get_binary_op(ast->attr);
2014-06-06 20:35:21 +00:00
zend_ast_evaluate(&op1, ast->child[0], scope TSRMLS_CC);
zend_ast_evaluate(&op2, ast->child[1], scope TSRMLS_CC);
op(result, &op1, &op2 TSRMLS_CC);
2013-11-06 18:21:07 +00:00
zval_dtor(&op1);
zval_dtor(&op2);
break;
}
2014-06-26 20:02:54 +00:00
case ZEND_AST_GREATER:
case ZEND_AST_GREATER_EQUAL:
{
/* op1 > op2 is the same as op2 < op1 */
binary_op_type op = ast->kind == ZEND_AST_GREATER
? is_smaller_function : is_smaller_or_equal_function;
zend_ast_evaluate(&op1, ast->child[0], scope TSRMLS_CC);
zend_ast_evaluate(&op2, ast->child[1], scope TSRMLS_CC);
op(result, &op2, &op1 TSRMLS_CC);
zval_dtor(&op1);
zval_dtor(&op2);
break;
}
case ZEND_AST_UNARY_OP:
{
unary_op_type op = get_unary_op(ast->attr);
2014-06-06 20:35:21 +00:00
zend_ast_evaluate(&op1, ast->child[0], scope TSRMLS_CC);
op(result, &op1 TSRMLS_CC);
2013-11-06 18:21:07 +00:00
zval_dtor(&op1);
break;
}
2014-06-28 16:03:26 +00:00
case ZEND_AST_ZVAL:
2014-06-06 20:35:21 +00:00
ZVAL_DUP(result, zend_ast_get_zval(ast));
2014-04-24 20:56:15 +00:00
if (Z_OPT_CONSTANT_P(result)) {
Merge mainstream 'master' branch into refactoring During merge I had to revert: Nikita's patch for php_splice() (it probably needs to be applyed again) Bob Weinand's patches related to constant expression handling (we need to review them carefully) I also reverted all our attempts to support sapi/phpdbg (we didn't test it anyway) Conflicts: Zend/zend.h Zend/zend_API.c Zend/zend_ast.c Zend/zend_compile.c Zend/zend_compile.h Zend/zend_constants.c Zend/zend_exceptions.c Zend/zend_execute.c Zend/zend_execute.h Zend/zend_execute_API.c Zend/zend_hash.c Zend/zend_highlight.c Zend/zend_language_parser.y Zend/zend_language_scanner.c Zend/zend_language_scanner_defs.h Zend/zend_variables.c Zend/zend_vm_def.h Zend/zend_vm_execute.h ext/date/php_date.c ext/dom/documenttype.c ext/hash/hash.c ext/iconv/iconv.c ext/mbstring/tests/zend_multibyte-10.phpt ext/mbstring/tests/zend_multibyte-11.phpt ext/mbstring/tests/zend_multibyte-12.phpt ext/mysql/php_mysql.c ext/mysqli/mysqli.c ext/mysqlnd/mysqlnd_reverse_api.c ext/mysqlnd/php_mysqlnd.c ext/opcache/ZendAccelerator.c ext/opcache/zend_accelerator_util_funcs.c ext/opcache/zend_persist.c ext/opcache/zend_persist_calc.c ext/pcre/php_pcre.c ext/pdo/pdo_dbh.c ext/pdo/pdo_stmt.c ext/pdo_pgsql/pgsql_driver.c ext/pgsql/pgsql.c ext/reflection/php_reflection.c ext/session/session.c ext/spl/spl_array.c ext/spl/spl_observer.c ext/standard/array.c ext/standard/basic_functions.c ext/standard/html.c ext/standard/mail.c ext/standard/php_array.h ext/standard/proc_open.c ext/standard/streamsfuncs.c ext/standard/user_filters.c ext/standard/var_unserializer.c ext/standard/var_unserializer.re main/php_variables.c sapi/phpdbg/phpdbg.c sapi/phpdbg/phpdbg_bp.c sapi/phpdbg/phpdbg_frame.c sapi/phpdbg/phpdbg_help.c sapi/phpdbg/phpdbg_list.c sapi/phpdbg/phpdbg_print.c sapi/phpdbg/phpdbg_prompt.c
2014-04-25 20:32:51 +00:00
zval_update_constant_ex(result, 1, scope TSRMLS_CC);
2013-11-06 18:21:07 +00:00
}
break;
case ZEND_AST_AND:
2014-06-06 20:35:21 +00:00
zend_ast_evaluate(&op1, ast->child[0], scope TSRMLS_CC);
if (zend_is_true(&op1 TSRMLS_CC)) {
2014-06-06 20:35:21 +00:00
zend_ast_evaluate(&op2, ast->child[1], scope TSRMLS_CC);
ZVAL_BOOL(result, zend_is_true(&op2 TSRMLS_CC));
2013-11-06 18:21:07 +00:00
zval_dtor(&op2);
} else {
ZVAL_BOOL(result, 0);
}
zval_dtor(&op1);
break;
case ZEND_AST_OR:
2014-06-06 20:35:21 +00:00
zend_ast_evaluate(&op1, ast->child[0], scope TSRMLS_CC);
if (zend_is_true(&op1 TSRMLS_CC)) {
2013-11-06 18:21:07 +00:00
ZVAL_BOOL(result, 1);
} else {
2014-06-06 20:35:21 +00:00
zend_ast_evaluate(&op2, ast->child[1], scope TSRMLS_CC);
ZVAL_BOOL(result, zend_is_true(&op2 TSRMLS_CC));
2013-11-06 18:21:07 +00:00
zval_dtor(&op2);
}
zval_dtor(&op1);
break;
case ZEND_AST_CONDITIONAL:
2014-06-06 20:35:21 +00:00
zend_ast_evaluate(&op1, ast->child[0], scope TSRMLS_CC);
if (zend_is_true(&op1 TSRMLS_CC)) {
2014-06-06 20:35:21 +00:00
if (!ast->child[1]) {
2013-11-06 18:21:07 +00:00
*result = op1;
} else {
2014-06-06 20:35:21 +00:00
zend_ast_evaluate(result, ast->child[1], scope TSRMLS_CC);
2013-11-06 18:21:07 +00:00
zval_dtor(&op1);
}
} else {
2014-06-06 20:35:21 +00:00
zend_ast_evaluate(result, ast->child[2], scope TSRMLS_CC);
2013-11-06 18:21:07 +00:00
zval_dtor(&op1);
}
break;
2014-06-26 10:43:20 +00:00
case ZEND_AST_UNARY_PLUS:
2013-11-06 18:21:07 +00:00
ZVAL_LONG(&op1, 0);
2014-06-06 20:35:21 +00:00
zend_ast_evaluate(&op2, ast->child[0], scope TSRMLS_CC);
2013-11-06 18:21:07 +00:00
add_function(result, &op1, &op2 TSRMLS_CC);
zval_dtor(&op2);
break;
2014-06-26 10:43:20 +00:00
case ZEND_AST_UNARY_MINUS:
2013-11-06 18:21:07 +00:00
ZVAL_LONG(&op1, 0);
2014-06-06 20:35:21 +00:00
zend_ast_evaluate(&op2, ast->child[0], scope TSRMLS_CC);
2013-11-06 18:21:07 +00:00
sub_function(result, &op1, &op2 TSRMLS_CC);
zval_dtor(&op2);
break;
2014-06-26 11:16:31 +00:00
case ZEND_AST_ARRAY:
array_init(result);
{
2014-06-26 11:16:31 +00:00
zend_uint i;
zend_ast_list *list = zend_ast_get_list(ast);
for (i = 0; i < list->children; i++) {
zend_ast *elem = list->child[i];
2014-06-26 11:16:31 +00:00
if (elem->child[1]) {
zend_ast_evaluate(&op1, elem->child[1], scope TSRMLS_CC);
} else {
ZVAL_UNDEF(&op1);
}
2014-06-26 11:16:31 +00:00
zend_ast_evaluate(&op2, elem->child[0], scope TSRMLS_CC);
zend_ast_add_array_element(result, &op1, &op2 TSRMLS_CC);
}
}
break;
//???
#if 0
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;
#endif
2013-11-06 18:21:07 +00:00
default:
zend_error(E_ERROR, "Unsupported constant expression");
}
2013-11-06 18:21:07 +00:00
}
2013-11-06 18:21:07 +00:00
ZEND_API zend_ast *zend_ast_copy(zend_ast *ast)
{
if (ast == NULL) {
return NULL;
2014-06-28 16:03:26 +00:00
} else if (ast->kind == ZEND_AST_ZVAL) {
zend_ast_zval *new = emalloc(sizeof(zend_ast_zval));
new->kind = ZEND_AST_ZVAL;
new->attr = ast->attr;
ZVAL_DUP(&new->val, zend_ast_get_zval(ast));
return (zend_ast *) new;
} else if (zend_ast_is_list(ast)) {
zend_ast_list *list = zend_ast_get_list(ast);
zend_ast_list *new = emalloc(sizeof(zend_ast_list)
+ sizeof(zend_ast *) * (list->children - 1));
zend_uint i;
new->kind = list->kind;
new->attr = list->attr;
new->children = list->children;
for (i = 0; i < list->children; i++) {
new->child[i] = zend_ast_copy(list->child[i]);
}
return (zend_ast *) new;
2014-07-21 16:02:31 +00:00
} else {
zend_uint i, children = zend_ast_get_num_children(ast);
zend_ast *new = emalloc(sizeof(zend_ast) + sizeof(zend_ast *) * (children - 1));
new->kind = ast->kind;
2014-06-28 16:03:26 +00:00
new->attr = ast->attr;
for (i = 0; i < children; i++) {
2014-06-06 20:35:21 +00:00
new->child[i] = zend_ast_copy(ast->child[i]);
}
return new;
}
}
static void zend_ast_destroy_ex(zend_ast *ast, zend_bool free) {
if (!ast) {
return;
}
switch (ast->kind) {
case ZEND_AST_ZVAL:
zval_ptr_dtor(zend_ast_get_zval(ast));
break;
case ZEND_AST_ZNODE:
break;
case ZEND_AST_FUNC_DECL:
case ZEND_AST_CLOSURE:
case ZEND_AST_METHOD:
2014-07-21 14:34:45 +00:00
case ZEND_AST_CLASS:
{
zend_ast_decl *decl = (zend_ast_decl *) ast;
STR_RELEASE(decl->name);
if (decl->doc_comment) {
STR_RELEASE(decl->doc_comment);
2014-07-18 13:23:16 +00:00
}
zend_ast_destroy_ex(decl->child[0], free);
zend_ast_destroy_ex(decl->child[1], free);
zend_ast_destroy_ex(decl->child[2], free);
break;
}
default:
if (zend_ast_is_list(ast)) {
zend_ast_list *list = zend_ast_get_list(ast);
zend_uint i;
for (i = 0; i < list->children; i++) {
zend_ast_destroy_ex(list->child[i], free);
}
} else {
zend_uint i, children = zend_ast_get_num_children(ast);
for (i = 0; i < children; i++) {
zend_ast_destroy_ex(ast->child[i], free);
}
2013-11-06 18:21:07 +00:00
}
}
if (free) {
efree(ast);
}
}
ZEND_API void zend_ast_destroy(zend_ast *ast) {
zend_ast_destroy_ex(ast, 0);
}
ZEND_API void zend_ast_destroy_and_free(zend_ast *ast) {
zend_ast_destroy_ex(ast, 1);
}
ZEND_API void zend_ast_apply(zend_ast *ast, zend_ast_apply_func fn TSRMLS_DC) {
if (zend_ast_is_list(ast)) {
zend_ast_list *list = zend_ast_get_list(ast);
zend_uint i;
for (i = 0; i < list->children; ++i) {
fn(&list->child[i] TSRMLS_CC);
}
} else {
zend_uint i, children = zend_ast_get_num_children(ast);
for (i = 0; i < children; ++i) {
fn(&ast->child[i] TSRMLS_CC);
}
}
}