summaryrefslogtreecommitdiff
path: root/Zend/zend_ast.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_ast.c')
-rw-r--r--Zend/zend_ast.c130
1 files changed, 130 insertions, 0 deletions
diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c
new file mode 100644
index 0000000000..21c08da510
--- /dev/null
+++ b/Zend/zend_ast.c
@@ -0,0 +1,130 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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 COPY_ZVAL_TO_OP(nr) \
+ 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; \
+ }
+
+void zend_ast_add(zval *result, intermediary_ast_function_type func, char op_count) {
+ zend_ast *ast = emalloc(sizeof(zend_ast) + op_count * sizeof(zval *));
+ ast->op_count = op_count;
+ ast->ops = (zval **)(ast + 1);
+ 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) */
+
+void zend_ast_add_unary(zval *result, unary_ast_func func, zval *op0 TSRMLS_DC) {
+ if (!op0 || !IS_CONSTANT_TYPE(Z_TYPE_P(op0))) {
+ func(result, op0 TSRMLS_CC);
+ if (op0) zval_dtor(op0);
+ return;
+ }
+
+ zend_ast_add(result, (intermediary_ast_function_type)func, 1);
+ COPY_ZVAL_TO_OP(0)
+}
+
+void zend_ast_add_binary(zval *result, binary_ast_func func, zval *op0, zval *op1 TSRMLS_DC) {
+ if ((!op0 || !IS_CONSTANT_TYPE(Z_TYPE_P(op0))) && (!op1 || !IS_CONSTANT_TYPE(Z_TYPE_P(op1)))) {
+ func(result, op0, op1 TSRMLS_CC);
+ if (op0) zval_dtor(op0);
+ if (op1) zval_dtor(op1);
+ return;
+ }
+
+ zend_ast_add(result, (intermediary_ast_function_type)func, 2);
+ COPY_ZVAL_TO_OP(0)
+ COPY_ZVAL_TO_OP(1)
+}
+
+void zend_ast_add_ternary(zval *result, ternary_ast_func func, zval *op0, zval *op1, zval *op2 TSRMLS_DC) {
+ if ((!op0 || !IS_CONSTANT_TYPE(Z_TYPE_P(op0))) && (!op1 || !IS_CONSTANT_TYPE(Z_TYPE_P(op1))) && (!op2 || !IS_CONSTANT_TYPE(Z_TYPE_P(op2)))) {
+ func(result, op0, op1, op2 TSRMLS_CC);
+ if (op0) zval_dtor(op0);
+ if (op1) zval_dtor(op1);
+ if (op2) zval_dtor(op2);
+ 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;
+ zval **ops = emalloc((sizeof(zval *) + sizeof(zval)) * ast->op_count);
+
+ for (i = ast->op_count; i--;) {
+ if (ast->ops[i] && IS_CONSTANT_TYPE(Z_TYPE_P(ast->ops[i]))) {
+ ops[i] = ((zval *)(ops + ast->op_count)) + i;
+ *ops[i] = *ast->ops[i];
+ zval_copy_ctor(ops[i]);
+ zval_update_constant_ex(&ops[i], (void *)1, NULL TSRMLS_CC);
+ } else {
+ ops[i] = ast->ops[i];
+ }
+ }
+
+ switch (ast->op_count) {
+ case 1:
+ ((unary_ast_func)ast->func)(result, ops[0] TSRMLS_CC);
+ break;
+ case 2:
+ ((binary_ast_func)ast->func)(result, ops[0], ops[1] TSRMLS_CC);
+ break;
+ case 3:
+ ((ternary_ast_func)ast->func)(result, ops[0], ops[1], ops[2] TSRMLS_CC);
+ break;
+ }
+
+ for (i = ast->op_count; i--;) {
+ if (ast->ops[i] != ops[i]) {
+ zval_dtor(ops[i]);
+ }
+ }
+
+ efree(ops);
+}
+
+void zend_ast_destroy(zend_ast *ast TSRMLS_DC) {
+ int i;
+
+ for (i = ast->op_count; i--;) {
+ if (ast->ops[i] && !Z_DELREF_P(ast->ops[i])) {
+ zval_dtor(ast->ops[i]);
+ efree(ast->ops[i]);
+ }
+ }
+
+ efree(ast);
+}