op_array->arg_info = arg_infos;
}
+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_op_array *op_array = emalloc(sizeof(zend_op_array));
+ zend_string *lcname;
+ zend_op *opline;
+
+ // TODO.AST interactive (not just here - also bpc etc!)
+
+ init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC);
+
+ if (Z_TYPE(CG(current_namespace)) != IS_UNDEF) {
+ op_array->function_name = name = zend_concat_names(
+ Z_STRVAL(CG(current_namespace)), Z_STRLEN(CG(current_namespace)), name->val, name->len);
+ } else {
+ op_array->function_name = STR_COPY(name);
+ }
+
+ op_array->line_start = ast->lineno;
+ if (returns_ref) {
+ op_array->fn_flags |= ZEND_ACC_RETURN_REFERENCE;
+ }
+
+ lcname = STR_ALLOC(name->len, 0);
+ zend_str_tolower_copy(lcname->val, name->val, name->len);
+
+ if (CG(current_import_function)) {
+ zend_string *import_name = zend_hash_find_ptr(CG(current_import_function), lcname);
+ if (import_name) {
+ char *import_name_lc = zend_str_tolower_dup(import_name->val, import_name->len);
+
+ if (import_name->len != name->len
+ || memcmp(import_name_lc, lcname->val, name->len)
+ ) {
+ zend_error(E_COMPILE_ERROR, "Cannot declare function %s "
+ "because the name is already in use", name->val);
+ }
+
+ efree(import_name_lc);
+ }
+ }
+
+ opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+ opline->opcode = ZEND_DECLARE_FUNCTION;
+ opline->extended_value = ZEND_DECLARE_FUNCTION;
+ opline->op2_type = IS_CONST;
+ LITERAL_STR(opline->op2, lcname);
+
+ {
+ zval key;
+ build_runtime_defined_function_key(&key, lcname->val, lcname->len TSRMLS_CC);
+
+ opline->op1_type = IS_CONST;
+ opline->op1.constant = zend_add_literal(CG(active_op_array), &key TSRMLS_CC);
+
+ zend_hash_update_ptr(CG(function_table), Z_STR(key), op_array);
+ }
+
+ CG(active_op_array) = op_array;
+ zend_stack_push(&CG(context_stack), (void *) &CG(context));
+ zend_init_compiler_context(TSRMLS_C);
+
+ if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) {
+ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+
+ opline = emit_op(NULL, ZEND_EXT_NOP, NULL, NULL TSRMLS_CC);
+ opline->lineno = ast->lineno;
+ }
+
+ {
+ /* Push a separator to the switch stack */
+ zend_switch_entry switch_entry;
+
+ switch_entry.cond.op_type = IS_UNUSED;
+ switch_entry.default_case = 0;
+ switch_entry.control_var = 0;
+
+ zend_stack_push(&CG(switch_cond_stack), (void *) &switch_entry);
+ }
+
+ {
+ /* Push a separator to the foreach stack */
+ zend_op dummy_opline;
+
+ dummy_opline.result_type = IS_UNUSED;
+
+ zend_stack_push(&CG(foreach_copy_stack), (void *) &dummy_opline);
+ }
+
+ zend_compile_params(params_ast TSRMLS_CC);
+ zend_compile_stmt(stmt_ast TSRMLS_CC);
+
+ zend_do_extended_info(TSRMLS_C);
+ zend_do_return(NULL, 0 TSRMLS_CC);
+
+ pass_two(CG(active_op_array) TSRMLS_CC);
+ zend_release_labels(0 TSRMLS_CC);
+
+ // TODO.AST __autoload
+ // TODO.AST end line
+ // TODO.AST doc comment
+
+ CG(active_op_array) = orig_op_array;
+
+ /* 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_binary_op(znode *result, zend_ast *ast TSRMLS_DC) {
zend_ast *left_ast = ast->child[0];
zend_ast *right_ast = ast->child[1];
case ZEND_AST_TRY:
zend_compile_try(ast TSRMLS_CC);
break;
+ case ZEND_AST_FUNC_DECL:
+ zend_compile_func_decl(ast TSRMLS_CC);
+ break;
default:
{
znode result;
top_statement:
statement { AS($1); zend_verify_namespace(TSRMLS_C); }
- | function_declaration_statement { zend_verify_namespace(TSRMLS_C); zend_do_early_binding(TSRMLS_C); }
+ | function_declaration_statement { AS($1); zend_verify_namespace(TSRMLS_C); zend_do_early_binding(TSRMLS_C); }
| class_declaration_statement { zend_verify_namespace(TSRMLS_C); zend_do_early_binding(TSRMLS_C); }
| T_HALT_COMPILER '(' ')' ';' { zend_do_halt_compiler_register(TSRMLS_C); YYACCEPT; }
| T_NAMESPACE namespace_name ';' { zend_do_begin_namespace(&$2, 0 TSRMLS_CC); }
inner_statement:
statement { $$.u.ast = $1.u.ast; }
- | function_declaration_statement { AN($$); }
+ | function_declaration_statement { $$.u.ast = $1.u.ast; }
| class_declaration_statement { AN($$); }
| T_HALT_COMPILER '(' ')' ';'
{ zend_error_noreturn(E_COMPILE_ERROR, "__HALT_COMPILER() can only be used from the outermost scope"); }
;
function_declaration_statement:
- unticked_function_declaration_statement { DO_TICKS(); }
+ 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); }
;
class_declaration_statement:
| T_ELLIPSIS { $$.op_type = ZEND_PARAM_VARIADIC; }
;
-unticked_function_declaration_statement:
- function is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$3, 0, $2.op_type, NULL TSRMLS_CC); }
- '(' parameter_list ')' { zend_compile_params($6.u.ast TSRMLS_CC); zend_ast_destroy($6.u.ast); }
- '{' inner_statement_list '}' { AS($10); zend_do_end_function_declaration(&$1 TSRMLS_CC); }
-;
-
unticked_class_declaration_statement:
class_entry_type T_STRING extends_from
{ zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); }