summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@php.net>2008-11-25 09:56:32 +0000
committerDmitry Stogov <dmitry@php.net>2008-11-25 09:56:32 +0000
commitea45b713c8ed4110e26588fab00730a677106231 (patch)
treee3d5f0254b879300c304f2bb3b500c0598e09378
parentcc2c72091233930ad17d14c8388b4cd272fef112 (diff)
downloadphp-git-ea45b713c8ed4110e26588fab00730a677106231.tar.gz
Added support for namespaces with brackets. (Greg)
-rw-r--r--NEWS1
-rw-r--r--Zend/tests/ns_079.phpt12
-rw-r--r--Zend/tests/ns_080.phpt15
-rw-r--r--Zend/tests/ns_081.phpt23
-rw-r--r--Zend/tests/ns_082.phpt12
-rw-r--r--Zend/tests/ns_083.phpt14
-rw-r--r--Zend/tests/ns_084.phpt23
-rw-r--r--Zend/tests/ns_085.phpt27
-rw-r--r--Zend/tests/ns_086.phpt28
-rw-r--r--Zend/tests/ns_087.phpt24
-rw-r--r--Zend/zend_compile.c84
-rw-r--r--Zend/zend_compile.h4
-rw-r--r--Zend/zend_globals.h2
-rw-r--r--Zend/zend_language_parser.y16
14 files changed, 262 insertions, 23 deletions
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--
+<?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: