return (zend_ast *) ast;
}
+ZEND_API zend_ast *zend_ast_create_func_decl(
+ zend_ast_kind kind, zend_bool returns_ref, zend_uint start_lineno, zend_uint end_lineno,
+ zend_string *name, zend_ast *params, zend_ast *uses, zend_ast *stmt
+) {
+ zend_ast_func_decl *ast = emalloc(sizeof(zend_ast_func_decl));
+
+ ast->kind = kind;
+ ast->returns_ref = returns_ref;
+ ast->start_lineno = start_lineno;
+ ast->end_lineno = end_lineno;
+ ast->name = name;
+ ast->params = params;
+ ast->uses = uses;
+ ast->stmt = stmt;
+
+ 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
) {
ZEND_API void zend_ast_destroy(zend_ast *ast)
{
- int i;
+ if (!ast) {
+ return;
+ }
- if (ast->kind == ZEND_AST_ZVAL) {
- zval_ptr_dtor(zend_ast_get_zval(ast));
- } else if (ast->kind != ZEND_AST_ZNODE) {
- for (i = 0; i < ast->children; i++) {
- if (ast->child[i]) {
+ 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:
+ {
+ zend_ast_func_decl *fn = (zend_ast_func_decl *) ast;
+ STR_RELEASE(fn->name);
+ zend_ast_destroy(fn->params);
+ zend_ast_destroy(fn->uses);
+ zend_ast_destroy(fn->stmt);
+ break;
+ }
+ default:
+ {
+ zend_uint i;
+ for (i = 0; i < ast->children; i++) {
zend_ast_destroy(ast->child[i]);
}
}
}
+
efree(ast);
}
ZEND_AST_TYPE,
ZEND_AST_FUNC_DECL,
-
ZEND_AST_CLOSURE,
ZEND_AST_CLOSURE_USES,
};
zval val;
} zend_ast_zval;
+/* Using a separate structure as it needs a bunch of extra information. */
+typedef struct _zend_ast_func_decl {
+ zend_ast_kind kind;
+ zend_bool returns_ref;
+ zend_uint start_lineno;
+ zend_uint end_lineno;
+ zend_string *name;
+ zend_ast *params;
+ zend_ast *uses;
+ zend_ast *stmt;
+} zend_ast_func_decl;
+
static inline zval *zend_ast_get_zval(zend_ast *ast) {
return &((zend_ast_zval *) ast)->val;
}
ZEND_API zend_ast *zend_ast_create(
zend_uint children, zend_ast_kind kind, ...);
+ZEND_API zend_ast *zend_ast_create_func_decl(
+ zend_ast_kind kind, zend_bool by_ref, zend_uint start_lineno, zend_uint end_lineno,
+ zend_string *name, zend_ast *params, zend_ast *uses, zend_ast *stmt
+);
+
ZEND_API zend_ast *zend_ast_create_dynamic(zend_ast_kind kind);
ZEND_API zend_ast *zend_ast_dynamic_add(zend_ast *ast, zend_ast *op);
ZEND_API void zend_ast_dynamic_shrink(zend_ast **ast);
}
}
-static void zend_begin_func_decl(
- znode *result, zend_string *name, zend_uint start_lineno, zend_bool returns_ref TSRMLS_DC
-) {
+void zend_compile_func_decl(znode *result, zend_ast *ast TSRMLS_DC) {
+ zend_ast_func_decl *fn = (zend_ast_func_decl *) ast;
+ zend_op_array *orig_op_array = CG(active_op_array);
zend_op_array *op_array = emalloc(sizeof(zend_op_array));
- zend_string *lcname;
+ zend_string *name = fn->name, *lcname;
zend_op *opline;
- zend_bool is_closure = result != NULL;
+ zend_bool is_closure = ast->kind == ZEND_AST_CLOSURE;
// TODO.AST interactive (not just here - also bpc etc!)
op_array->function_name = STR_COPY(name);
}
- op_array->line_start = start_lineno;
- if (returns_ref) {
+ op_array->line_start = fn->start_lineno;
+ op_array->line_end = fn->end_lineno;
+ if (fn->returns_ref) {
op_array->fn_flags |= ZEND_ACC_RETURN_REFERENCE;
}
if (is_closure) {
if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) {
zend_op *opline_ext = emit_op(NULL, ZEND_EXT_NOP, NULL, NULL TSRMLS_CC);
- opline_ext->lineno = start_lineno;
+ opline_ext->lineno = fn->start_lineno;
}
{
zend_stack_push(&CG(foreach_copy_stack), (void *) &dummy_opline);
}
-}
-static void zend_end_func_decl(TSRMLS_D) {
+ zend_compile_params(fn->params TSRMLS_CC);
+ zend_compile_closure_uses(fn->uses TSRMLS_CC);
+ zend_compile_stmt(fn->stmt TSRMLS_CC);
+
zend_do_extended_info(TSRMLS_C);
zend_do_return(NULL, 0 TSRMLS_CC);
zend_release_labels(0 TSRMLS_CC);
// TODO.AST __autoload
- // TODO.AST end line
// TODO.AST doc comment
/* Pop the switch and foreach separators */
zend_stack_del_top(&CG(switch_cond_stack));
zend_stack_del_top(&CG(foreach_copy_stack));
-}
-void zend_compile_func_decl(zend_ast *ast TSRMLS_DC) {
- zend_ast *name_ast = ast->child[0];
- zend_ast *params_ast = ast->child[1];
- zend_ast *stmt_ast = ast->child[2];
- zend_bool returns_ref = ast->attr;
- zend_string *name = Z_STR_P(zend_ast_get_zval(name_ast));
-
- zend_op_array *orig_op_array = CG(active_op_array);
- zend_begin_func_decl(NULL, name, ast->lineno, returns_ref TSRMLS_CC);
-
- zend_compile_params(params_ast TSRMLS_CC);
- zend_compile_stmt(stmt_ast TSRMLS_CC);
-
- zend_end_func_decl(TSRMLS_C);
- CG(active_op_array) = orig_op_array;
-}
-
-void zend_compile_closure(znode *result, zend_ast *ast TSRMLS_DC) {
- zend_ast *params_ast = ast->child[0];
- zend_ast *uses_ast = ast->child[1];
- zend_ast *stmt_ast = ast->child[2];
- zend_bool returns_ref = ast->attr;
- zend_string *name = STR_INIT("{closure}", sizeof("{closure}") - 1, 0);
-
- zend_op_array *orig_op_array = CG(active_op_array);
- zend_begin_func_decl(result, name, ast->lineno, returns_ref TSRMLS_CC);
-
- zend_compile_closure_uses(uses_ast TSRMLS_CC);
- zend_compile_params(params_ast TSRMLS_CC);
- zend_compile_stmt(stmt_ast TSRMLS_CC);
-
- zend_end_func_decl(TSRMLS_C);
CG(active_op_array) = orig_op_array;
-
- STR_RELEASE(name);
}
void zend_compile_binary_op(znode *result, zend_ast *ast TSRMLS_DC) {
zend_compile_try(ast TSRMLS_CC);
break;
case ZEND_AST_FUNC_DECL:
- zend_compile_func_decl(ast TSRMLS_CC);
+ zend_compile_func_decl(NULL, ast TSRMLS_CC);
break;
default:
{
zend_compile_magic_const(result, ast TSRMLS_CC);
return;
case ZEND_AST_CLOSURE:
- zend_compile_closure(result, ast TSRMLS_CC);
+ zend_compile_func_decl(result, ast TSRMLS_CC);
return;
default:
ZEND_ASSERT(0 /* not supported */);
function_declaration_statement:
function is_reference T_STRING '(' parameter_list ')' '{' inner_statement_list '}'
- { $$.u.ast = zend_ast_create_ex(3, ZEND_AST_FUNC_DECL,
- $2.op_type, AST_ZVAL(&$3), $5.u.ast, $8.u.ast); }
+ { $$.u.ast = zend_ast_create_func_decl(ZEND_AST_FUNC_DECL, $2.op_type,
+ $1.u.op.opline_num, CG(zend_lineno), Z_STR($3.u.constant),
+ $5.u.ast, NULL, $8.u.ast); }
;
class_declaration_statement:
| T_YIELD expr T_DOUBLE_ARROW expr
{ $$.u.ast = zend_ast_create_binary(ZEND_YIELD, $4.u.ast, $2.u.ast); }
| function is_reference '(' parameter_list ')' lexical_vars '{' inner_statement_list '}'
- { $$.u.ast = zend_ast_create_ex(3, ZEND_AST_CLOSURE,
- $2.op_type, $4.u.ast, $6.u.ast, $8.u.ast); }
+ { $$.u.ast = zend_ast_create_func_decl(ZEND_AST_CLOSURE, $2.op_type,
+ $1.u.op.opline_num, CG(zend_lineno),
+ STR_INIT("{closure}", sizeof("{closure}") - 1, 0),
+ $4.u.ast, $6.u.ast, $8.u.ast); }
| T_STATIC function is_reference { zend_do_begin_lambda_function_declaration(&$$, &$2, $3.op_type, 1 TSRMLS_CC); }
'(' parameter_list ')' { zend_compile_params($6.u.ast TSRMLS_CC); zend_ast_destroy($6.u.ast); } lexical_vars { zend_compile_closure_uses($9.u.ast TSRMLS_CC); if ($9.u.ast) zend_ast_destroy($9.u.ast); }
'{' inner_statement_list '}' { AS($12); zend_do_end_function_declaration(&$2 TSRMLS_CC); $$.u.ast = AST_ZNODE(&$4); }