mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Implement declare()
This commit is contained in:
parent
2653b8b5dc
commit
b9be66ebf2
5 changed files with 100 additions and 20 deletions
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue