diff options
author | Dmitry Stogov <dmitry@php.net> | 2008-11-25 09:56:32 +0000 |
---|---|---|
committer | Dmitry Stogov <dmitry@php.net> | 2008-11-25 09:56:32 +0000 |
commit | ea45b713c8ed4110e26588fab00730a677106231 (patch) | |
tree | e3d5f0254b879300c304f2bb3b500c0598e09378 | |
parent | cc2c72091233930ad17d14c8388b4cd272fef112 (diff) | |
download | php-git-ea45b713c8ed4110e26588fab00730a677106231.tar.gz |
Added support for namespaces with brackets. (Greg)
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | Zend/tests/ns_079.phpt | 12 | ||||
-rw-r--r-- | Zend/tests/ns_080.phpt | 15 | ||||
-rw-r--r-- | Zend/tests/ns_081.phpt | 23 | ||||
-rw-r--r-- | Zend/tests/ns_082.phpt | 12 | ||||
-rw-r--r-- | Zend/tests/ns_083.phpt | 14 | ||||
-rw-r--r-- | Zend/tests/ns_084.phpt | 23 | ||||
-rw-r--r-- | Zend/tests/ns_085.phpt | 27 | ||||
-rw-r--r-- | Zend/tests/ns_086.phpt | 28 | ||||
-rw-r--r-- | Zend/tests/ns_087.phpt | 24 | ||||
-rw-r--r-- | Zend/zend_compile.c | 84 | ||||
-rw-r--r-- | Zend/zend_compile.h | 4 | ||||
-rw-r--r-- | Zend/zend_globals.h | 2 | ||||
-rw-r--r-- | Zend/zend_language_parser.y | 16 |
14 files changed, 262 insertions, 23 deletions
@@ -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-- +<?php +namespace foo { + namespace oops { + } +} +?> +===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-- +<?php +namespace foo { +echo "hi\n"; +} +__HALT_COMPILER(); +namespace unprocessed { +echo "should not echo\n"; +} +?> +===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-- +<?php +namespace foo { +use \foo; +class bar { + function __construct() {echo __METHOD__,"\n";} +} +new foo; +new bar; +namespace oops; +class foo { + function __construct() {echo __METHOD__,"\n";} +} +use foo\bar as foo1; +new foo1; +new foo; +} +?> +===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-- +<?php +namespace foo { +} +namespace ok { +echo "ok\n"; +} +?> +--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-- +<?php +$a = 'oops'; +echo $a; +namespace foo { +} +namespace ok { +echo "ok\n"; +} +?> +--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-- +<?php +namespace foo; +use \foo; +class bar { + function __construct() {echo __METHOD__,"\n";} +} +new foo; +new bar; +namespace oops { +class foo { + function __construct() {echo __METHOD__,"\n";} +} +use foo\bar as foo1; +new foo1; +new foo; +} +?> +===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-- +<?php +namespace foo { +use \foo; +class bar { + function __construct() {echo __METHOD__,"\n";} +} +new foo; +new bar; +} +namespace { +class foo { + function __construct() {echo __METHOD__,"\n";} +} +use foo\bar as foo1; +new foo1; +new foo; +echo "===DONE===\n"; +} +--EXPECT-- +foo::__construct +foo\bar::__construct +foo\bar::__construct +foo::__construct +===DONE===
\ No newline at end of file diff --git a/Zend/tests/ns_086.phpt b/Zend/tests/ns_086.phpt new file mode 100644 index 0000000000..ce3e2a6476 --- /dev/null +++ b/Zend/tests/ns_086.phpt @@ -0,0 +1,28 @@ +--TEST-- +086: bracketed namespace with encoding +--FILE-- +<?php +declare(encoding='utf-8'); +namespace foo { +use \foo; +class bar { + function __construct() {echo __METHOD__,"\n";} +} +new foo; +new bar; +} +namespace { +class foo { + function __construct() {echo __METHOD__,"\n";} +} +use foo\bar as foo1; +new foo1; +new foo; +echo "===DONE===\n"; +} +--EXPECT-- +foo::__construct +foo\bar::__construct +foo\bar::__construct +foo::__construct +===DONE===
\ No newline at end of file diff --git a/Zend/tests/ns_087.phpt b/Zend/tests/ns_087.phpt new file mode 100644 index 0000000000..b2f0a89b22 --- /dev/null +++ b/Zend/tests/ns_087.phpt @@ -0,0 +1,24 @@ +--TEST-- +087: bracketed namespace with stuff in between +--FILE-- +<?php +namespace foo { +use \foo; +class bar { + function __construct() {echo __METHOD__,"\n";} +} +new foo; +new bar; +} +$a = 'oops'; +namespace { +class foo { + function __construct() {echo __METHOD__,"\n";} +} +use foo\bar as foo1; +new foo1; +new foo; +echo "===DONE===\n"; +} +--EXPECTF-- +Fatal error: No code may exist outside of namespace {} in %s on line 10 diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index c79e288f02..04c3fe5dc6 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -138,6 +138,8 @@ void zend_init_compiler_data_structures(TSRMLS_D) CG(in_compilation) = 0; CG(start_lineno) = 0; CG(current_namespace) = NULL; + CG(in_namespace) = 0; + CG(has_bracketed_namespaces) = 0; CG(current_import) = NULL; init_compiler_declarables(TSRMLS_C); zend_hash_apply(CG(auto_globals), (apply_func_t) zend_auto_global_arm TSRMLS_CC); @@ -4948,6 +4950,9 @@ again: if (LANG_SCNG(yy_text)[LANG_SCNG(yy_leng)-1] != '>') { 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: |