2013-10-31 07:57:12 +00:00
|
|
|
/*
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
| Zend Engine |
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
| Copyright (c) 1998-2013 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> |
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* $Id$ */
|
|
|
|
|
|
|
|
#include "zend_ast.h"
|
|
|
|
#include "zend_execute.h"
|
|
|
|
|
|
|
|
#define OP_IS_CONST_THEN(op, do_code) \
|
2013-10-31 17:21:37 +00:00
|
|
|
switch (op?Z_TYPE_P(op) & IS_CONSTANT_TYPE_MASK:-1) { \
|
|
|
|
case -1: \
|
2013-10-31 07:57:12 +00:00
|
|
|
case IS_CONSTANT: \
|
|
|
|
case IS_CONSTANT_ARRAY: \
|
|
|
|
case IS_CONSTANT_AST: { \
|
|
|
|
do_code \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define OP_IS_NOT_CONST_THEN(op, do_code) \
|
2013-10-31 17:21:37 +00:00
|
|
|
if (op) { \
|
|
|
|
switch (Z_TYPE_P(op) & IS_CONSTANT_TYPE_MASK) { \
|
|
|
|
case IS_CONSTANT: \
|
|
|
|
case IS_CONSTANT_ARRAY: \
|
|
|
|
case IS_CONSTANT_AST: \
|
|
|
|
break; \
|
2013-10-31 07:57:12 +00:00
|
|
|
\
|
2013-10-31 17:21:37 +00:00
|
|
|
default: { \
|
|
|
|
do_code \
|
|
|
|
} \
|
2013-10-31 07:57:12 +00:00
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define COPY_ZVAL_TO_OP(nr) \
|
2013-10-31 17:21:37 +00:00
|
|
|
if (op##nr) { \
|
|
|
|
Z_AST_P(result)->ops[nr] = emalloc(sizeof(zval)); \
|
|
|
|
*Z_AST_P(result)->ops[nr] = *op##nr; \
|
|
|
|
} else { \
|
|
|
|
Z_AST_P(result)->ops[nr] = NULL; \
|
|
|
|
}
|
2013-10-31 07:57:12 +00:00
|
|
|
|
|
|
|
void zend_ast_add(zval *result, intermediary_ast_function_type func, char op_count) {
|
|
|
|
zend_ast *ast = emalloc(sizeof(zend_ast));
|
|
|
|
ast->op_count = op_count;
|
|
|
|
ast->ops = emalloc(op_count * sizeof(zval *));
|
|
|
|
ast->refcount = 1;
|
|
|
|
ast->func = func;
|
|
|
|
Z_AST_P(result) = ast;
|
|
|
|
Z_TYPE_P(result) = IS_CONSTANT_AST;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Do operations on constant operators at compile time (AST building time) */
|
|
|
|
|
2013-10-31 17:21:37 +00:00
|
|
|
void zend_ast_add_unary(zval *result, unary_ast_func func, zval *op0 TSRMLS_DC) {
|
2013-10-31 07:57:12 +00:00
|
|
|
OP_IS_NOT_CONST_THEN(op0,
|
2013-10-31 17:21:37 +00:00
|
|
|
func(result, op0 TSRMLS_CC);
|
|
|
|
zval_dtor(op0);
|
2013-10-31 07:57:12 +00:00
|
|
|
return;
|
|
|
|
)
|
|
|
|
|
|
|
|
zend_ast_add(result, (intermediary_ast_function_type)func, 1);
|
|
|
|
COPY_ZVAL_TO_OP(0)
|
|
|
|
}
|
|
|
|
|
2013-10-31 17:21:37 +00:00
|
|
|
void zend_ast_add_binary(zval *result, binary_ast_func func, zval *op0, zval *op1 TSRMLS_DC) {
|
2013-10-31 07:57:12 +00:00
|
|
|
OP_IS_NOT_CONST_THEN(op0, OP_IS_NOT_CONST_THEN(op1,
|
2013-10-31 17:21:37 +00:00
|
|
|
func(result, op0, op1 TSRMLS_CC);
|
|
|
|
zval_dtor(op0);
|
|
|
|
zval_dtor(op1);
|
2013-10-31 07:57:12 +00:00
|
|
|
return;
|
|
|
|
))
|
|
|
|
|
|
|
|
zend_ast_add(result, (intermediary_ast_function_type)func, 2);
|
|
|
|
COPY_ZVAL_TO_OP(0)
|
|
|
|
COPY_ZVAL_TO_OP(1)
|
|
|
|
}
|
|
|
|
|
2013-10-31 17:21:37 +00:00
|
|
|
void zend_ast_add_ternary(zval *result, ternary_ast_func func, zval *op0, zval *op1, zval *op2 TSRMLS_DC) {
|
2013-10-31 07:57:12 +00:00
|
|
|
OP_IS_NOT_CONST_THEN(op0, OP_IS_NOT_CONST_THEN(op1, OP_IS_NOT_CONST_THEN(op2,
|
2013-10-31 17:21:37 +00:00
|
|
|
func(result, op0, op1, op2 TSRMLS_CC);
|
|
|
|
zval_dtor(op0);
|
|
|
|
zval_dtor(op1);
|
|
|
|
zval_dtor(op2);
|
2013-10-31 07:57:12 +00:00
|
|
|
return;
|
|
|
|
)))
|
|
|
|
|
|
|
|
zend_ast_add(result, (intermediary_ast_function_type)func, 3);
|
|
|
|
COPY_ZVAL_TO_OP(0)
|
|
|
|
COPY_ZVAL_TO_OP(1)
|
|
|
|
COPY_ZVAL_TO_OP(2)
|
|
|
|
}
|
|
|
|
|
|
|
|
void zend_ast_evaluate(zval *result, zend_ast *ast TSRMLS_DC) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = ast->op_count; i--;) {
|
2013-10-31 17:21:37 +00:00
|
|
|
if (ast->ops[i]) {
|
|
|
|
OP_IS_CONST_THEN(ast->ops[i],
|
|
|
|
zval_update_constant_ex(&ast->ops[i], (void *)1, NULL TSRMLS_CC);
|
|
|
|
)
|
|
|
|
}
|
2013-10-31 07:57:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (ast->op_count) {
|
|
|
|
case 1:
|
2013-10-31 17:21:37 +00:00
|
|
|
((unary_ast_func)ast->func)(result, ast->ops[0] TSRMLS_CC);
|
2013-10-31 07:57:12 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
2013-10-31 17:21:37 +00:00
|
|
|
((binary_ast_func)ast->func)(result, ast->ops[0], ast->ops[1] TSRMLS_CC);
|
2013-10-31 07:57:12 +00:00
|
|
|
break;
|
|
|
|
case 3:
|
2013-10-31 17:21:37 +00:00
|
|
|
((ternary_ast_func)ast->func)(result, ast->ops[0], ast->ops[1], ast->ops[2] TSRMLS_CC);
|
2013-10-31 07:57:12 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void zend_ast_destroy(zend_ast *ast TSRMLS_DC) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = ast->op_count; i--;) {
|
2013-10-31 17:21:37 +00:00
|
|
|
if (ast->ops[i] && !Z_DELREF_P(ast->ops[i])) {
|
2013-10-31 07:57:12 +00:00
|
|
|
zval_dtor(ast->ops[i]);
|
|
|
|
efree(ast->ops[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
efree(ast->ops);
|
|
|
|
efree(ast);
|
|
|
|
}
|