From: Dmitry Stogov Date: Tue, 25 Nov 2008 09:56:32 +0000 (+0000) Subject: Added support for namespaces with brackets. (Greg) X-Git-Tag: php-5.3.0alpha2~81 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ea45b713c8ed4110e26588fab00730a677106231;p=php Added support for namespaces with brackets. (Greg) --- diff --git a/NEWS b/NEWS index 9fe0ae85ee..83d29d31dd 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,7 @@ PHP NEWS parameter validation. (Felipe) - Changed openssl info to show the shared library version number. (Scott) +- Added support for namespaces with brackets. (Greg) - Added stream_cast() and stream_set_options() to user-space stream wrappers, allowing stream_select(), stream_set_blocking(), stream_set_timeout() and stream_set_write_buffer() to work with user-space stream wrappers. (Arnaud) diff --git a/Zend/tests/ns_079.phpt b/Zend/tests/ns_079.phpt new file mode 100644 index 0000000000..c11181c54b --- /dev/null +++ b/Zend/tests/ns_079.phpt @@ -0,0 +1,12 @@ +--TEST-- +079: nested namespaces +--FILE-- + +===DONE=== +--EXPECTF-- +Fatal error: Namespace declarations cannot be nested in %s on line %d diff --git a/Zend/tests/ns_080.phpt b/Zend/tests/ns_080.phpt new file mode 100644 index 0000000000..9c81c0d4c8 --- /dev/null +++ b/Zend/tests/ns_080.phpt @@ -0,0 +1,15 @@ +--TEST-- +080: bracketed namespaces and __HALT_COMPILER(); +--FILE-- + +===DONE=== +--EXPECT-- +hi \ No newline at end of file diff --git a/Zend/tests/ns_081.phpt b/Zend/tests/ns_081.phpt new file mode 100644 index 0000000000..e08a8088e0 --- /dev/null +++ b/Zend/tests/ns_081.phpt @@ -0,0 +1,23 @@ +--TEST-- +081: bracketed namespace with nested unbracketed namespace +--FILE-- + +===DONE=== +--EXPECTF-- +Fatal error: Cannot mix bracketed namespace declarations with unbracketed namespace declarations in %sns_081.php on line 9 diff --git a/Zend/tests/ns_082.phpt b/Zend/tests/ns_082.phpt new file mode 100644 index 0000000000..3220974047 --- /dev/null +++ b/Zend/tests/ns_082.phpt @@ -0,0 +1,12 @@ +--TEST-- +082: bracketed namespace with closing tag +--FILE-- + +--EXPECT-- +ok \ No newline at end of file diff --git a/Zend/tests/ns_083.phpt b/Zend/tests/ns_083.phpt new file mode 100644 index 0000000000..4b821dbf0b --- /dev/null +++ b/Zend/tests/ns_083.phpt @@ -0,0 +1,14 @@ +--TEST-- +083: bracketed namespace with junk before the ns declaration +--FILE-- + +--EXPECTF-- +Fatal error: Namespace declaration statement has to be the very first statement in the script in %s on line %d diff --git a/Zend/tests/ns_084.phpt b/Zend/tests/ns_084.phpt new file mode 100644 index 0000000000..cb1ae55e28 --- /dev/null +++ b/Zend/tests/ns_084.phpt @@ -0,0 +1,23 @@ +--TEST-- +084: unbracketed namespace with nested bracketed namespace +--FILE-- + +===DONE=== +--EXPECTF-- +Fatal error: Cannot mix bracketed namespace declarations with unbracketed namespace declarations in %sns_084.php on line 9 diff --git a/Zend/tests/ns_085.phpt b/Zend/tests/ns_085.phpt new file mode 100644 index 0000000000..377da6a8dc --- /dev/null +++ b/Zend/tests/ns_085.phpt @@ -0,0 +1,27 @@ +--TEST-- +085: bracketed namespace +--FILE-- +') { CG(increment_lineno) = 1; } + if (CG(has_bracketed_namespaces) && !CG(in_namespace)) { + goto again; + } retval = ';'; /* implicit ; */ break; case T_OPEN_TAG_WITH_ECHO: @@ -5081,11 +5086,28 @@ void zend_do_build_namespace_name(znode *result, znode *prefix, znode *name TSRM } /* }}} */ -void zend_do_namespace(const znode *name TSRMLS_DC) /* {{{ */ +void zend_do_begin_namespace(const znode *name, zend_bool with_bracket TSRMLS_DC) /* {{{ */ { char *lcname; - if (CG(active_op_array)->last > 0) { + /* handle mixed syntax declaration or nested namespaces */ + if (!CG(has_bracketed_namespaces)) { + if (CG(current_namespace)) { + /* previous namespace declarations were unbracketed */ + if (with_bracket) { + zend_error(E_COMPILE_ERROR, "Cannot mix bracketed namespace declarations with unbracketed namespace declarations"); + } + } + } else { + /* previous namespace declarations were bracketed */ + if (!with_bracket) { + zend_error(E_COMPILE_ERROR, "Cannot mix bracketed namespace declarations with unbracketed namespace declarations"); + } else if (CG(current_namespace) || CG(in_namespace)) { + zend_error(E_COMPILE_ERROR, "Namespace declarations cannot be nested"); + } + } + + if (((!with_bracket && !CG(current_namespace)) || (with_bracket && !CG(has_bracketed_namespaces))) && CG(active_op_array)->last > 0) { /* ignore ZEND_EXT_STMT and ZEND_TICKS */ int num = CG(active_op_array)->last; while (num > 0 && @@ -5093,31 +5115,45 @@ void zend_do_namespace(const znode *name TSRMLS_DC) /* {{{ */ CG(active_op_array)->opcodes[num-1].opcode == ZEND_TICKS)) { --num; } - if (!CG(current_namespace) && num > 0) { + if (num > 0) { zend_error(E_COMPILE_ERROR, "Namespace declaration statement has to be the very first statement in the script"); } } - lcname = zend_str_tolower_dup(Z_STRVAL(name->u.constant), Z_STRLEN(name->u.constant)); - if (((Z_STRLEN(name->u.constant) == sizeof("self")-1) && - !memcmp(lcname, "self", sizeof("self")-1)) || - ((Z_STRLEN(name->u.constant) == sizeof("parent")-1) && - !memcmp(lcname, "parent", sizeof("parent")-1))) { - zend_error(E_COMPILE_ERROR, "Cannot use '%s' as namespace name", Z_STRVAL(name->u.constant)); + + CG(in_namespace) = 1; + if (with_bracket) { + CG(has_bracketed_namespaces) = 1; } - efree(lcname); - if (CG(current_namespace)) { - zval_dtor(CG(current_namespace)); + if (name) { + lcname = zend_str_tolower_dup(Z_STRVAL(name->u.constant), Z_STRLEN(name->u.constant)); + if (((Z_STRLEN(name->u.constant) == sizeof("self")-1) && + !memcmp(lcname, "self", sizeof("self")-1)) || + ((Z_STRLEN(name->u.constant) == sizeof("parent")-1) && + !memcmp(lcname, "parent", sizeof("parent")-1))) { + zend_error(E_COMPILE_ERROR, "Cannot use '%s' as namespace name", Z_STRVAL(name->u.constant)); + } + efree(lcname); + + if (CG(current_namespace)) { + zval_dtor(CG(current_namespace)); + } else { + ALLOC_ZVAL(CG(current_namespace)); + } + *CG(current_namespace) = name->u.constant; } else { - ALLOC_ZVAL(CG(current_namespace)); + if (CG(current_namespace)) { + zval_dtor(CG(current_namespace)); + FREE_ZVAL(CG(current_namespace)); + CG(current_namespace) = NULL; + } } + if (CG(current_import)) { zend_hash_destroy(CG(current_import)); efree(CG(current_import)); CG(current_import) = NULL; } - - *CG(current_namespace) = name->u.constant; } /* }}} */ @@ -5233,8 +5269,17 @@ void zend_do_declare_constant(znode *name, znode *value TSRMLS_DC) /* {{{ */ } /* }}} */ -void zend_do_end_compilation(TSRMLS_D) /* {{{ */ +void zend_verify_namespace(TSRMLS_D) /* {{{ */ { + if (CG(has_bracketed_namespaces) && !CG(in_namespace)) { + zend_error(E_COMPILE_ERROR, "No code may exist outside of namespace {}"); + } +} +/* }}} */ + +void zend_do_end_namespace(TSRMLS_D) /* {{{ */ +{ + CG(in_namespace) = 0; if (CG(current_namespace)) { zval_dtor(CG(current_namespace)); FREE_ZVAL(CG(current_namespace)); @@ -5248,6 +5293,13 @@ void zend_do_end_compilation(TSRMLS_D) /* {{{ */ } /* }}} */ +void zend_do_end_compilation(TSRMLS_D) /* {{{ */ +{ + CG(has_bracketed_namespaces) = 0; + zend_do_end_namespace(TSRMLS_C); +} +/* }}} */ + /* {{{ zend_dirname Returns directory name component of path */ ZEND_API size_t zend_dirname(char *path, size_t len) diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 50f56d9c41..c607604cae 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -537,7 +537,9 @@ void zend_do_abstract_method(const znode *function_name, znode *modifiers, const void zend_do_declare_constant(znode *name, znode *value TSRMLS_DC); void zend_do_build_namespace_name(znode *result, znode *prefix, znode *name TSRMLS_DC); -void zend_do_namespace(const znode *name TSRMLS_DC); +void zend_do_begin_namespace(const znode *name, zend_bool with_brackets TSRMLS_DC); +void zend_do_end_namespace(TSRMLS_D); +void zend_verify_namespace(TSRMLS_D); void zend_do_use(znode *name, znode *new_name, int is_global TSRMLS_DC); void zend_do_end_compilation(TSRMLS_D); diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 88fe44e083..d30dd89b11 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -134,6 +134,8 @@ struct _zend_compiler_globals { zval *current_namespace; HashTable *current_import; + zend_bool in_namespace; + zend_bool has_bracketed_namespaces; HashTable *labels; zend_stack labels_stack; diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index e613f05abc..7feb689087 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -166,13 +166,17 @@ namespace_name: ; top_statement: - statement - | function_declaration_statement { zend_do_early_binding(TSRMLS_C); } - | class_declaration_statement { zend_do_early_binding(TSRMLS_C); } + statement { zend_verify_namespace(TSRMLS_C); } + | function_declaration_statement { 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_namespace(&$2 TSRMLS_CC); } - | T_USE use_declarations ';' - | constant_declaration ';' + | T_NAMESPACE namespace_name ';' { zend_do_begin_namespace(&$2, 0 TSRMLS_CC); } + | T_NAMESPACE namespace_name '{' { zend_do_begin_namespace(&$2, 1 TSRMLS_CC); } + top_statement_list '}' { zend_do_end_namespace(TSRMLS_C); } + | T_NAMESPACE '{' { zend_do_begin_namespace(NULL, 1 TSRMLS_CC); } + top_statement_list '}' { zend_do_end_namespace(TSRMLS_C); } + | T_USE use_declarations ';' { zend_verify_namespace(TSRMLS_C); } + | constant_declaration ';' { zend_verify_namespace(TSRMLS_C); } ; use_declarations: