Implement declare()

This commit is contained in:
Nikita Popov 2014-07-22 16:11:19 +02:00
parent 2653b8b5dc
commit b9be66ebf2
5 changed files with 100 additions and 20 deletions

View file

@ -9,4 +9,4 @@ abstract class bar {
class foo extends bar {
}
--EXPECTF--
Fatal error: Class foo contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (bar::bar) in %sbug43323.php on line 7
Fatal error: Class foo contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (bar::bar) in %sbug43323.php on line 6

View file

@ -94,6 +94,7 @@ enum _zend_ast_kind {
ZEND_AST_TRY,
ZEND_AST_CATCH_LIST,
ZEND_AST_CATCH,
ZEND_AST_DECLARE,
ZEND_AST_PARAM_LIST,
ZEND_AST_PARAM,

View file

@ -5235,6 +5235,93 @@ void zend_compile_try(zend_ast *ast TSRMLS_DC) {
efree(jmp_opnums);
}
void zend_compile_declare(zend_ast *ast TSRMLS_DC) {
zend_ast *declares_ast = ast->child[0];
zend_ast *stmt_ast = ast->child[1];
zend_uint i;
zend_stack_push(&CG(declare_stack), &CG(declarables));
for (i = 0; i < declares_ast->children; ++i) {
zend_ast *declare_ast = declares_ast->child[i];
zend_ast *name_ast = declare_ast->child[0];
zend_ast *value_ast = declare_ast->child[1];
zend_string *name = Z_STR_P(zend_ast_get_zval(name_ast));
zval value_zv;
_tmp_compile_const_expr(&value_zv, value_ast TSRMLS_CC);
if (!zend_binary_strcasecmp(name->val, name->len, "ticks", sizeof("ticks") - 1)) {
convert_to_long(&value_zv);
ZVAL_COPY_VALUE(&CG(declarables).ticks, &value_zv);
} else if (!zend_binary_strcasecmp(name->val, name->len, "encoding", sizeof("encoding") - 1)) {
if (Z_TYPE(value_zv) == IS_CONSTANT) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use constants as encoding");
}
/*
* Check that the pragma comes before any opcodes. If the compilation
* got as far as this, the previous portion of the script must have been
* parseable according to the .ini script_encoding setting. We still
* want to tell them to put declare() at the top.
*/
{
zend_uint num = CG(active_op_array)->last;
/* ignore ZEND_EXT_STMT and ZEND_TICKS */
while (num > 0 &&
(CG(active_op_array)->opcodes[num-1].opcode == ZEND_EXT_STMT ||
CG(active_op_array)->opcodes[num-1].opcode == ZEND_TICKS)) {
--num;
}
if (num > 0) {
zend_error_noreturn(E_COMPILE_ERROR, "Encoding declaration pragma must be "
"the very first statement in the script");
}
}
if (CG(multibyte)) {
const zend_encoding *new_encoding, *old_encoding;
zend_encoding_filter old_input_filter;
CG(encoding_declared) = 1;
convert_to_string(&value_zv);
new_encoding = zend_multibyte_fetch_encoding(Z_STRVAL(value_zv) TSRMLS_CC);
if (!new_encoding) {
zend_error(E_COMPILE_WARNING, "Unsupported encoding [%s]", Z_STRVAL(value_zv));
} else {
old_input_filter = LANG_SCNG(input_filter);
old_encoding = LANG_SCNG(script_encoding);
zend_multibyte_set_filter(new_encoding TSRMLS_CC);
/* need to re-scan if input filter changed */
if (old_input_filter != LANG_SCNG(input_filter) ||
(old_input_filter && new_encoding != old_encoding)) {
zend_multibyte_yyinput_again(old_input_filter, old_encoding TSRMLS_CC);
}
}
} else {
zend_error(E_COMPILE_WARNING, "declare(encoding=...) ignored because "
"Zend multibyte feature is turned off by settings");
}
zval_dtor(&value_zv);
} else {
zend_error(E_COMPILE_WARNING, "Unsupported declare '%s'", name->val);
zval_dtor(&value_zv);
}
}
if (stmt_ast) {
zend_declarables *declarables = zend_stack_top(&CG(declare_stack));
zend_compile_stmt(stmt_ast TSRMLS_CC);
CG(declarables) = *declarables;
}
}
void zend_compile_stmt_list(zend_ast *ast TSRMLS_DC) {
zend_uint i;
for (i = 0; i < ast->children; ++i) {
@ -7365,6 +7452,9 @@ void zend_compile_stmt(zend_ast *ast TSRMLS_DC) {
case ZEND_AST_TRY:
zend_compile_try(ast TSRMLS_CC);
break;
case ZEND_AST_DECLARE:
zend_compile_declare(ast TSRMLS_CC);
break;
case ZEND_AST_FUNC_DECL:
case ZEND_AST_METHOD:
zend_compile_func_decl(NULL, ast TSRMLS_CC);

View file

@ -349,7 +349,8 @@ unticked_statement:
foreach_statement
{ $$.u.ast = zend_ast_create(4, ZEND_AST_FOREACH,
$3.u.ast, $7.u.ast, $5.u.ast, $9.u.ast); }
| T_DECLARE { $1.u.op.opline_num = get_next_op_number(CG(active_op_array)); zend_do_declare_begin(TSRMLS_C); } '(' declare_list ')' declare_statement { zend_do_declare_end(&$1 TSRMLS_CC); AN($$); }
| T_DECLARE '(' const_list ')' declare_statement
{ $$.u.ast = zend_ast_create_binary(ZEND_AST_DECLARE, $3.u.ast, $5.u.ast); }
| ';' /* empty statement */ { $$.u.ast = NULL; }
| T_TRY '{' inner_statement_list '}' catch_list finally_statement
{ $$.u.ast = zend_ast_create_ternary(ZEND_AST_TRY, $3.u.ast, $5.u.ast, $6.u.ast); }
@ -457,17 +458,10 @@ foreach_statement:
declare_statement:
statement { AS($1); }
| ':' inner_statement_list T_ENDDECLARE ';' { AS($2); }
statement { $$.u.ast = $1.u.ast; }
| ':' inner_statement_list T_ENDDECLARE ';' { $$.u.ast = $2.u.ast; }
;
declare_list:
T_STRING '=' static_scalar { zend_do_declare_stmt(&$1, &$3 TSRMLS_CC); }
| declare_list ',' T_STRING '=' static_scalar { zend_do_declare_stmt(&$3, &$5 TSRMLS_CC); }
;
switch_case_list:
'{' case_list '}' { $$.u.ast = $2.u.ast; }
| '{' ';' case_list '}' { $$.u.ast = $3.u.ast; }
@ -955,10 +949,6 @@ dereferencable_scalar:
| T_CONSTANT_ENCAPSED_STRING { $$.u.ast = AST_ZVAL(&$1); }
;
static_scalar: /* compile-time evaluated scalars */
expr { zend_do_constant_expression(&$$, $1.u.ast TSRMLS_CC); }
;
scalar:
T_LNUMBER { $$.u.ast = AST_ZVAL(&$1); }
| T_DNUMBER { $$.u.ast = AST_ZVAL(&$1); }

View file

@ -8,10 +8,11 @@ function a() {
unregister_tick_function('a');
}
declare (ticks=1);
register_tick_function('a');
declare (ticks=1) {
register_tick_function('a');
echo "Done\n";
echo "Done\n";
}
?>
--EXPECTF--
hello
@ -19,5 +20,3 @@ Warning: unregister_tick_function(): Unable to delete tick function executed at
Done
hello
Warning: unregister_tick_function(): Unable to delete tick function executed at the moment in %s on line %d
hello
Warning: unregister_tick_function(): Unable to delete tick function executed at the moment in %s on line %d