]> granicus.if.org Git - php/commitdiff
Added support for namespaces with brackets. (Greg)
authorDmitry Stogov <dmitry@php.net>
Tue, 25 Nov 2008 09:56:32 +0000 (09:56 +0000)
committerDmitry Stogov <dmitry@php.net>
Tue, 25 Nov 2008 09:56:32 +0000 (09:56 +0000)
14 files changed:
NEWS
Zend/tests/ns_079.phpt [new file with mode: 0644]
Zend/tests/ns_080.phpt [new file with mode: 0644]
Zend/tests/ns_081.phpt [new file with mode: 0644]
Zend/tests/ns_082.phpt [new file with mode: 0644]
Zend/tests/ns_083.phpt [new file with mode: 0644]
Zend/tests/ns_084.phpt [new file with mode: 0644]
Zend/tests/ns_085.phpt [new file with mode: 0644]
Zend/tests/ns_086.phpt [new file with mode: 0644]
Zend/tests/ns_087.phpt [new file with mode: 0644]
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_globals.h
Zend/zend_language_parser.y

diff --git a/NEWS b/NEWS
index 9fe0ae85ee4cc8a3e7cb0589c0a2bbd6c7bdbbee..83d29d31dda3fca3cb3afef939eda37f2b2bb04d 100644 (file)
--- 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 (file)
index 0000000..c11181c
--- /dev/null
@@ -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 (file)
index 0000000..9c81c0d
--- /dev/null
@@ -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 (file)
index 0000000..e08a808
--- /dev/null
@@ -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 (file)
index 0000000..3220974
--- /dev/null
@@ -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 (file)
index 0000000..4b821db
--- /dev/null
@@ -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 (file)
index 0000000..cb1ae55
--- /dev/null
@@ -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 (file)
index 0000000..377da6a
--- /dev/null
@@ -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 (file)
index 0000000..ce3e2a6
--- /dev/null
@@ -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 (file)
index 0000000..b2f0a89
--- /dev/null
@@ -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
index c79e288f02fb2fb1efe69f17ee2f035f2935adfe..04c3fe5dc63816b7fdd27eb97ce38ef396e9cb83 100644 (file)
@@ -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)
index 50f56d9c417ef1c930058351b652fedfb567796b..c607604cae1284446b0ef3b9b743ee9ebe1a0d78 100644 (file)
@@ -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);
 
index 88fe44e08315a929a4ee0efa84c24282c2a6335f..d30dd89b112ce03fbeb1d367abb31ab98e604773 100644 (file)
@@ -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;
index e613f05abc6d9d7a3a82862f35747f1afc8c4abc..7feb6890876c39fde3cc0b752036012a6b78f058 100644 (file)
@@ -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: